aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/README.md6
-rw-r--r--test/functional/README.md7
-rwxr-xr-xtest/functional/combine_logs.py20
-rwxr-xr-xtest/functional/create_cache.py2
-rw-r--r--test/functional/data/rpc_getblockstats.json24
-rw-r--r--test/functional/data/rpc_psbt.json130
-rwxr-xr-xtest/functional/example_test.py34
-rwxr-xr-xtest/functional/feature_assumevalid.py39
-rwxr-xr-xtest/functional/feature_bip68_sequence.py13
-rwxr-xr-xtest/functional/feature_block.py184
-rwxr-xr-xtest/functional/feature_blocksdir.py6
-rwxr-xr-xtest/functional/feature_cltv.py84
-rwxr-xr-xtest/functional/feature_config_args.py36
-rwxr-xr-xtest/functional/feature_csv_activation.py37
-rwxr-xr-xtest/functional/feature_dbcrash.py15
-rwxr-xr-xtest/functional/feature_dersig.py89
-rwxr-xr-xtest/functional/feature_fee_estimation.py12
-rwxr-xr-xtest/functional/feature_help.py43
-rwxr-xr-xtest/functional/feature_includeconf.py8
-rwxr-xr-xtest/functional/feature_logging.py2
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py19
-rwxr-xr-xtest/functional/feature_minchainwork.py7
-rwxr-xr-xtest/functional/feature_notifications.py11
-rwxr-xr-xtest/functional/feature_nulldummy.py43
-rwxr-xr-xtest/functional/feature_proxy.py2
-rwxr-xr-xtest/functional/feature_pruning.py34
-rwxr-xr-xtest/functional/feature_rbf.py43
-rwxr-xr-xtest/functional/feature_reindex.py6
-rwxr-xr-xtest/functional/feature_segwit.py80
-rwxr-xr-xtest/functional/feature_uacomment.py2
-rwxr-xr-xtest/functional/feature_versionbits_warning.py20
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py8
-rwxr-xr-xtest/functional/interface_http.py4
-rwxr-xr-xtest/functional/interface_rest.py5
-rwxr-xr-xtest/functional/interface_zmq.py40
-rwxr-xr-xtest/functional/mempool_accept.py4
-rwxr-xr-xtest/functional/mempool_limit.py9
-rwxr-xr-xtest/functional/mempool_packages.py13
-rwxr-xr-xtest/functional/mempool_persist.py8
-rwxr-xr-xtest/functional/mempool_reorg.py23
-rwxr-xr-xtest/functional/mempool_resurrect.py23
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py17
-rwxr-xr-xtest/functional/mining_basic.py100
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py22
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py11
-rwxr-xr-xtest/functional/p2p_compactblocks.py26
-rwxr-xr-xtest/functional/p2p_disconnect_ban.py2
-rwxr-xr-xtest/functional/p2p_feefilter.py16
-rwxr-xr-xtest/functional/p2p_fingerprint.py14
-rwxr-xr-xtest/functional/p2p_invalid_block.py31
-rwxr-xr-xtest/functional/p2p_invalid_locator.py43
-rwxr-xr-xtest/functional/p2p_invalid_tx.py25
-rwxr-xr-xtest/functional/p2p_leak.py51
-rwxr-xr-xtest/functional/p2p_mempool.py9
-rwxr-xr-xtest/functional/p2p_node_network_limited.py19
-rwxr-xr-xtest/functional/p2p_segwit.py2012
-rwxr-xr-xtest/functional/p2p_sendheaders.py40
-rwxr-xr-xtest/functional/p2p_timeouts.py32
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py32
-rwxr-xr-xtest/functional/rpc_bind.py12
-rwxr-xr-xtest/functional/rpc_blockchain.py29
-rwxr-xr-xtest/functional/rpc_createmultisig.py101
-rwxr-xr-xtest/functional/rpc_decodescript.py7
-rwxr-xr-xtest/functional/rpc_deprecated.py95
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py11
-rwxr-xr-xtest/functional/rpc_getblockstats.py22
-rwxr-xr-xtest/functional/rpc_getchaintips.py20
-rwxr-xr-xtest/functional/rpc_help.py42
-rwxr-xr-xtest/functional/rpc_invalidateblock.py12
-rwxr-xr-xtest/functional/rpc_named_arguments.py2
-rwxr-xr-xtest/functional/rpc_net.py46
-rwxr-xr-xtest/functional/rpc_preciousblock.py15
-rwxr-xr-xtest/functional/rpc_psbt.py229
-rwxr-xr-xtest/functional/rpc_rawtransaction.py65
-rwxr-xr-xtest/functional/rpc_scantxoutset.py95
-rwxr-xr-xtest/functional/rpc_signmessage.py5
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py19
-rwxr-xr-xtest/functional/rpc_txoutproof.py29
-rwxr-xr-xtest/functional/rpc_uptime.py2
-rwxr-xr-xtest/functional/rpc_users.py7
-rwxr-xr-xtest/functional/rpc_zmq.py37
-rw-r--r--test/functional/test_framework/address.py2
-rw-r--r--test/functional/test_framework/blocktools.py37
-rw-r--r--test/functional/test_framework/coverage.py2
-rwxr-xr-xtest/functional/test_framework/messages.py72
-rwxr-xr-xtest/functional/test_framework/mininode.py305
-rw-r--r--test/functional/test_framework/netutil.py4
-rw-r--r--test/functional/test_framework/script.py5
-rw-r--r--test/functional/test_framework/siphash.py2
-rw-r--r--test/functional/test_framework/socks5.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py147
-rwxr-xr-xtest/functional/test_framework/test_node.py81
-rw-r--r--test/functional/test_framework/util.py12
-rwxr-xr-xtest/functional/test_runner.py66
-rwxr-xr-xtest/functional/wallet_abandonconflict.py22
-rwxr-xr-xtest/functional/wallet_address_types.py10
-rwxr-xr-xtest/functional/wallet_backup.py9
-rwxr-xr-xtest/functional/wallet_basic.py27
-rwxr-xr-xtest/functional/wallet_bumpfee.py31
-rwxr-xr-xtest/functional/wallet_disable.py4
-rwxr-xr-xtest/functional/wallet_disableprivatekeys.py35
-rwxr-xr-xtest/functional/wallet_dump.py121
-rwxr-xr-xtest/functional/wallet_encryption.py8
-rwxr-xr-xtest/functional/wallet_fallbackfee.py8
-rwxr-xr-xtest/functional/wallet_groups.py96
-rwxr-xr-xtest/functional/wallet_hd.py5
-rwxr-xr-xtest/functional/wallet_import_rescan.py24
-rwxr-xr-xtest/functional/wallet_importmulti.py42
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py30
-rwxr-xr-xtest/functional/wallet_keypool.py13
-rwxr-xr-xtest/functional/wallet_keypool_topup.py5
-rwxr-xr-xtest/functional/wallet_labels.py104
-rwxr-xr-xtest/functional/wallet_listreceivedby.py14
-rwxr-xr-xtest/functional/wallet_listsinceblock.py5
-rwxr-xr-xtest/functional/wallet_listtransactions.py7
-rwxr-xr-xtest/functional/wallet_multiwallet.py74
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py5
-rwxr-xr-xtest/functional/wallet_txn_clone.py13
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py9
-rwxr-xr-xtest/functional/wallet_zapwallettxes.py5
-rwxr-xr-xtest/lint/check-doc.py8
-rwxr-xr-xtest/lint/check-rpc-mappings.py10
-rwxr-xr-xtest/lint/commit-script-check.sh1
-rwxr-xr-xtest/lint/git-subtree-check.sh1
-rwxr-xr-xtest/lint/lint-all.sh6
-rwxr-xr-xtest/lint/lint-assertions.sh23
-rwxr-xr-xtest/lint/lint-circular-dependencies.sh83
-rwxr-xr-xtest/lint/lint-filenames.sh24
-rwxr-xr-xtest/lint/lint-format-strings.py291
-rwxr-xr-xtest/lint/lint-format-strings.sh43
-rwxr-xr-xtest/lint/lint-include-guards.sh3
-rwxr-xr-xtest/lint/lint-includes.sh23
-rwxr-xr-xtest/lint/lint-locale-dependence.sh9
-rwxr-xr-xtest/lint/lint-logs.sh4
-rwxr-xr-xtest/lint/lint-python-shebang.sh4
-rwxr-xr-xtest/lint/lint-python-utf8-encoding.sh28
-rwxr-xr-xtest/lint/lint-python.sh14
-rwxr-xr-xtest/lint/lint-qt.sh20
-rwxr-xr-xtest/lint/lint-shell-locale.sh25
-rwxr-xr-xtest/lint/lint-shell.sh24
-rw-r--r--test/lint/lint-spelling.ignore-words.txt6
-rwxr-xr-xtest/lint/lint-spelling.sh18
-rwxr-xr-xtest/lint/lint-tests.sh3
-rwxr-xr-xtest/lint/lint-whitespace.sh3
-rwxr-xr-xtest/util/bitcoin-util-test.py8
-rw-r--r--test/util/data/bitcoin-util-test.json55
-rw-r--r--test/util/data/txcreatesignv1.hex2
-rw-r--r--test/util/data/txcreatesignv1.json16
-rwxr-xr-xtest/util/rpcauth-test.py2
149 files changed, 4347 insertions, 2472 deletions
diff --git a/test/README.md b/test/README.md
index b522c4469a..a5ba732bc0 100644
--- a/test/README.md
+++ b/test/README.md
@@ -5,7 +5,7 @@ etc.
There are currently two sets of tests in this directory:
-- [functional](/test/functional) which test the functionality of
+- [functional](/test/functional) which test the functionality of
bitcoind and bitcoin-qt by interacting with them through the RPC and P2P
interfaces.
- [util](/test/util) which tests the bitcoin utilities, currently only
@@ -177,11 +177,11 @@ Note: gdb attach step may require `sudo`
### Util tests
-Util tests can be run locally by running `test/util/bitcoin-util-test.py`.
+Util tests can be run locally by running `test/util/bitcoin-util-test.py`.
Use the `-v` option for verbose output.
# Writing functional tests
You are encouraged to write functional tests for new or existing features.
-Further information about the functional test framework and individual
+Further information about the functional test framework and individual
tests is found in [test/functional](/test/functional).
diff --git a/test/functional/README.md b/test/functional/README.md
index fdd7c339c5..6929ab5991 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -28,6 +28,7 @@ don't have test cases for.
- When subclassing the BitcoinTestFramwork, place overrides for the
`set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of
the subclass, then locally-defined helper methods, then the `run_test()` method.
+- Use `'{}'.format(x)` for string formatting, not `'%s' % x`.
#### Naming guidelines
@@ -76,7 +77,7 @@ 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
+with the bitcoind(s) being tested in a callback-based event loop; the other
implements the test logic.
- `P2PConnection` is the class used to connect to a bitcoind. `P2PInterface`
@@ -84,10 +85,6 @@ contains the higher level logic for processing P2P payloads and connecting to
the Bitcoin Core node application logic. For custom behaviour, subclass the
P2PInterface object and override the callback methods.
-- Call `network_thread_start()` after all `P2PInterface` objects are created to
-start the networking thread. (Continue with the test logic in your existing
-thread.)
-
- Can be used to write tests where specific P2P protocol behavior is tested.
Examples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`.
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index d1bf9206b2..3759913e44 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -13,7 +13,7 @@ import re
import sys
# Matches on the date format at the start of the log event
-TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z")
+TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{6})?Z")
LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])
@@ -63,7 +63,7 @@ def get_log_events(source, logfile):
Log events may be split over multiple lines. We use the timestamp
regex match as the marker for a new log event."""
try:
- with open(logfile, 'r') as infile:
+ with open(logfile, 'r', encoding='utf-8') as infile:
event = ''
timestamp = ''
for line in infile:
@@ -75,11 +75,17 @@ def get_log_events(source, logfile):
if time_match:
if event:
yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
- event = line
timestamp = time_match.group()
+ if time_match.group(1) is None:
+ # timestamp does not have microseconds. Add zeroes.
+ timestamp_micro = timestamp.replace("Z", ".000000Z")
+ line = line.replace(timestamp, timestamp_micro)
+ timestamp = timestamp_micro
+ event = line
# if it doesn't have a timestamp, it's a continuation line of the previous log.
else:
- event += "\n" + line
+ # Add the line. Prefix with space equivalent to the source + timestamp so log lines are aligned
+ event += " " + line
# Flush the final event
yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
except FileNotFoundError:
@@ -98,7 +104,11 @@ def print_logs(log_events, color=False, html=False):
colors["reset"] = "\033[0m" # Reset font color
for event in log_events:
- print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, event.event, colors["reset"]))
+ lines = event.event.splitlines()
+ print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
+ if len(lines) > 1:
+ for line in lines[1:]:
+ print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
else:
try:
diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py
index 9665c50a92..edf16fa47e 100755
--- a/test/functional/create_cache.py
+++ b/test/functional/create_cache.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Create a blockchain cache.
diff --git a/test/functional/data/rpc_getblockstats.json b/test/functional/data/rpc_getblockstats.json
index 750abc5c42..b8cabe1e5e 100644
--- a/test/functional/data/rpc_getblockstats.json
+++ b/test/functional/data/rpc_getblockstats.json
@@ -112,13 +112,19 @@
"avgfeerate": 0,
"avgtxsize": 0,
"blockhash": "1d7fe80f19d28b8e712af0399ac84006db753441f3033111b3a8d610afab364f",
+ "feerate_percentiles": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
"height": 101,
"ins": 0,
"maxfee": 0,
"maxfeerate": 0,
"maxtxsize": 0,
"medianfee": 0,
- "medianfeerate": 0,
"mediantime": 1525107242,
"mediantxsize": 0,
"minfee": 0,
@@ -144,12 +150,18 @@
"avgtxsize": 187,
"blockhash": "4e21a43675d7a41cb6b944e068c5bcd0a677baf658d9ebe021ae2d2f99397ccc",
"height": 102,
+ "feerate_percentiles": [
+ 20,
+ 20,
+ 20,
+ 20,
+ 20
+ ],
"ins": 1,
"maxfee": 3760,
"maxfeerate": 20,
"maxtxsize": 187,
"medianfee": 3760,
- "medianfeerate": 20,
"mediantime": 1525107242,
"mediantxsize": 187,
"minfee": 3760,
@@ -174,13 +186,19 @@
"avgfeerate": 109,
"avgtxsize": 228,
"blockhash": "22d9b8b9c2a37c81515f3fc84f7241f6c07dbcea85ef16b00bcc33ae400a030f",
+ "feerate_percentiles": [
+ 20,
+ 20,
+ 20,
+ 300,
+ 300
+ ],
"height": 103,
"ins": 3,
"maxfee": 49800,
"maxfeerate": 300,
"maxtxsize": 248,
"medianfee": 3760,
- "medianfeerate": 20,
"mediantime": 1525107243,
"mediantxsize": 248,
"minfee": 3320,
diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json
new file mode 100644
index 0000000000..dd40a096de
--- /dev/null
+++ b/test/functional/data/rpc_psbt.json
@@ -0,0 +1,130 @@
+{
+ "invalid" : [
+ "AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAABqRzBEAiBwsiRRI+a/R01gxbUMBD1MaRpdJDXwmjSnZiqdwlF5CgIgATKcqdrPKAvfMHQOwDkEIkIsgctFg5RXrrdvwS7dlbMBIQJlfRGNM1e44PTCzUbbezn22cONmnCry5st5dyNv+TOMf7///8C09/1BQAAAAAZdqkU0MWZA8W6woaHYOkP1SGkZlqnZSCIrADh9QUAAAAAF6kUNUXm4zuDLEcFDyTT7rk8nAOUi8eHsy4TAA==",
+ "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==",
+ "cHNidP8BAP0KAQIAAAACqwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QAAAAAakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpL+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAABASAA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHhwEEFgAUhdE1N/LiZUBaNNuvqePdoB+4IwgAAAA=",
+ "cHNidP8AAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==",
+ "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQA/AgAAAAH//////////////////////////////////////////wAAAAAA/////wEAAAAAAAAAAANqAQAAAAAAAAAA",
+ "cHNidP8CAAFVAgAAAAEnmiMjpd+1H8RfIg+liw/BPh4zQnkqhdfjbNYzO1y8OQAAAAAA/////wGgWuoLAAAAABl2qRT/6cAGEJfMO2NvLLBGD6T8Qn0rRYisAAAAAAABASCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA",
+ "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAIBACCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA",
+ "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIQIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYwQwIgBCS1jv+qppThVZ6lyTu/1KiQZCJAVc3wcLZ3FGlELQcCH1yOsP6mUW1guKyzOtZO3mDoeFv7OqlLmb34YVHbmpoBAQQiACB3H9GK1FlmbdSfPVZOPbxC9MhHdONgraFoFqjtSI1WgQEFR1IhA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GIQPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvVKuIgYDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYQtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA==",
+ "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQIEACIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA",
+ "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoECBQBHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA",
+ "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriEGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb0QtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA==",
+ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAIAALsCAAAAAarXOTEBi9JfhK5AC2iEi+CdtwbqwqwYKYur7nGrZW+LAAAAAEhHMEQCIFj2/HxqM+GzFUjUgcgmwBW9MBNarULNZ3kNq2bSrSQ7AiBKHO0mBMZzW2OT5bQWkd14sA8MWUL7n3UYVvqpOBV9ugH+////AoDw+gIAAAAAF6kUD7lGNCFpa4LIM68kHHjBfdveSTSH0PIKJwEAAAAXqRQpynT4oI+BmZQoGFyXtdhS5AY/YYdlAAAAAQfaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
+ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAACBwDaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
+ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAggA2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
+ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
+ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A",
+ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A",
+ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"
+ ],
+ "valid" : [
+ "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA",
+ "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA",
+ "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA==",
+ "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=",
+ "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriIGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GELSmumcAAACAAAAAgAQAAIAiBgPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvRC0prpnAAAAgAAAAIAFAACAAAA=",
+ "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA=="
+ ],
+ "creator" : [
+ {
+ "inputs" : [
+ {
+ "txid":"75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858",
+ "vout":0
+ },
+ {
+ "txid":"1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83",
+ "vout":1
+ }
+ ],
+ "outputs" : [
+ {
+ "bcrt1qmpwzkuwsqc9snjvgdt4czhjsnywa5yjdqpxskv":1.49990000
+ },
+ {
+ "bcrt1qqzh2ngh97ru8dfvgma25d6r595wcwqy0cee4cc": 1
+ }
+ ],
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA="
+ }
+ ],
+ "signer" : [
+ {
+ "privkeys" : [
+ "cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr",
+ "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d"
+ ],
+ "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
+ },
+ {
+ "privkeys" : [
+ "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
+ "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
+ ],
+ "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
+ },
+ {
+ "privkeys" : [
+ "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
+ ],
+ "psbt" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=",
+ "result" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
+ },
+ {
+ "privkeys" : [
+ "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
+ "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
+ ],
+ "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
+ },
+ {
+ "privkeys" : [
+ "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
+ "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
+ ],
+ "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
+ },
+ {
+ "privkeys" : [
+ "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
+ "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
+ ],
+ "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
+ }
+ ],
+ "combiner" : [
+ {
+ "combine" : [
+ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
+ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
+ ],
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXRzBEAiBjGpif5zipKtAZhgIzEsGSFP4oArOeXLwaw2eIBsaSwwIgOdtsOHvSZ3Ft/bPU2NpQuOhdITMmunx9qqTAzkHrkiMBAQMEAQAAAAEER1IhApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/IQLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU211KuIgYClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8Q2QxqTwAAAIAAAACAAAAAgCIGAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXENkMak8AAACAAAAAgAEAAIAAAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IciAgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3EcwRAIgYut6VWEHp8c/RaxKtaHd329wdfsSdZaafzg+//eEvLICIAwF27dHDb8vCFV901bHMlwe0wkT6ZbNOECUXbEiKNpfASICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
+ },
+ {
+ "combine" : [
+ "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwA=",
+ "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA="
+ ],
+ "result" : "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8KDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PCg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA="
+ }
+ ],
+ "finalizer" : [
+ {
+ "finalize" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
+ "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
+ }
+ ],
+ "extractor" : [
+ {
+ "extract" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
+ "result" : "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000"
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index 05d1c1bf4e..3f15367a75 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""An example functional test
@@ -15,14 +15,12 @@ from collections import defaultdict
# Avoid wildcard * imports if possible
from test_framework.blocktools import (create_block, create_coinbase)
+from test_framework.messages import CInv
from test_framework.mininode import (
- CInv,
P2PInterface,
mininode_lock,
msg_block,
msg_getdata,
- network_thread_join,
- network_thread_start,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -69,16 +67,17 @@ def custom_function():
# self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
pass
+
class ExampleTest(BitcoinTestFramework):
# Each functional test is a subclass of the BitcoinTestFramework class.
- # Override the set_test_params(), add_options(), setup_chain(), setup_network()
+ # Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network()
# and setup_nodes() methods to customize the test setup as required.
def set_test_params(self):
"""Override test parameters for your individual test.
- This method must be overridden and num_nodes must be exlicitly set."""
+ This method must be overridden and num_nodes must be explicitly set."""
self.setup_clean_chain = True
self.num_nodes = 3
# Use self.extra_args to change command-line arguments for the nodes
@@ -86,6 +85,11 @@ class ExampleTest(BitcoinTestFramework):
# self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test()
+ # Use skip_test_if_missing_module() to skip the test if your test requires certain modules to be present.
+ # This test uses generate which requires wallet to be compiled
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
# Use add_options() to add specific command-line options for your test.
# In practice this is not used very much, since the tests are mostly written
# to be run in automated environments without command-line options.
@@ -113,7 +117,7 @@ class ExampleTest(BitcoinTestFramework):
# sync_all() should not include node2, since we're not expecting it to
# sync.
connect_nodes(self.nodes[0], 1)
- self.sync_all([self.nodes[0:1]])
+ self.sync_all([self.nodes[0:2]])
# Use setup_nodes() to customize the node start behaviour (for example if
# you don't want to start all nodes at the start of the test).
@@ -132,18 +136,12 @@ class ExampleTest(BitcoinTestFramework):
def run_test(self):
"""Main test logic"""
- # Create P2P connections to two of the nodes
+ # Create P2P connections will wait for a verack to make sure the connection is fully up
self.nodes[0].add_p2p_connection(BaseNode())
- # Start up network handling in another thread. This needs to be called
- # after the P2P connections have been created.
- network_thread_start()
- # wait_for_verack ensures that the P2P connection is fully up.
- self.nodes[0].p2p.wait_for_verack()
-
# Generating a block on one of the nodes will get us out of IBD
blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
- self.sync_all([self.nodes[0:1]])
+ self.sync_all([self.nodes[0:2]])
# Notice above how we called an RPC by calling a method with the same
# name on the node object. Notice also how we used a keyword argument
@@ -189,15 +187,9 @@ class ExampleTest(BitcoinTestFramework):
connect_nodes(self.nodes[1], 2)
self.log.info("Add P2P connection to node2")
- # We can't add additional P2P connections once the network thread has started. Disconnect the connection
- # to node0, wait for the network thread to terminate, then connect to node2. This is specific to
- # the current implementation of the network thread and may be improved in future.
self.nodes[0].disconnect_p2ps()
- network_thread_join()
self.nodes[2].add_p2p_connection(BaseNode())
- network_thread_start()
- self.nodes[2].p2p.wait_for_verack()
self.log.info("Wait for node2 reach current tip. Test that it has propagated all the blocks to us")
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 5a09142412..3d0467038d 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test logic for skipping signature validation on old blocks.
@@ -33,16 +33,16 @@ import time
from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.key import CECKey
-from test_framework.mininode import (CBlockHeader,
- COutPoint,
- CTransaction,
- CTxIn,
- CTxOut,
- network_thread_join,
- network_thread_start,
- P2PInterface,
- msg_block,
- msg_headers)
+from test_framework.messages import (
+ CBlockHeader,
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxOut,
+ msg_block,
+ msg_headers
+)
+from test_framework.mininode import P2PInterface
from test_framework.script import (CScript, OP_TRUE)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -68,12 +68,12 @@ class AssumeValidTest(BitcoinTestFramework):
def send_blocks_until_disconnected(self, p2p_conn):
"""Keep sending blocks to the node until we're disconnected."""
for i in range(len(self.blocks)):
- if p2p_conn.state != "connected":
+ if not p2p_conn.is_connected:
break
try:
p2p_conn.send_message(msg_block(self.blocks[i]))
except IOError as e:
- assert str(e) == 'Not connected, no pushbuf'
+ assert not p2p_conn.is_connected
break
def assert_blockchain_height(self, node, height):
@@ -95,13 +95,8 @@ class AssumeValidTest(BitcoinTestFramework):
break
def run_test(self):
-
- # Connect to node0
p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
- network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
-
# Build the blockchain
self.tip = int(self.nodes[0].getbestblockhash(), 16)
self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
@@ -160,9 +155,7 @@ class AssumeValidTest(BitcoinTestFramework):
self.block_time += 1
height += 1
- # We're adding new connections so terminate the network thread
self.nodes[0].disconnect_p2ps()
- network_thread_join()
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
@@ -172,12 +165,6 @@ class AssumeValidTest(BitcoinTestFramework):
p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
- network_thread_start()
-
- p2p0.wait_for_verack()
- p2p1.wait_for_verack()
- p2p2.wait_for_verack()
-
# send header lists to all three nodes
p2p0.send_header_for_blocks(self.blocks[0:2000])
p2p0.send_header_for_blocks(self.blocks[2000:])
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index d8521550b5..8466f851ca 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -1,12 +1,16 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP68 implementation."""
+import time
+
+from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
+from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
+from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.blocktools import *
+from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, get_bip9_status, satoshi_round, sync_blocks
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height)
@@ -21,6 +25,9 @@ class BIP68Test(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [[], ["-acceptnonstdtxn=0"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index f943fdf176..71c3a396c1 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test block processing."""
@@ -7,7 +7,7 @@ import copy
import struct
import time
-from test_framework.blocktools import create_block, create_coinbase, create_transaction, get_legacy_sigopcount_block
+from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script, get_legacy_sigopcount_block
from test_framework.key import CECKey
from test_framework.messages import (
CBlock,
@@ -20,7 +20,7 @@ from test_framework.messages import (
uint256_from_compact,
uint256_from_str,
)
-from test_framework.mininode import P2PDataStore, network_thread_start, network_thread_join
+from test_framework.mininode import P2PDataStore
from test_framework.script import (
CScript,
MAX_SCRIPT_ELEMENT_SIZE,
@@ -48,11 +48,6 @@ from test_framework.util import assert_equal
MAX_BLOCK_SIGOPS = 20000
-class PreviousSpendableOutput():
- def __init__(self, tx=CTransaction(), n=-1):
- self.tx = tx
- self.n = n # the output we're spending
-
# Use this class for tests that require behavior other than normal "mininode" behavior.
# For now, it is used to serialize a bloated varint (b64).
class CBrokenBlock(CBlock):
@@ -132,7 +127,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Don't reorg to a chain of the same length")
self.move_tip(1)
b3 = self.next_block(3, spend=out[1])
- txout_b3 = PreviousSpendableOutput(b3.vtx[1], 0)
+ txout_b3 = b3.vtx[1]
self.sync_blocks([b3], False)
# Now we add another block to make the alternative chain longer.
@@ -174,7 +169,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block where the miner creates too much coinbase reward")
self.move_tip(6)
b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b9], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -186,7 +181,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b10], False)
b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b11], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)
# Try again, but with a valid fork first
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -199,7 +194,7 @@ class FullBlockTest(BitcoinTestFramework):
b13 = self.next_block(13, spend=out[4])
self.save_spendable_output()
b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
- self.sync_blocks([b12, b13, b14], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)
# New tip should be b13.
assert_equal(node.getbestblockhash(), b13.hash)
@@ -218,7 +213,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with too many checksigs")
too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
- self.sync_blocks([b16], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# Attempt to spend a transaction created on a different fork
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -227,7 +222,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with a spend from a re-org'ed out tx")
self.move_tip(15)
b17 = self.next_block(17, spend=txout_b3)
- self.sync_blocks([b17], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a transaction created on a different fork (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -240,7 +235,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b18], False)
b19 = self.next_block(19, spend=out[6])
- self.sync_blocks([b19], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a coinbase at depth too low
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -249,7 +244,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block spending an immature coinbase.")
self.move_tip(15)
b20 = self.next_block(20, spend=out[7])
- self.sync_blocks([b20], False, 16, b'bad-txns-premature-spend-of-coinbase')
+ self.sync_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
# Attempt to spend a coinbase at depth too low (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -262,7 +257,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b21], False)
b22 = self.next_block(22, spend=out[5])
- self.sync_blocks([b22], False, 16, b'bad-txns-premature-spend-of-coinbase')
+ self.sync_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
# Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -291,7 +286,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vout = [CTxOut(0, script_output)]
b24 = self.update_block(24, [tx])
assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)
- self.sync_blocks([b24], False, 16, b'bad-blk-length', reconnect=True)
+ self.sync_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)
b25 = self.next_block(25, spend=out[7])
self.sync_blocks([b25], False)
@@ -309,7 +304,7 @@ class FullBlockTest(BitcoinTestFramework):
# update_block causes the merkle root to get updated, even with no new
# transactions, and updates the required state.
b26 = self.update_block(26, [])
- self.sync_blocks([b26], False, 16, b'bad-cb-length', reconnect=True)
+ self.sync_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)
# Extend the b26 chain to make sure bitcoind isn't accepting b26
b27 = self.next_block(27, spend=out[7])
@@ -321,7 +316,7 @@ class FullBlockTest(BitcoinTestFramework):
b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
b28.vtx[0].rehash()
b28 = self.update_block(28, [])
- self.sync_blocks([b28], False, 16, b'bad-cb-length', reconnect=True)
+ self.sync_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)
# Extend the b28 chain to make sure bitcoind isn't accepting b28
b29 = self.next_block(29, spend=out[7])
@@ -357,7 +352,7 @@ class FullBlockTest(BitcoinTestFramework):
too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))
b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b32], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# CHECKMULTISIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")
@@ -370,7 +365,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))
b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
- self.sync_blocks([b34], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# CHECKSIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
@@ -383,7 +378,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))
b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
- self.sync_blocks([b36], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# Check spending of a transaction in a block which failed to connect
#
@@ -397,15 +392,15 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block spending transaction from a block which failed to connect")
self.move_tip(35)
b37 = self.next_block(37, spend=out[11])
- txout_b37 = PreviousSpendableOutput(b37.vtx[1], 0)
- tx = self.create_and_sign_transaction(out[11].tx, out[11].n, 0)
+ txout_b37 = b37.vtx[1]
+ tx = self.create_and_sign_transaction(out[11], 0)
b37 = self.update_block(37, [tx])
- self.sync_blocks([b37], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid
self.move_tip(35)
b38 = self.next_block(38, spend=txout_b37)
- self.sync_blocks([b38], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Check P2SH SigOp counting
#
@@ -432,9 +427,9 @@ class FullBlockTest(BitcoinTestFramework):
# Create a transaction that spends one satoshi to the p2sh_script, the rest to OP_TRUE
# This must be signed because it is spending a coinbase
spend = out[11]
- tx = self.create_tx(spend.tx, spend.n, 1, p2sh_script)
- tx.vout.append(CTxOut(spend.tx.vout[spend.n].nValue - 1, CScript([OP_TRUE])))
- self.sign_tx(tx, spend.tx, spend.n)
+ tx = self.create_tx(spend, 0, 1, p2sh_script)
+ tx.vout.append(CTxOut(spend.vout[0].nValue - 1, CScript([OP_TRUE])))
+ self.sign_tx(tx, spend)
tx.rehash()
b39 = self.update_block(39, [tx])
b39_outputs += 1
@@ -497,7 +492,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.rehash()
new_txs.append(tx)
self.update_block(40, new_txs)
- self.sync_blocks([b40], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b40], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# same as b40, but one less sigop
self.log.info("Accept a block with the max number of P2SH sigops")
@@ -548,7 +543,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b44], True)
self.log.info("Reject a block with a non-coinbase as the first tx")
- non_coinbase = self.create_tx(out[15].tx, out[15].n, 1)
+ non_coinbase = self.create_tx(out[15], 0, 1)
b45 = CBlock()
b45.nTime = self.tip.nTime + 1
b45.hashPrevBlock = self.tip.sha256
@@ -560,7 +555,7 @@ class FullBlockTest(BitcoinTestFramework):
self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1
self.tip = b45
self.blocks[45] = b45
- self.sync_blocks([b45], False, 16, b'bad-cb-missing', reconnect=True)
+ self.sync_blocks([b45], success=False, reject_reason='bad-cb-missing', reconnect=True)
self.log.info("Reject a block with no transactions")
self.move_tip(44)
@@ -575,7 +570,7 @@ class FullBlockTest(BitcoinTestFramework):
self.tip = b46
assert 46 not in self.blocks
self.blocks[46] = b46
- self.sync_blocks([b46], False, 16, b'bad-blk-length', reconnect=True)
+ self.sync_blocks([b46], success=False, reject_reason='bad-blk-length', reconnect=True)
self.log.info("Reject a block with invalid work")
self.move_tip(44)
@@ -598,7 +593,7 @@ class FullBlockTest(BitcoinTestFramework):
b49 = self.next_block(49)
b49.hashMerkleRoot += 1
b49.solve()
- self.sync_blocks([b49], False, 16, b'bad-txnmrklroot', reconnect=True)
+ self.sync_blocks([b49], success=False, reject_reason='bad-txnmrklroot', reconnect=True)
self.log.info("Reject a block with incorrect POW limit")
self.move_tip(44)
@@ -612,7 +607,7 @@ class FullBlockTest(BitcoinTestFramework):
b51 = self.next_block(51)
cb2 = create_coinbase(51, self.coinbase_pubkey)
b51 = self.update_block(51, [cb2])
- self.sync_blocks([b51], False, 16, b'bad-cb-multiple', reconnect=True)
+ self.sync_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)
self.log.info("Reject a block with duplicate transactions")
# Note: txns have to be in the right position in the merkle tree to trigger this error
@@ -620,7 +615,7 @@ class FullBlockTest(BitcoinTestFramework):
b52 = self.next_block(52, spend=out[15])
tx = self.create_tx(b52.vtx[1], 0, 1)
b52 = self.update_block(52, [tx, tx])
- self.sync_blocks([b52], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b52], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
# Test block timestamps
# -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
@@ -675,7 +670,7 @@ class FullBlockTest(BitcoinTestFramework):
# b57 - a good block with 2 txs, don't submit until end
self.move_tip(55)
b57 = self.next_block(57)
- tx = self.create_and_sign_transaction(out[16].tx, out[16].n, 1)
+ tx = self.create_and_sign_transaction(out[16], 1)
tx1 = self.create_tx(tx, 0, 1)
b57 = self.update_block(57, [tx, tx1])
@@ -687,12 +682,12 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(len(b56.vtx), 3)
b56 = self.update_block(56, [tx1])
assert_equal(b56.hash, b57.hash)
- self.sync_blocks([b56], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b56], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
# b57p2 - a good block with 6 tx'es, don't submit until end
self.move_tip(55)
b57p2 = self.next_block("57p2")
- tx = self.create_and_sign_transaction(out[16].tx, out[16].n, 1)
+ tx = self.create_and_sign_transaction(out[16], 1)
tx1 = self.create_tx(tx, 0, 1)
tx2 = self.create_tx(tx1, 0, 1)
tx3 = self.create_tx(tx2, 0, 1)
@@ -707,7 +702,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(b56p2.hash, b57p2.hash)
assert_equal(len(b56p2.vtx), 6)
b56p2 = self.update_block("b56p2", [tx3, tx4])
- self.sync_blocks([b56p2], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b56p2], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
self.move_tip("57p2")
self.sync_blocks([b57p2], True)
@@ -727,20 +722,20 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(57)
b58 = self.next_block(58, spend=out[17])
tx = CTransaction()
- assert(len(out[17].tx.vout) < 42)
- tx.vin.append(CTxIn(COutPoint(out[17].tx.sha256, 42), CScript([OP_TRUE]), 0xffffffff))
+ assert(len(out[17].vout) < 42)
+ tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))
tx.vout.append(CTxOut(0, b""))
tx.calc_sha256()
b58 = self.update_block(58, [tx])
- self.sync_blocks([b58], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b58], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# tx with output value > input value
self.log.info("Reject a block with a transaction with outputs > inputs")
self.move_tip(57)
b59 = self.next_block(59)
- tx = self.create_and_sign_transaction(out[17].tx, out[17].n, 51 * COIN)
+ tx = self.create_and_sign_transaction(out[17], 51 * COIN)
b59 = self.update_block(59, [tx])
- self.sync_blocks([b59], False, 16, b'bad-txns-in-belowout', reconnect=True)
+ self.sync_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)
# reset to good chain
self.move_tip(57)
@@ -764,7 +759,7 @@ class FullBlockTest(BitcoinTestFramework):
b61.vtx[0].rehash()
b61 = self.update_block(61, [])
assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
- self.sync_blocks([b61], False, 16, b'bad-txns-BIP30', reconnect=True)
+ self.sync_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)
# Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
#
@@ -776,13 +771,12 @@ class FullBlockTest(BitcoinTestFramework):
b62 = self.next_block(62)
tx = CTransaction()
tx.nLockTime = 0xffffffff # this locktime is non-final
- assert(out[18].n < len(out[18].tx.vout))
- tx.vin.append(CTxIn(COutPoint(out[18].tx.sha256, out[18].n))) # don't set nSequence
+ tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0))) # don't set nSequence
tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
assert(tx.vin[0].nSequence < 0xffffffff)
tx.calc_sha256()
b62 = self.update_block(62, [tx])
- self.sync_blocks([b62], False, 16, b'bad-txns-nonfinal')
+ self.sync_blocks([b62], success=False, reject_reason='bad-txns-nonfinal')
# Test a non-final coinbase is also rejected
#
@@ -796,7 +790,7 @@ class FullBlockTest(BitcoinTestFramework):
b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
b63.vtx[0].rehash()
b63 = self.update_block(63, [])
- self.sync_blocks([b63], False, 16, b'bad-txns-nonfinal')
+ self.sync_blocks([b63], success=False, reject_reason='bad-txns-nonfinal')
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that
# the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
@@ -830,7 +824,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
b64a = self.update_block("64a", [tx])
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
- self.sync_blocks([b64a], False, 1, b'error parsing message')
+ self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize(): iostream error')
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
# resend the header message, it won't send us the getdata message again. Just
@@ -856,8 +850,8 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Accept a block with a transaction spending an output created in the same block")
self.move_tip(64)
b65 = self.next_block(65)
- tx1 = self.create_and_sign_transaction(out[19].tx, out[19].n, out[19].tx.vout[0].nValue)
- tx2 = self.create_and_sign_transaction(tx1, 0, 0)
+ tx1 = self.create_and_sign_transaction(out[19], out[19].vout[0].nValue)
+ tx2 = self.create_and_sign_transaction(tx1, 0)
b65 = self.update_block(65, [tx1, tx2])
self.sync_blocks([b65], True)
self.save_spendable_output()
@@ -869,10 +863,10 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with a transaction spending an output created later in the same block")
self.move_tip(65)
b66 = self.next_block(66)
- tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue)
- tx2 = self.create_and_sign_transaction(tx1, 0, 1)
+ tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
+ tx2 = self.create_and_sign_transaction(tx1, 1)
b66 = self.update_block(66, [tx2, tx1])
- self.sync_blocks([b66], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b66], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to double-spend a transaction created in a block
#
@@ -883,11 +877,11 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with a transaction double spending a transaction creted in the same block")
self.move_tip(65)
b67 = self.next_block(67)
- tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue)
- tx2 = self.create_and_sign_transaction(tx1, 0, 1)
- tx3 = self.create_and_sign_transaction(tx1, 0, 2)
+ tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
+ tx2 = self.create_and_sign_transaction(tx1, 1)
+ tx3 = self.create_and_sign_transaction(tx1, 2)
b67 = self.update_block(67, [tx1, tx2, tx3])
- self.sync_blocks([b67], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# More tests of block subsidy
#
@@ -904,14 +898,14 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block trying to claim too much subsidy in the coinbase transaction")
self.move_tip(65)
b68 = self.next_block(68, additional_coinbase_value=10)
- tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 9)
+ tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)
b68 = self.update_block(68, [tx])
- self.sync_blocks([b68], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)
self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")
self.move_tip(65)
b69 = self.next_block(69, additional_coinbase_value=10)
- tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 10)
+ tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 10)
self.update_block(69, [tx])
self.sync_blocks([b69], True)
self.save_spendable_output()
@@ -930,7 +924,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
tx.vout.append(CTxOut(1, b""))
b70 = self.update_block(70, [tx])
- self.sync_blocks([b70], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
#
@@ -942,8 +936,8 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability")
self.move_tip(69)
b72 = self.next_block(72)
- tx1 = self.create_and_sign_transaction(out[21].tx, out[21].n, 2)
- tx2 = self.create_and_sign_transaction(tx1, 0, 1)
+ tx1 = self.create_and_sign_transaction(out[21], 2)
+ tx2 = self.create_and_sign_transaction(tx1, 1)
b72 = self.update_block(72, [tx1, tx2]) # now tip is 72
b71 = copy.deepcopy(b72)
b71.vtx.append(tx2) # add duplicate tx2
@@ -955,7 +949,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(b72.sha256, b71.sha256)
self.move_tip(71)
- self.sync_blocks([b71], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
self.move_tip(72)
self.sync_blocks([b72], True)
@@ -990,12 +984,12 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS + 2] = 0
a[MAX_BLOCK_SIGOPS + 3] = 0
- tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a))
+ tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b73 = self.update_block(73, [tx])
assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b73], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)
- # b74/75 - if we push an invalid script element, all prevous sigops are counted,
+ # b74/75 - if we push an invalid script element, all previous sigops are counted,
# but sigops after the element are not counted.
#
# The invalid script element is that the push_data indicates that
@@ -1015,9 +1009,9 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS + 2] = 0xff
a[MAX_BLOCK_SIGOPS + 3] = 0xff
a[MAX_BLOCK_SIGOPS + 4] = 0xff
- tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a))
+ tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b74 = self.update_block(74, [tx])
- self.sync_blocks([b74], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)
self.move_tip(72)
b75 = self.next_block(75)
@@ -1028,7 +1022,7 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS + 1] = 0xff
a[MAX_BLOCK_SIGOPS + 2] = 0xff
a[MAX_BLOCK_SIGOPS + 3] = 0xff
- tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a))
+ tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b75 = self.update_block(75, [tx])
self.sync_blocks([b75], True)
self.save_spendable_output()
@@ -1039,7 +1033,7 @@ class FullBlockTest(BitcoinTestFramework):
size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5
a = bytearray([OP_CHECKSIG] * size)
a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs
- tx = self.create_and_sign_transaction(out[23].tx, 0, 1, CScript(a))
+ tx = self.create_and_sign_transaction(out[23], 1, CScript(a))
b76 = self.update_block(76, [tx])
self.sync_blocks([b76], True)
self.save_spendable_output()
@@ -1064,7 +1058,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Test transaction resurrection during a re-org")
self.move_tip(76)
b77 = self.next_block(77)
- tx77 = self.create_and_sign_transaction(out[24].tx, out[24].n, 10 * COIN)
+ tx77 = self.create_and_sign_transaction(out[24], 10 * COIN)
b77 = self.update_block(77, [tx77])
self.sync_blocks([b77], True)
self.save_spendable_output()
@@ -1109,9 +1103,9 @@ class FullBlockTest(BitcoinTestFramework):
b83 = self.next_block(83)
op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]
script = CScript(op_codes)
- tx1 = self.create_and_sign_transaction(out[28].tx, out[28].n, out[28].tx.vout[0].nValue, script)
+ tx1 = self.create_and_sign_transaction(out[28], out[28].vout[0].nValue, script)
- tx2 = self.create_and_sign_transaction(tx1, 0, 0, CScript([OP_TRUE]))
+ tx2 = self.create_and_sign_transaction(tx1, 0, CScript([OP_TRUE]))
tx2.vin[0].scriptSig = CScript([OP_FALSE])
tx2.rehash()
@@ -1126,13 +1120,13 @@ class FullBlockTest(BitcoinTestFramework):
#
self.log.info("Test re-orging blocks with OP_RETURN in them")
b84 = self.next_block(84)
- tx1 = self.create_tx(out[29].tx, out[29].n, 0, CScript([OP_RETURN]))
+ tx1 = self.create_tx(out[29], 0, 0, CScript([OP_RETURN]))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.calc_sha256()
- self.sign_tx(tx1, out[29].tx, out[29].n)
+ self.sign_tx(tx1, out[29])
tx1.rehash()
tx2 = self.create_tx(tx1, 1, 0, CScript([OP_RETURN]))
tx2.vout.append(CTxOut(0, CScript([OP_RETURN])))
@@ -1166,7 +1160,7 @@ class FullBlockTest(BitcoinTestFramework):
b89a = self.next_block("89a", spend=out[32])
tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
b89a = self.update_block("89a", [tx])
- self.sync_blocks([b89a], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)")
@@ -1217,21 +1211,21 @@ class FullBlockTest(BitcoinTestFramework):
# this is a little handier to use than the version in blocktools.py
def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])):
- return create_transaction(spend_tx, n, b"", value, script)
+ return create_tx_with_script(spend_tx, n, amount=value, script_pub_key=script)
# sign a transaction, using the key we know about
# this signs input 0 in tx, which is assumed to be spending output n in spend_tx
- def sign_tx(self, tx, spend_tx, n):
- scriptPubKey = bytearray(spend_tx.vout[n].scriptPubKey)
+ def sign_tx(self, tx, spend_tx):
+ scriptPubKey = bytearray(spend_tx.vout[0].scriptPubKey)
if (scriptPubKey[0] == OP_TRUE): # an anyone-can-spend
tx.vin[0].scriptSig = CScript()
return
- (sighash, err) = SignatureHash(spend_tx.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL)
+ (sighash, err) = SignatureHash(spend_tx.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL)
tx.vin[0].scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))])
- def create_and_sign_transaction(self, spend_tx, n, value, script=CScript([OP_TRUE])):
- tx = self.create_tx(spend_tx, n, value, script)
- self.sign_tx(tx, spend_tx, n)
+ def create_and_sign_transaction(self, spend_tx, value, script=CScript([OP_TRUE])):
+ tx = self.create_tx(spend_tx, 0, value, script)
+ self.sign_tx(tx, spend_tx)
tx.rehash()
return tx
@@ -1250,11 +1244,11 @@ class FullBlockTest(BitcoinTestFramework):
if spend is None:
block = create_block(base_block_hash, coinbase, block_time)
else:
- coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees
+ coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees
coinbase.rehash()
block = create_block(base_block_hash, coinbase, block_time)
- tx = create_transaction(spend.tx, spend.n, b"", 1, script) # spend 1 satoshi
- self.sign_tx(tx, spend.tx, spend.n)
+ tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi
+ self.sign_tx(tx, spend)
self.add_transactions_to_block(block, [tx])
block.hashMerkleRoot = block.calc_merkle_root()
if solve:
@@ -1273,7 +1267,7 @@ class FullBlockTest(BitcoinTestFramework):
# get an output that we previously marked as spendable
def get_spendable_output(self):
self.log.debug("getting spendable output %s" % self.spendable_outputs[0].vtx[0])
- return PreviousSpendableOutput(self.spendable_outputs.pop(0).vtx[0], 0)
+ return self.spendable_outputs.pop(0).vtx[0]
# move the tip back to a previous block
def move_tip(self, number):
@@ -1299,7 +1293,6 @@ class FullBlockTest(BitcoinTestFramework):
Helper to connect and wait for version handshake."""
self.nodes[0].add_p2p_connection(P2PDataStore())
- network_thread_start()
# We need to wait for the initial getheaders from the peer before we
# start populating our blockstore. If we don't, then we may run ahead
# to the next subtest before we receive the getheaders. We'd then send
@@ -1314,14 +1307,13 @@ class FullBlockTest(BitcoinTestFramework):
The node gets disconnected several times in this test. This helper
method reconnects the p2p and restarts the network thread."""
self.nodes[0].disconnect_p2ps()
- network_thread_join()
self.bootstrap_p2p()
- def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True, reconnect=False, timeout=60):
+ def sync_blocks(self, blocks, success=True, reject_reason=None, request_block=True, reconnect=False, timeout=60):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
Call with success = False if the tip shouldn't advance to the most recent block."""
- self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_code=reject_code, reject_reason=reject_reason, request_block=request_block, timeout=timeout)
+ self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason, request_block=request_block, timeout=timeout, expect_disconnect=reconnect)
if reconnect:
self.reconnect_p2p()
diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py
index 56f91651a8..c170f510c8 100755
--- a/test/functional/feature_blocksdir.py
+++ b/test/functional/feature_blocksdir.py
@@ -20,14 +20,14 @@ class BlocksdirTest(BitcoinTestFramework):
self.stop_node(0)
shutil.rmtree(self.nodes[0].datadir)
initialize_datadir(self.options.tmpdir, 0)
- self.log.info("Starting with non exiting blocksdir ...")
+ self.log.info("Starting with nonexistent blocksdir ...")
blocksdir_path = os.path.join(self.options.tmpdir, 'blocksdir')
self.nodes[0].assert_start_raises_init_error(["-blocksdir=" + blocksdir_path], 'Error: Specified blocks directory "{}" does not exist.'.format(blocksdir_path))
os.mkdir(blocksdir_path)
- self.log.info("Starting with exiting blocksdir ...")
+ self.log.info("Starting with existing blocksdir ...")
self.start_node(0, ["-blocksdir=" + blocksdir_path])
self.log.info("mining blocks..")
- self.nodes[0].generate(10)
+ self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
assert os.path.isfile(os.path.join(blocksdir_path, "regtest", "blocks", "blk00000.dat"))
assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest", "blocks", "index"))
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index e9a8945e76..f84b08a199 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP65 (CHECKLOCKTIMEVERIFY).
@@ -8,11 +8,17 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
1351.
"""
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import *
-from test_framework.blocktools import create_coinbase, create_block
+from test_framework.blocktools import create_coinbase, create_block, create_transaction
+from test_framework.messages import CTransaction, msg_block, ToHex
+from test_framework.mininode import P2PInterface
from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ hex_str_to_bytes,
+)
+
from io import BytesIO
CLTV_HEIGHT = 1351
@@ -49,38 +55,27 @@ def cltv_validate(node, tx, height):
list(CScript(new_tx.vin[0].scriptSig)))
return new_tx
-def create_transaction(node, coinbase, to_address, amount):
- from_txid = node.getblock(coinbase)['tx'][0]
- inputs = [{ "txid" : from_txid, "vout" : 0}]
- outputs = { to_address : amount }
- rawtx = node.createrawtransaction(inputs, outputs)
- signresult = node.signrawtransactionwithwallet(rawtx)
- tx = CTransaction()
- tx.deserialize(BytesIO(hex_str_to_bytes(signresult['hex'])))
- return tx
class BIP65Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
+ self.extra_args = [['-whitelist=127.0.0.1', '-par=1']] # Use only one script thread to get the exact reject reason for testing
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
- network_thread_start()
-
- # wait_for_verack ensures that the P2P connection is fully up.
- self.nodes[0].p2p.wait_for_verack()
-
self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
- self.coinbase_blocks = self.nodes[0].generate(CLTV_HEIGHT - 2)
+ self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)]
self.nodeaddress = self.nodes[0].getnewaddress()
self.log.info("Test that an invalid-according-to-CLTV transaction can still appear in a block")
- spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[0],
- self.nodeaddress, 1.0)
+ spendtx = create_transaction(self.nodes[0], self.coinbase_txids[0],
+ self.nodeaddress, amount=1.0)
cltv_invalidate(spendtx)
spendtx.rehash()
@@ -101,47 +96,36 @@ class BIP65Test(BitcoinTestFramework):
block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
block.nVersion = 3
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
- with mininode_lock:
- assert_equal(self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000003)')
- assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- del self.nodes[0].p2p.last_message["reject"]
+ with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000003)'.format(block.hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block")
block.nVersion = 4
- spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[1],
- self.nodeaddress, 1.0)
+ spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1],
+ self.nodeaddress, amount=1.0)
cltv_invalidate(spendtx)
spendtx.rehash()
# First we show that this tx is valid except for CLTV by getting it
- # accepted to the mempool (which we can achieve with
- # -promiscuousmempoolflags).
- self.nodes[0].p2p.send_and_ping(msg_tx(spendtx))
- assert spendtx.hash in self.nodes[0].getrawmempool()
+ # rejected from the mempool for exactly that reason.
+ assert_equal(
+ [{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
+ self.nodes[0].testmempoolaccept(rawtxs=[bytes_to_hex_str(spendtx.serialize())], allowhighfees=True)
+ )
- # Now we verify that a block with this transaction is invalid.
+ # Now we verify that a block with this transaction is also invalid.
block.vtx.append(spendtx)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
-
- wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
- with mininode_lock:
- assert self.nodes[0].p2p.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
- assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
- # Generic rejection when a block is invalid
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'block-validation-failed')
- else:
- assert b'Negative locktime' in self.nodes[0].p2p.last_message["reject"].reason
+ with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index e9924451d1..1124119e2b 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test various command line arguments and configuration file parameters."""
@@ -14,8 +14,32 @@ class ConfArgsTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def test_config_file_parser(self):
+ # Assume node is stopped
+
+ inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf')
+ with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf:
+ conf.write('includeconf={}\n'.format(inc_conf_file_path))
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('-dash=1\n')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('nono\n')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('') # clear
+
def run_test(self):
self.stop_node(0)
+
+ self.test_config_file_parser()
+
# Remove the -datadir argument so it doesn't override the config file
self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")]
@@ -36,13 +60,15 @@ class ConfArgsTest(BitcoinTestFramework):
f.write("datadir=" + new_data_dir + "\n")
f.write(conf_file_contents)
- self.nodes[0].assert_start_raises_init_error(['-conf=' + conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.')
+ # Temporarily disabled, because this test would access the user's home dir (~/.bitcoin)
+ #self.nodes[0].assert_start_raises_init_error(['-conf=' + conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.')
# Create the directory and ensure the config file now works
os.mkdir(new_data_dir)
- self.start_node(0, ['-conf='+conf_file, '-wallet=w1'])
- self.stop_node(0)
- assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1'))
+ # Temporarily disabled, because this test would access the user's home dir (~/.bitcoin)
+ #self.start_node(0, ['-conf='+conf_file, '-wallet=w1'])
+ #self.stop_node(0)
+ #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1'))
# Ensure command line argument overrides datadir in conf
os.mkdir(new_data_dir_2)
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index 37d60aad61..df79c4312c 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test activation of the first version bits soft fork.
@@ -47,9 +47,9 @@ from itertools import product
from io import BytesIO
import time
-from test_framework.blocktools import create_coinbase, create_block
+from test_framework.blocktools import create_coinbase, create_block, create_transaction
from test_framework.messages import ToHex, CTransaction
-from test_framework.mininode import network_thread_start, P2PDataStore
+from test_framework.mininode import P2PDataStore
from test_framework.script import (
CScript,
OP_CHECKSEQUENCEVERIFY,
@@ -85,15 +85,6 @@ def relative_locktime(sdf, srhb, stf, srlb):
def all_rlt_txs(txs):
return [tx['tx'] for tx in txs]
-def create_transaction(node, txid, to_address, amount):
- inputs = [{"txid": txid, "vout": 0}]
- outputs = {to_address: amount}
- rawtx = node.createrawtransaction(inputs, outputs)
- tx = CTransaction()
- f = BytesIO(hex_str_to_bytes(rawtx))
- tx.deserialize(f)
- return tx
-
def sign_transaction(node, unsignedtx):
rawtx = ToHex(unsignedtx)
signresult = node.signrawtransactionwithwallet(rawtx)
@@ -103,15 +94,14 @@ def sign_transaction(node, unsignedtx):
return tx
def create_bip112special(node, input, txversion, address):
- tx = create_transaction(node, input, address, Decimal("49.98"))
+ tx = create_transaction(node, input, address, amount=Decimal("49.98"))
tx.nVersion = txversion
signtx = sign_transaction(node, tx)
signtx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))
return signtx
def send_generic_input_tx(node, coinbases, address):
- amount = Decimal("49.99")
- return node.sendrawtransaction(ToHex(sign_transaction(node, create_transaction(node, node.getblock(coinbases.pop())['tx'][0], address, amount))))
+ return node.sendrawtransaction(ToHex(sign_transaction(node, create_transaction(node, node.getblock(coinbases.pop())['tx'][0], address, amount=Decimal("49.99")))))
def create_bip68txs(node, bip68inputs, txversion, address, locktime_delta=0):
"""Returns a list of bip68 transactions with different bits set."""
@@ -119,7 +109,7 @@ def create_bip68txs(node, bip68inputs, txversion, address, locktime_delta=0):
assert(len(bip68inputs) >= 16)
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
locktime = relative_locktime(sdf, srhb, stf, srlb)
- tx = create_transaction(node, bip68inputs[i], address, Decimal("49.98"))
+ tx = create_transaction(node, bip68inputs[i], address, amount=Decimal("49.98"))
tx.nVersion = txversion
tx.vin[0].nSequence = locktime + locktime_delta
tx = sign_transaction(node, tx)
@@ -134,7 +124,7 @@ def create_bip112txs(node, bip112inputs, varyOP_CSV, txversion, address, locktim
assert(len(bip112inputs) >= 16)
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
locktime = relative_locktime(sdf, srhb, stf, srlb)
- tx = create_transaction(node, bip112inputs[i], address, Decimal("49.98"))
+ tx = create_transaction(node, bip112inputs[i], address, amount=Decimal("49.98"))
if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed
tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta
else: # vary nSequence instead, OP_CSV is fixed
@@ -155,6 +145,9 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.setup_clean_chain = True
self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4', '-addresstype=legacy']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def generate_blocks(self, number, version, test_blocks=None):
if test_blocks is None:
test_blocks = []
@@ -175,16 +168,14 @@ class BIP68_112_113Test(BitcoinTestFramework):
block.solve()
return block
- def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True):
+ def sync_blocks(self, blocks, success=True):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
Call with success = False if the tip shouldn't advance to the most recent block."""
- self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_code=reject_code, reject_reason=reject_reason, request_block=request_block)
+ self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success)
def run_test(self):
self.nodes[0].add_p2p_connection(P2PDataStore())
- network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
self.log.info("Generate blocks in the past for coinbase outputs.")
long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future
@@ -280,10 +271,10 @@ class BIP68_112_113Test(BitcoinTestFramework):
# Test both version 1 and version 2 transactions for all tests
# BIP113 test transaction will be modified before each use to put in appropriate block time
- bip113tx_v1 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98"))
+ bip113tx_v1 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, amount=Decimal("49.98"))
bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE
bip113tx_v1.nVersion = 1
- bip113tx_v2 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98"))
+ bip113tx_v2 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, amount=Decimal("49.98"))
bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE
bip113tx_v2.nVersion = 2
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index cef257cf9b..ae1eacf2d7 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test recovery from a crash during chainstate writing.
@@ -31,10 +31,9 @@ import random
import sys
import time
-from test_framework.mininode import *
-from test_framework.script import *
+from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, ToHex
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, create_confirmed_utxos, hex_str_to_bytes
HTTP_DISCONNECT_ERRORS = [http.client.CannotSendRequest]
try:
@@ -46,6 +45,8 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = False
+ # Need a bit of extra time for the nodes to start up for this test
+ self.rpc_timewait = 90
# Set -maxmempool=0 to turn off mempool memory sharing with dbcache
# Set -rpcservertimeout=900 to reduce socket disconnects in this
@@ -62,9 +63,11 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.node3_args = ["-blockmaxweight=4000000"]
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
- # Need a bit of extra time for the nodes to start up for this test
- self.add_nodes(self.num_nodes, extra_args=self.extra_args, timewait=90)
+ self.add_nodes(self.num_nodes, extra_args=self.extra_args)
self.start_nodes()
# Leave them unconnected, we'll use submitblock directly in this test
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 02dcc3e55d..16272877e7 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP66 (DER SIG).
@@ -7,12 +7,16 @@
Test that the DERSIG soft-fork activates at (regtest) height 1251.
"""
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import *
-from test_framework.blocktools import create_coinbase, create_block
+from test_framework.blocktools import create_coinbase, create_block, create_transaction
+from test_framework.messages import msg_block
+from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.script import CScript
-from io import BytesIO
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ wait_until,
+)
DERSIG_HEIGHT = 1251
@@ -37,38 +41,28 @@ def unDERify(tx):
newscript.append(i)
tx.vin[0].scriptSig = CScript(newscript)
-def create_transaction(node, coinbase, to_address, amount):
- from_txid = node.getblock(coinbase)['tx'][0]
- inputs = [{ "txid" : from_txid, "vout" : 0}]
- outputs = { to_address : amount }
- rawtx = node.createrawtransaction(inputs, outputs)
- signresult = node.signrawtransactionwithwallet(rawtx)
- tx = CTransaction()
- tx.deserialize(BytesIO(hex_str_to_bytes(signresult['hex'])))
- return tx
+
class BIP66Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
+ self.extra_args = [['-whitelist=127.0.0.1', '-par=1', '-enablebip61']] # Use only one script thread to get the exact reject reason for testing
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
- network_thread_start()
-
- # wait_for_verack ensures that the P2P connection is fully up.
- self.nodes[0].p2p.wait_for_verack()
-
self.log.info("Mining %d blocks", DERSIG_HEIGHT - 2)
- self.coinbase_blocks = self.nodes[0].generate(DERSIG_HEIGHT - 2)
+ self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(DERSIG_HEIGHT - 2)]
self.nodeaddress = self.nodes[0].getnewaddress()
self.log.info("Test that a transaction with non-DER signature can still appear in a block")
- spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[0],
- self.nodeaddress, 1.0)
+ spendtx = create_transaction(self.nodes[0], self.coinbase_txids[0],
+ self.nodeaddress, amount=1.0)
unDERify(spendtx)
spendtx.rehash()
@@ -91,57 +85,46 @@ class BIP66Test(BitcoinTestFramework):
block.nVersion = 2
block.rehash()
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
- with mininode_lock:
- assert_equal(self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000002)')
- assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- del self.nodes[0].p2p.last_message["reject"]
+ with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000002)'.format(block.hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
block.nVersion = 3
- spendtx = create_transaction(self.nodes[0], self.coinbase_blocks[1],
- self.nodeaddress, 1.0)
+ spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1],
+ self.nodeaddress, amount=1.0)
unDERify(spendtx)
spendtx.rehash()
# First we show that this tx is valid except for DERSIG by getting it
- # accepted to the mempool (which we can achieve with
- # -promiscuousmempoolflags).
- self.nodes[0].p2p.send_and_ping(msg_tx(spendtx))
- assert spendtx.hash in self.nodes[0].getrawmempool()
+ # rejected from the mempool for exactly that reason.
+ assert_equal(
+ [{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
+ self.nodes[0].testmempoolaccept(rawtxs=[bytes_to_hex_str(spendtx.serialize())], allowhighfees=True)
+ )
- # Now we verify that a block with this transaction is invalid.
+ # Now we verify that a block with this transaction is also invalid.
block.vtx.append(spendtx)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Non-canonical DER signature)'.format(block.vtx[-1].hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
with mininode_lock:
- # We can receive different reject messages depending on whether
- # bitcoind is running with multiple script check threads. If script
- # check threads are not in use, then transaction script validation
- # happens sequentially, and bitcoind produces more specific reject
- # reasons.
assert self.nodes[0].p2p.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
- # Generic rejection when a block is invalid
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'block-validation-failed')
- else:
- assert b'Non-canonical DER signature' in self.nodes[0].p2p.last_message["reject"].reason
+ assert b'Non-canonical DER signature' in self.nodes[0].p2p.last_message["reject"].reason
self.log.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted")
- block.vtx[1] = create_transaction(self.nodes[0],
- self.coinbase_blocks[1], self.nodeaddress, 1.0)
+ block.vtx[1] = create_transaction(self.nodes[0], self.coinbase_txids[1], self.nodeaddress, amount=1.0)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
block.solve()
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 32a6bd5d59..aaab4279b5 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test fee estimation code."""
from decimal import Decimal
import random
-from test_framework.mininode import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN
+from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN
from test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_EQUAL, hash160, OP_TRUE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -126,6 +126,9 @@ class EstimateFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
"""
We'll setup the network to have 3 nodes that all mine with different parameters.
@@ -168,6 +171,11 @@ class EstimateFeeTest(BitcoinTestFramework):
newmem.append(utx)
self.memutxo = newmem
+ def import_deterministic_coinbase_privkeys(self):
+ self.start_nodes()
+ super().import_deterministic_coinbase_privkeys()
+ self.stop_nodes()
+
def run_test(self):
self.log.info("This test is time consuming, please be patient")
self.log.info("Splitting inputs so we can generate tx's")
diff --git a/test/functional/feature_help.py b/test/functional/feature_help.py
index d38275a9ca..ed1d25c0d6 100755
--- a/test/functional/feature_help.py
+++ b/test/functional/feature_help.py
@@ -3,7 +3,6 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Verify that starting bitcoin with -h works as expected."""
-import subprocess
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -17,41 +16,47 @@ class HelpTest(BitcoinTestFramework):
self.add_nodes(self.num_nodes)
# Don't start the node
+ def get_node_output(self, *, ret_code_expected):
+ ret_code = self.nodes[0].process.wait(timeout=5)
+ assert_equal(ret_code, ret_code_expected)
+ self.nodes[0].stdout.seek(0)
+ self.nodes[0].stderr.seek(0)
+ out = self.nodes[0].stdout.read()
+ err = self.nodes[0].stderr.read()
+ self.nodes[0].stdout.close()
+ self.nodes[0].stderr.close()
+
+ # Clean up TestNode state
+ self.nodes[0].running = False
+ self.nodes[0].process = None
+ self.nodes[0].rpc_connected = False
+ self.nodes[0].rpc = None
+
+ return out, err
+
def run_test(self):
self.log.info("Start bitcoin with -h for help text")
- self.nodes[0].start(extra_args=['-h'], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+ self.nodes[0].start(extra_args=['-h'])
# Node should exit immediately and output help to stdout.
- ret_code = self.nodes[0].process.wait(timeout=1)
- assert_equal(ret_code, 0)
- output = self.nodes[0].process.stdout.read()
+ output, _ = self.get_node_output(ret_code_expected=0)
assert b'Options' in output
self.log.info("Help text received: {} (...)".format(output[0:60]))
- self.nodes[0].running = False
self.log.info("Start bitcoin with -version for version information")
- self.nodes[0].start(extra_args=['-version'], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+ self.nodes[0].start(extra_args=['-version'])
# Node should exit immediately and output version to stdout.
- ret_code = self.nodes[0].process.wait(timeout=1)
- assert_equal(ret_code, 0)
- output = self.nodes[0].process.stdout.read()
+ output, _ = self.get_node_output(ret_code_expected=0)
assert b'version' in output
self.log.info("Version text received: {} (...)".format(output[0:60]))
# Test that arguments not in the help results in an error
self.log.info("Start bitcoind with -fakearg to make sure it does not start")
- self.nodes[0].start(extra_args=['-fakearg'], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+ self.nodes[0].start(extra_args=['-fakearg'])
# Node should exit immediately and output an error to stderr
- ret_code = self.nodes[0].process.wait(timeout=1)
- assert_equal(ret_code, 1)
- output = self.nodes[0].process.stderr.read()
+ _, output = self.get_node_output(ret_code_expected=1)
assert b'Error parsing command line arguments' in output
self.log.info("Error message received: {} (...)".format(output[0:60]))
- # Clean up TestNode state
- self.nodes[0].running = False
- self.nodes[0].process = None
- self.nodes[0].rpc_connected = False
- self.nodes[0].rpc = None
if __name__ == '__main__':
HelpTest().main()
diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py
index 9a7a0ca103..d06f6826f0 100755
--- a/test/functional/feature_includeconf.py
+++ b/test/functional/feature_includeconf.py
@@ -55,9 +55,11 @@ class IncludeConfTest(BitcoinTestFramework):
self.stop_node(0, expected_stderr="warning: -includeconf cannot be used from included files; ignoring -includeconf=relative2.conf")
self.log.info("-includeconf cannot contain invalid arg")
- with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "w", encoding="utf8") as f:
- f.write("foo=bar\n")
- self.nodes[0].assert_start_raises_init_error(expected_msg="Error reading configuration file: Invalid configuration value foo")
+
+ # Commented out as long as we ignore invalid arguments in configuration files
+ #with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "w", encoding="utf8") as f:
+ # f.write("foo=bar\n")
+ #self.nodes[0].assert_start_raises_init_error(expected_msg="Error reading configuration file: Invalid configuration value foo")
self.log.info("-includeconf cannot be invalid path")
os.remove(os.path.join(self.options.tmpdir, "node0", "relative.conf"))
diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py
index 166f8f8694..8bb7e02695 100755
--- a/test/functional/feature_logging.py
+++ b/test/functional/feature_logging.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test debug logging."""
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index 0946f27b90..87c318de9a 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test behavior of -maxuploadtarget.
@@ -13,9 +13,10 @@ if uploadtarget has been reached.
from collections import defaultdict
import time
-from test_framework.mininode import *
+from test_framework.messages import CInv, msg_getdata
+from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, mine_large_block
class TestP2PConn(P2PInterface):
def __init__(self):
@@ -39,6 +40,9 @@ class MaxUploadTest(BitcoinTestFramework):
# Cache for utxos, as the listunspent may take a long time later in the test
self.utxo_cache = []
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Before we connect anything, we first set the time on the node
# to be in the past, otherwise things break because the CNode
@@ -57,12 +61,6 @@ class MaxUploadTest(BitcoinTestFramework):
for _ in range(3):
p2p_conns.append(self.nodes[0].add_p2p_connection(TestP2PConn()))
- network_thread_start()
- for p2pc in p2p_conns:
- p2pc.wait_for_verack()
-
- # Test logic begins here
-
# Now mine a big block
mine_large_block(self.nodes[0], self.utxo_cache)
@@ -149,9 +147,6 @@ class MaxUploadTest(BitcoinTestFramework):
# Reconnect to self.nodes[0]
self.nodes[0].add_p2p_connection(TestP2PConn())
- network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
-
#retrieve 20 blocks which should be enough to break the 1MB limit
getdata_request.inv = [CInv(2, big_new_block)]
for i in range(20):
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py
index 90a3de0e0d..dbff6f15f2 100755
--- a/test/functional/feature_minchainwork.py
+++ b/test/functional/feature_minchainwork.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test logic for setting nMinimumChainWork on command line.
@@ -51,7 +51,8 @@ class MinimumChainWorkTest(BitcoinTestFramework):
num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK)
self.log.info("Generating %d blocks on node0", num_blocks_to_generate)
- hashes = self.nodes[0].generate(num_blocks_to_generate)
+ hashes = self.nodes[0].generatetoaddress(num_blocks_to_generate,
+ self.nodes[0].get_deterministic_priv_key().address)
self.log.info("Node0 current chain work: %s", self.nodes[0].getblockheader(hashes[-1])['chainwork'])
@@ -72,7 +73,7 @@ class MinimumChainWorkTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getblockcount(), starting_blockcount)
self.log.info("Generating one more block")
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
self.log.info("Verifying nodes are all synced")
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 8964c8d64b..25a7329a0d 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the -alertnotify, -blocknotify and -walletnotify options."""
@@ -13,6 +13,9 @@ class NotificationsTest(BitcoinTestFramework):
self.num_nodes = 2
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
self.block_filename = os.path.join(self.options.tmpdir, "blocks.txt")
@@ -36,7 +39,7 @@ class NotificationsTest(BitcoinTestFramework):
wait_until(lambda: os.path.isfile(self.block_filename) and os.stat(self.block_filename).st_size >= (block_count * 65), timeout=10)
# file content should equal the generated blocks hashes
- with open(self.block_filename, 'r') as f:
+ with open(self.block_filename, 'r', encoding="utf-8") as f:
assert_equal(sorted(blocks), sorted(l.strip() for l in f.read().splitlines()))
self.log.info("test -walletnotify")
@@ -45,7 +48,7 @@ class NotificationsTest(BitcoinTestFramework):
# file content should equal the generated transaction hashes
txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
- with open(self.tx_filename, 'r') as f:
+ with open(self.tx_filename, 'r', encoding="ascii") as f:
assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines()))
os.remove(self.tx_filename)
@@ -58,7 +61,7 @@ class NotificationsTest(BitcoinTestFramework):
# file content should equal the generated transaction hashes
txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
- with open(self.tx_filename, 'r') as f:
+ with open(self.tx_filename, 'r', encoding="ascii") as f:
assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines()))
# Mine another 41 up-version blocks. -alertnotify should trigger on the 51st.
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 7db6a03b45..a79cc3d34b 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test NULLDUMMY softfork.
@@ -13,12 +13,12 @@ Generate 427 more blocks.
[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.
"""
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import CTransaction, network_thread_start
-from test_framework.blocktools import create_coinbase, create_block, add_witness_commitment
+from test_framework.blocktools import create_coinbase, create_block, create_transaction, add_witness_commitment
+from test_framework.messages import CTransaction
from test_framework.script import CScript
-from io import BytesIO
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str
+
import time
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)"
@@ -42,15 +42,17 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.setup_clean_chain = True
# This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
# normal segwit activation here (and don't use the default always-on behaviour).
- self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
self.address = self.nodes[0].getnewaddress()
- self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])['address']
+ self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address])['address']
self.wit_address = self.nodes[0].addwitnessaddress(self.address)
self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address']
- network_thread_start()
self.coinbase_blocks = self.nodes[0].generate(2) # Block 2
coinbase_txid = []
for i in self.coinbase_blocks:
@@ -62,16 +64,16 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.lastblocktime = int(time.time()) + 429
self.log.info("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]")
- test1txs = [self.create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, 49)]
+ test1txs = [create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, amount=49)]
txid1 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[0].serialize_with_witness()), True)
- test1txs.append(self.create_transaction(self.nodes[0], txid1, self.ms_address, 48))
+ test1txs.append(create_transaction(self.nodes[0], txid1, self.ms_address, amount=48))
txid2 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[1].serialize_with_witness()), True)
- test1txs.append(self.create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, 49))
+ test1txs.append(create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, amount=49))
txid3 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[2].serialize_with_witness()), True)
self.block_submit(self.nodes[0], test1txs, False, True)
self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
- test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 47)
+ test2tx = create_transaction(self.nodes[0], txid2, self.ms_address, amount=47)
trueDummy(test2tx)
assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True)
@@ -79,14 +81,14 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.block_submit(self.nodes[0], [test2tx], False, True)
self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
- test4tx = self.create_transaction(self.nodes[0], test2tx.hash, self.address, 46)
+ test4tx = create_transaction(self.nodes[0], test2tx.hash, self.address, amount=46)
test6txs=[CTransaction(test4tx)]
trueDummy(test4tx)
assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True)
self.block_submit(self.nodes[0], [test4tx])
self.log.info("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation")
- test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48)
+ test5tx = create_transaction(self.nodes[0], txid3, self.wit_address, amount=48)
test6txs.append(CTransaction(test5tx))
test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01'
assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True)
@@ -98,17 +100,6 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.block_submit(self.nodes[0], test6txs, True, True)
- def create_transaction(self, node, txid, to_address, amount):
- inputs = [{ "txid" : txid, "vout" : 0}]
- outputs = { to_address : amount }
- rawtx = node.createrawtransaction(inputs, outputs)
- signresult = node.signrawtransactionwithwallet(rawtx)
- tx = CTransaction()
- f = BytesIO(hex_str_to_bytes(signresult['hex']))
- tx.deserialize(f)
- return tx
-
-
def block_submit(self, node, txs, witness = False, accept = False):
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)
block.nVersion = 4
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 2d10c547e2..31d2ee8e13 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test bitcoind with different proxy configuration.
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 11a52b9ee2..772151dc4b 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the pruning code.
@@ -10,7 +10,8 @@ This test takes 30 mins or more (up to 2 hours)
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, connect_nodes, mine_large_block, sync_blocks, wait_until
+
import os
MIN_BLOCKS_TO_KEEP = 288
@@ -28,18 +29,24 @@ class PruneTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 6
+ self.rpc_timewait = 900
# Create nodes 0 and 1 to mine.
# Create node 2 to test pruning.
- self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000" ]
+ self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000"]
# Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
# Create nodes 5 to test wallet in prune mode, but do not connect
- self.extra_args = [self.full_node_default_args,
- self.full_node_default_args,
- ["-maxreceivebuffer=20000", "-prune=550"],
- ["-maxreceivebuffer=20000"],
- ["-maxreceivebuffer=20000"],
- ["-prune=550"]]
+ self.extra_args = [
+ self.full_node_default_args,
+ self.full_node_default_args,
+ ["-maxreceivebuffer=20000", "-prune=550"],
+ ["-maxreceivebuffer=20000"],
+ ["-maxreceivebuffer=20000"],
+ ["-prune=550"],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def setup_network(self):
self.setup_nodes()
@@ -54,7 +61,7 @@ class PruneTest(BitcoinTestFramework):
sync_blocks(self.nodes[0:5])
def setup_nodes(self):
- self.add_nodes(self.num_nodes, self.extra_args, timewait=900)
+ self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
def create_big_chain(self):
@@ -260,10 +267,17 @@ class PruneTest(BitcoinTestFramework):
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
assert_raises_rpc_error(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
+ # Save block transaction count before pruning, assert value
+ block1_details = node.getblock(node.getblockhash(1))
+ assert_equal(block1_details["nTx"], len(block1_details["tx"]))
+
# mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
node.generate(6)
assert_equal(node.getblockchaininfo()["blocks"], 1001)
+ # Pruned block should still know the number of transactions
+ assert_equal(node.getblockheader(node.getblockhash(1))["nTx"], block1_details["nTx"])
+
# negative heights should raise an exception
assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10)
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index c087960782..ff7c2b23bf 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -1,13 +1,15 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the RBF code."""
+from decimal import Decimal
+
+from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut
+from test_framework.script import CScript, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.script import *
-from test_framework.mininode import *
+from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, satoshi_round
MAX_REPLACEMENT_LIMIT = 100
@@ -59,17 +61,26 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
return COutPoint(int(txid, 16), 0)
-class ReplaceByFeeTest(BitcoinTestFramework):
+class ReplaceByFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.extra_args= [["-maxorphantx=1000",
- "-whitelist=127.0.0.1",
- "-limitancestorcount=50",
- "-limitancestorsize=101",
- "-limitdescendantcount=200",
- "-limitdescendantsize=101"],
- ["-mempoolreplacement=0"]]
+ self.extra_args = [
+ [
+ "-maxorphantx=1000",
+ "-whitelist=127.0.0.1",
+ "-limitancestorcount=50",
+ "-limitancestorsize=101",
+ "-limitdescendantcount=200",
+ "-limitdescendantsize=101",
+ ],
+ [
+ "-mempoolreplacement=0",
+ ],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
# Leave IBD
@@ -427,6 +438,9 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a_hex = txToHex(tx1a)
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ # This transaction isn't shown as replaceable
+ assert_equal(self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'], False)
+
# Shouldn't be able to double-spend
tx1b = CTransaction()
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
@@ -467,7 +481,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))]
tx3a_hex = txToHex(tx3a)
- self.nodes[0].sendrawtransaction(tx3a_hex, True)
+ tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, True)
+
+ # This transaction is shown as replaceable
+ assert_equal(self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'], True)
tx3b = CTransaction()
tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index d1d3f1d7f1..940b403f9c 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test running bitcoind with -reindex and -reindex-chainstate options.
@@ -19,10 +19,10 @@ class ReindexTest(BitcoinTestFramework):
self.num_nodes = 1
def reindex(self, justchainstate=False):
- self.nodes[0].generate(3)
+ self.nodes[0].generatetoaddress(3, self.nodes[0].get_deterministic_priv_key().address)
blockcount = self.nodes[0].getblockcount()
self.stop_nodes()
- extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
+ extra_args = [["-reindex-chainstate" if justchainstate else "-reindex"]]
self.start_nodes(extra_args)
wait_until(lambda: self.nodes[0].getblockcount() == blockcount)
self.log.info("Success")
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 3622e1834a..2cbfc26e89 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -1,22 +1,26 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the SegWit changeover logic."""
+from decimal import Decimal
+
from test_framework.address import (
+ key_to_p2pkh,
key_to_p2sh_p2wpkh,
key_to_p2wpkh,
program_to_witness,
+ script_to_p2sh,
script_to_p2sh_p2wsh,
script_to_p2wsh,
)
from test_framework.blocktools import witness_script, send_to_witness
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import sha256, CTransaction, CTxIn, COutPoint, CTxOut, COIN, ToHex, FromHex
-from test_framework.address import script_to_p2sh, key_to_p2pkh
+from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, sha256, ToHex
from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE, OP_DROP
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes, hex_str_to_bytes, sync_blocks, try_rpc
+
from io import BytesIO
NODE_0 = 0
@@ -42,9 +46,30 @@ class SegWitTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
- self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
- ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
- ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [
+ [
+ "-rpcserialversion=0",
+ "-vbparams=segwit:0:999999999999",
+ "-addresstype=legacy",
+ "-deprecatedrpc=addwitnessaddress",
+ ],
+ [
+ "-blockversion=4",
+ "-rpcserialversion=1",
+ "-vbparams=segwit:0:999999999999",
+ "-addresstype=legacy",
+ "-deprecatedrpc=addwitnessaddress",
+ ],
+ [
+ "-blockversion=536870915",
+ "-vbparams=segwit:0:999999999999",
+ "-addresstype=legacy",
+ "-deprecatedrpc=addwitnessaddress",
+ ],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def setup_network(self):
super().setup_network()
@@ -64,12 +89,8 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
- assert_raises_rpc_error(-26, error_msg, send_to_witness, 1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
+ assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script)
- def fail_mine(self, node, txid, sign, redeem_script=""):
- send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- assert_raises_rpc_error(-1, "CreateNewBlock: TestBlockValidity failed", node.generate, 1)
- sync_blocks(self.nodes)
def run_test(self):
self.nodes[0].generate(161) #block 161
@@ -129,21 +150,6 @@ class SegWitTest(BitcoinTestFramework):
self.nodes[0].generate(260) #block 423
sync_blocks(self.nodes)
- self.log.info("Verify default node can't accept any witness format txs before fork")
- # unsigned, no scriptsig
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False)
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False)
- # unsigned with redeem script
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))
- self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
- # signed
- self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True)
- self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True)
-
self.log.info("Verify witness txs are skipped for mining before the fork")
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425
@@ -164,6 +170,16 @@ class SegWitTest(BitcoinTestFramework):
segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
assert_equal(len(segwit_tx_list), 5)
+ self.log.info("Verify default node can't accept txs with missing witness")
+ # unsigned, no scriptsig
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False)
+ # unsigned with redeem script
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
+
self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
@@ -176,10 +192,10 @@ class SegWitTest(BitcoinTestFramework):
assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness()))
self.log.info("Verify witness txs without witness data are invalid after the fork")
- self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
- self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False)
- self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, witness_script(False, self.pubkey[2]))
- self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, witness_script(True, self.pubkey[2]))
+ self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)', wit_ids[NODE_2][WIT_V0][2], sign=False)
+ self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)', wit_ids[NODE_2][WIT_V1][2], sign=False)
+ self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)', p2sh_ids[NODE_2][WIT_V0][2], sign=False, redeem_script=witness_script(False, self.pubkey[2]))
+ self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)', p2sh_ids[NODE_2][WIT_V1][2], sign=False, redeem_script=witness_script(True, self.pubkey[2]))
self.log.info("Verify default node can now use witness txs")
self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432
diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py
index 80bd7ff29f..691a39b825 100755
--- a/test/functional/feature_uacomment.py
+++ b/test/functional/feature_uacomment.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the -uacomment option."""
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index 2985569a8f..88df61cabc 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test version bits warning system.
@@ -12,7 +12,7 @@ import re
from test_framework.blocktools import create_block, create_coinbase
from test_framework.messages import msg_block
-from test_framework.mininode import P2PInterface, network_thread_start, mininode_lock
+from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import wait_until
@@ -62,19 +62,17 @@ class VersionBitsWarningTest(BitcoinTestFramework):
return VB_PATTERN.search(alert_text) is not None
def run_test(self):
- # Handy alias
node = self.nodes[0]
node.add_p2p_connection(P2PInterface())
- network_thread_start()
- node.p2p.wait_for_verack()
+ node_deterministic_address = node.get_deterministic_priv_key().address
# Mine one period worth of blocks
- node.generate(VB_PERIOD)
+ node.generatetoaddress(VB_PERIOD, node_deterministic_address)
self.log.info("Check that there is no warning if previous VB_BLOCKS have <VB_THRESHOLD blocks with unknown versionbits version.")
# Build one period of blocks with < VB_THRESHOLD blocks signaling some unknown bit
self.send_blocks_with_version(node.p2p, VB_THRESHOLD - 1, VB_UNKNOWN_VERSION)
- node.generate(VB_PERIOD - VB_THRESHOLD + 1)
+ node.generatetoaddress(VB_PERIOD - VB_THRESHOLD + 1, node_deterministic_address)
# Check that we're not getting any versionbit-related errors in get*info()
assert(not VB_PATTERN.match(node.getmininginfo()["warnings"]))
@@ -83,7 +81,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.log.info("Check that there is a warning if >50 blocks in the last 100 were an unknown version")
# Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit
self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION)
- node.generate(VB_PERIOD - VB_THRESHOLD)
+ node.generatetoaddress(VB_PERIOD - VB_THRESHOLD, node_deterministic_address)
# Check that get*info() shows the 51/100 unknown block version error.
assert(WARN_UNKNOWN_RULES_MINED in node.getmininginfo()["warnings"])
@@ -92,16 +90,16 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.log.info("Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version.")
# Mine a period worth of expected blocks so the generic block-version warning
# is cleared. This will move the versionbit state to ACTIVE.
- node.generate(VB_PERIOD)
+ node.generatetoaddress(VB_PERIOD, node_deterministic_address)
# Stop-start the node. This is required because bitcoind will only warn once about unknown versions or unknown rules activating.
self.restart_node(0)
# Generating one block guarantees that we'll get out of IBD
- node.generate(1)
+ node.generatetoaddress(1, node_deterministic_address)
wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock)
# Generating one more block will be enough to generate an error.
- node.generate(1)
+ node.generatetoaddress(1, node_deterministic_address)
# Check that get*info() shows the versionbits unknown rules warning
assert(WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()["warnings"])
assert(WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()["warnings"])
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index e29fdc84e7..f311858bee 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test bitcoin-cli"""
@@ -12,9 +12,15 @@ class TestBitcoinCli(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
"""Main test logic"""
+ cli_response = self.nodes[0].cli("-version").send_cli()
+ assert("Bitcoin Core RPC client version" in cli_response)
+
self.log.info("Compare responses from gewalletinfo RPC and `bitcoin-cli getwalletinfo`")
cli_response = self.nodes[0].cli.getwalletinfo()
rpc_response = self.nodes[0].getwalletinfo()
diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py
index cd6d744545..e4b86f9e1e 100755
--- a/test/functional/interface_http.py
+++ b/test/functional/interface_http.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the RPC HTTP basics."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, str_to_b64str
import http.client
import urllib.parse
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index a48939d2e0..afa9de580f 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the REST API."""
@@ -43,6 +43,9 @@ class RESTTest (BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-rest"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, body='', status=200, ret_type=RetType.JSON):
rest_uri = '/rest' + uri
if req_type == ReqType.JSON:
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index af2e752b7a..1c518eab75 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -1,19 +1,20 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the ZMQ notification interface."""
-import configparser
import struct
-from test_framework.test_framework import BitcoinTestFramework, SkipTest
-from test_framework.mininode import CTransaction
-from test_framework.util import (assert_equal,
- bytes_to_hex_str,
- hash256,
- )
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.messages import CTransaction
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ hash256,
+)
from io import BytesIO
+
class ZMQSubscriber:
def __init__(self, socket, topic):
self.sequence = 0
@@ -37,19 +38,13 @@ class ZMQTest (BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- def setup_nodes(self):
- # Try to import python3-zmq. Skip this test if the import fails.
- try:
- import zmq
- except ImportError:
- raise SkipTest("python3-zmq module not available.")
-
- # Check that bitcoin has been built with ZMQ enabled.
- config = configparser.ConfigParser()
- config.read_file(open(self.options.configfile))
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_py3_zmq()
+ self.skip_if_no_bitcoind_zmq()
+ self.skip_if_no_wallet()
- if not config["components"].getboolean("ENABLE_ZMQ"):
- raise SkipTest("bitcoind has not been built with zmq enabled.")
+ def setup_nodes(self):
+ import zmq
# Initialize ZMQ context and socket.
# All messages are received in the same socket which means
@@ -68,7 +63,10 @@ class ZMQTest (BitcoinTestFramework):
self.rawblock = ZMQSubscriber(socket, b"rawblock")
self.rawtx = ZMQSubscriber(socket, b"rawtx")
- self.extra_args = [["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], []]
+ self.extra_args = [
+ ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]],
+ [],
+ ]
self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 7cdb24c6a5..8847777ba7 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -35,12 +35,14 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [[
- '-checkmempool',
'-txindex',
'-reindex', # Need reindex for txindex
'-acceptnonstdtxn=0', # Try to mimic main-net
]] * self.num_nodes
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def check_mempool_result(self, result_expected, *args, **kwargs):
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index 5382fe439e..c0918893cd 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool limiting together/eviction with the wallet."""
+from decimal import Decimal
+
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts
class MempoolLimitTest(BitcoinTestFramework):
def set_test_params(self):
@@ -13,6 +15,9 @@ class MempoolLimitTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
txouts = gen_return_txouts()
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 79cf159f43..9336547a6b 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -1,12 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test descendant package tracking code."""
+from decimal import Decimal
+
+from test_framework.messages import COIN
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import COIN
+from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round, sync_blocks, sync_mempools
MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
@@ -16,6 +18,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
# Build a transaction that spends parent_txid:vout
# Return amount sent
def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs):
@@ -32,7 +37,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
return (txid, send_value)
def run_test(self):
- ''' Mine some blocks and have them mature. '''
+ # Mine some blocks and have them mature.
self.nodes[0].generate(101)
utxo = self.nodes[0].listunspent(10)
txid = utxo[0]['txid']
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index 83dffb0521..b4e9d967fd 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool persistence.
@@ -35,17 +35,21 @@ Test is as follows:
node1 can't write to disk.
"""
+from decimal import Decimal
import os
import time
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error, wait_until
class MempoolPersistTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
self.extra_args = [[], ["-persistmempool=0"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
chain_height = self.nodes[0].getblockcount()
assert_equal(chain_height, 200)
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index eabed5d633..123f0b4c28 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool re-org scenarios.
@@ -8,14 +8,17 @@ Test re-org scenarios with a mempool that contains transactions
that spend (directly or indirectly) coinbase transactions.
"""
+from test_framework.blocktools import create_raw_transaction
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error
+
-# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.extra_args = [["-checkmempool"]] * 2
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
alert_filename = None # Set by setup_network
@@ -39,9 +42,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
# and make sure the mempool code behaves correctly.
b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ]
coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
- spend_101_raw = create_tx(self.nodes[0], coinbase_txids[1], node1_address, 49.99)
- spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 49.99)
- spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 49.99)
+ spend_101_raw = create_raw_transaction(self.nodes[0], coinbase_txids[1], node1_address, amount=49.99)
+ spend_102_raw = create_raw_transaction(self.nodes[0], coinbase_txids[2], node0_address, amount=49.99)
+ spend_103_raw = create_raw_transaction(self.nodes[0], coinbase_txids[3], node0_address, amount=49.99)
# Create a transaction which is time-locked to two blocks in the future
timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99})
@@ -57,11 +60,11 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
self.nodes[0].generate(1)
# Time-locked transaction is still too immature to spend
- assert_raises_rpc_error(-26,'non-final', self.nodes[0].sendrawtransaction, timelock_tx)
+ assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, timelock_tx)
# Create 102_1 and 103_1:
- spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98)
- spend_103_1_raw = create_tx(self.nodes[0], spend_103_id, node1_address, 49.98)
+ spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id, node1_address, amount=49.98)
+ spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id, node1_address, amount=49.98)
# Broadcast and mine 103_1:
spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 83e84da4bc..d035ca907a 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -1,17 +1,20 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test resurrection of mined transactions when the blockchain is re-organized."""
+from test_framework.blocktools import create_raw_transaction
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal
+
-# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [["-checkmempool"]]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
node0_address = self.nodes[0].getnewaddress()
@@ -25,16 +28,16 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
# Mine a new block
# ... make sure all the transactions are confirmed again.
- b = [ self.nodes[0].getblockhash(n) for n in range(1, 4) ]
- coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
- spends1_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in coinbase_txids ]
- spends1_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw ]
+ b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]
+ coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
+ spends1_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]
+ spends1_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw]
blocks = []
blocks.extend(self.nodes[0].generate(1))
- spends2_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.98) for txid in spends1_id ]
- spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ]
+ spends2_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.98) for txid in spends1_id]
+ spends2_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw]
blocks.extend(self.nodes[0].generate(1))
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index db0738c08a..854d506f0d 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test spending coinbase transactions.
@@ -13,13 +13,16 @@ but less mature coinbase spends are NOT.
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.blocktools import create_raw_transaction
+from test_framework.util import assert_equal, assert_raises_rpc_error
+
-# Create one-input, one-output, no-fee transaction:
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [["-checkmempool"]]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
chain_height = self.nodes[0].getblockcount()
@@ -29,9 +32,9 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
# Coinbase at height chain_height-100+1 ok in mempool, should
# get mined. Coinbase at height chain_height-100+2 is
# is too immature to spend.
- b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ]
- coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
- spends_raw = [ create_tx(self.nodes[0], txid, node0_address, 49.99) for txid in coinbase_txids ]
+ b = [self.nodes[0].getblockhash(n) for n in range(101, 103)]
+ coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
+ spends_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]
spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index 569bf71933..ff55ea5528 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mining RPCs
@@ -9,16 +9,23 @@
- submitblock"""
import copy
-from binascii import b2a_hex
from decimal import Decimal
from test_framework.blocktools import create_coinbase
-from test_framework.mininode import CBlock
+from test_framework.messages import (
+ CBlock,
+ CBlockHeader,
+)
+from test_framework.mininode import (
+ P2PDataStore,
+)
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ bytes_to_hex_str as b2x,
+)
-def b2x(b):
- return b2a_hex(b).decode('ascii')
def assert_template(node, block, expect, rehash=True):
if rehash:
@@ -34,6 +41,12 @@ class MiningTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
+ def assert_submitblock(block, result_str_1, result_str_2=None):
+ block.solve()
+ result_str_2 = result_str_2 or 'duplicate-invalid'
+ assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize())))
+ assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize())))
+
self.log.info('getmininginfo')
mining_info = node.getmininginfo()
assert_equal(mining_info['blocks'], 200)
@@ -45,7 +58,7 @@ class MiningTest(BitcoinTestFramework):
assert_equal(mining_info['pooledtx'], 0)
# Mine a block to leave initial block download
- node.generate(1)
+ node.generatetoaddress(1, node.get_deterministic_priv_key().address)
tmpl = node.getblocktemplate()
self.log.info("getblocktemplate: Test capability advertised")
assert 'proposal' in tmpl['capabilities']
@@ -86,6 +99,7 @@ class MiningTest(BitcoinTestFramework):
bad_block = copy.deepcopy(block)
bad_block.vtx.append(bad_block.vtx[0])
assert_template(node, bad_block, 'bad-txns-duplicate')
+ assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate')
self.log.info("getblocktemplate: Test invalid transaction")
bad_block = copy.deepcopy(block)
@@ -94,12 +108,14 @@ class MiningTest(BitcoinTestFramework):
bad_tx.rehash()
bad_block.vtx.append(bad_tx)
assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')
+ assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent')
self.log.info("getblocktemplate: Test nonfinal transaction")
bad_block = copy.deepcopy(block)
bad_block.vtx[0].nLockTime = 2 ** 32 - 1
bad_block.vtx[0].rehash()
assert_template(node, bad_block, 'bad-txns-nonfinal')
+ assert_submitblock(bad_block, 'bad-txns-nonfinal')
self.log.info("getblocktemplate: Test bad tx count")
# The tx count is immediately after the block header
@@ -118,18 +134,88 @@ class MiningTest(BitcoinTestFramework):
bad_block = copy.deepcopy(block)
bad_block.hashMerkleRoot += 1
assert_template(node, bad_block, 'bad-txnmrklroot', False)
+ assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot')
self.log.info("getblocktemplate: Test bad timestamps")
bad_block = copy.deepcopy(block)
bad_block.nTime = 2 ** 31 - 1
assert_template(node, bad_block, 'time-too-new')
+ assert_submitblock(bad_block, 'time-too-new', 'time-too-new')
bad_block.nTime = 0
assert_template(node, bad_block, 'time-too-old')
+ assert_submitblock(bad_block, 'time-too-old', 'time-too-old')
self.log.info("getblocktemplate: Test not best block")
bad_block = copy.deepcopy(block)
bad_block.hashPrevBlock = 123
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
+ assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found')
+
+ self.log.info('submitheader tests')
+ assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80))
+ assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78))
+ assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80))
+
+ block.nTime += 1
+ block.solve()
+
+ def chain_tip(b_hash, *, status='headers-only', branchlen=1):
+ return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status}
+
+ assert chain_tip(block.hash) not in node.getchaintips()
+ node.submitheader(hexdata=b2x(block.serialize()))
+ assert chain_tip(block.hash) in node.getchaintips()
+ node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) # Noop
+ assert chain_tip(block.hash) in node.getchaintips()
+
+ bad_block_root = copy.deepcopy(block)
+ bad_block_root.hashMerkleRoot += 2
+ bad_block_root.solve()
+ assert chain_tip(bad_block_root.hash) not in node.getchaintips()
+ node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
+ assert chain_tip(bad_block_root.hash) in node.getchaintips()
+ # Should still reject invalid blocks, even if we have the header:
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot')
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot')
+ assert chain_tip(bad_block_root.hash) in node.getchaintips()
+ # We know the header for this invalid block, so should just return early without error:
+ node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
+ assert chain_tip(bad_block_root.hash) in node.getchaintips()
+
+ bad_block_lock = copy.deepcopy(block)
+ bad_block_lock.vtx[0].nLockTime = 2**32 - 1
+ bad_block_lock.vtx[0].rehash()
+ bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
+ bad_block_lock.solve()
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal')
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid')
+ # Build a "good" block on top of the submitted bad block
+ bad_block2 = copy.deepcopy(block)
+ bad_block2.hashPrevBlock = bad_block_lock.sha256
+ bad_block2.solve()
+ assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
+
+ # Should reject invalid header right away
+ bad_block_time = copy.deepcopy(block)
+ bad_block_time.nTime = 1
+ bad_block_time.solve()
+ assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
+
+ # Should ask for the block from a p2p node, if they announce the header as well:
+ node.add_p2p_connection(P2PDataStore())
+ node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders
+ node.p2p.send_blocks_and_test(blocks=[block], node=node)
+ # Must be active now:
+ assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips()
+
+ # Building a few blocks should give the same results
+ node.generatetoaddress(10, node.get_deterministic_priv_key().address)
+ assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
+ assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
+ node.submitheader(hexdata=b2x(CBlockHeader(block).serialize()))
+ node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
+ assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid
+
if __name__ == '__main__':
MiningTest().main()
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index 252ff4dbff..9a3c15a4a7 100755
--- a/test/functional/mining_getblocktemplate_longpoll.py
+++ b/test/functional/mining_getblocktemplate_longpoll.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test longpolling with getblocktemplate."""
+from decimal import Decimal
+
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import get_rpc_proxy, random_transaction
import threading
@@ -13,8 +15,8 @@ class LongpollThread(threading.Thread):
def __init__(self, node):
threading.Thread.__init__(self)
# query current longpollid
- templat = node.getblocktemplate()
- self.longpollid = templat['longpollid']
+ template = node.getblocktemplate()
+ self.longpollid = template['longpollid']
# create a new connection to the node, we can't use the same
# connection from two threads
self.node = get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir)
@@ -26,14 +28,17 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)
- templat = self.nodes[0].getblocktemplate()
- longpollid = templat['longpollid']
+ template = self.nodes[0].getblocktemplate()
+ longpollid = template['longpollid']
# longpollid should not change between successive invocations if nothing else happens
- templat2 = self.nodes[0].getblocktemplate()
- assert(templat2['longpollid'] == longpollid)
+ template2 = self.nodes[0].getblocktemplate()
+ assert(template2['longpollid'] == longpollid)
# Test 1: test that the longpolling wait if we do nothing
thr = LongpollThread(self.nodes[0])
@@ -68,4 +73,3 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
if __name__ == '__main__':
GetBlockTemplateLPTest().main()
-
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index e16e1e242f..c5ddee56f1 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -1,12 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the prioritisetransaction mining RPC."""
+import time
+
+from test_framework.messages import COIN, MAX_BLOCK_BASE_SIZE
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import COIN, MAX_BLOCK_BASE_SIZE
+from test_framework.util import assert_equal, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts
class PrioritiseTransactionTest(BitcoinTestFramework):
def set_test_params(self):
@@ -14,6 +16,9 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-printpriority=1"], ["-printpriority=1"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Test `prioritisetransaction` required parameters
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction)
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 36cd8f5b09..fafc27d16a 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test compact blocks (BIP 152).
@@ -8,12 +8,15 @@ Version 1 compact blocks are pre-segwit (txids)
Version 2 compact blocks are post-segwit (wtxids)
"""
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from decimal import Decimal
+import random
+
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
+from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_block, msg_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_witness_block, msg_witness_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, NODE_WITNESS, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex
+from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.script import CScript, OP_TRUE, OP_DROP
-
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, get_bip9_status, satoshi_round, sync_blocks, wait_until
# TestP2PConn: A peer we use to send messages to bitcoind, and store responses.
class TestP2PConn(P2PInterface):
@@ -87,7 +90,7 @@ class TestP2PConn(P2PInterface):
This is used when we want to send a message into the node that we expect
will get us disconnected, eg an invalid block."""
self.send_message(message)
- wait_until(lambda: self.state != "connected", timeout=timeout, lock=mininode_lock)
+ wait_until(lambda: not self.is_connected, timeout=timeout, lock=mininode_lock)
class CompactBlocksTest(BitcoinTestFramework):
def set_test_params(self):
@@ -99,6 +102,9 @@ class CompactBlocksTest(BitcoinTestFramework):
self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex", "-deprecatedrpc=addwitnessaddress"]]
self.utxos = []
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def build_block_on_tip(self, node, segwit=False):
height = node.getblockcount()
tip = node.getbestblockhash()
@@ -788,15 +794,11 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
def run_test(self):
- # Setup the p2p connections and start up the network thread.
+ # Setup the p2p connections
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
- self.segwit_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
+ self.segwit_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
self.old_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
- network_thread_start()
-
- self.test_node.wait_for_verack()
-
# We will need UTXOs to construct transactions in later tests.
self.make_utxos()
diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py
index c6067befb2..67f24d6bff 100755
--- a/test/functional/p2p_disconnect_ban.py
+++ b/test/functional/p2p_disconnect_ban.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node disconnect and ban behavior"""
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index c304bbba85..d589519e45 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -1,14 +1,16 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test processing of feefilter messages."""
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from decimal import Decimal
import time
+from test_framework.messages import msg_feefilter
+from test_framework.mininode import mininode_lock, P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import sync_blocks, sync_mempools
def hashToHex(hash):
return format(hash, '064x')
@@ -40,6 +42,9 @@ class FeeFilterTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
node1 = self.nodes[1]
node0 = self.nodes[0]
@@ -47,10 +52,7 @@ class FeeFilterTest(BitcoinTestFramework):
node1.generate(1)
sync_blocks(self.nodes)
- # Setup the p2p connections and start up the network thread.
self.nodes[0].add_p2p_connection(TestP2PConn())
- network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
# Test that invs are received for all txs at feerate of 20 sat/byte
node1.settxfee(Decimal("0.00020000"))
diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py
index 516ce8555b..fab0887197 100755
--- a/test/functional/p2p_fingerprint.py
+++ b/test/functional/p2p_fingerprint.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test various fingerprinting protections.
@@ -11,19 +11,18 @@ the node should pretend that it does not have it to avoid fingerprinting.
import time
from test_framework.blocktools import (create_block, create_coinbase)
+from test_framework.messages import CInv
from test_framework.mininode import (
- CInv,
P2PInterface,
msg_headers,
msg_block,
msg_getdata,
msg_getheaders,
- network_thread_start,
- wait_until,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ wait_until,
)
class P2PFingerprintTest(BitcoinTestFramework):
@@ -77,14 +76,11 @@ class P2PFingerprintTest(BitcoinTestFramework):
def run_test(self):
node0 = self.nodes[0].add_p2p_connection(P2PInterface())
- network_thread_start()
- node0.wait_for_verack()
-
# Set node time to 60 days ago
self.nodes[0].setmocktime(int(time.time()) - 60 * 24 * 60 * 60)
# Generating a chain of 10 blocks
- block_hashes = self.nodes[0].generate(nblocks=10)
+ block_hashes = self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
# Create longer chain starting 2 blocks before current tip
height = len(block_hashes) - 2
@@ -115,7 +111,7 @@ class P2PFingerprintTest(BitcoinTestFramework):
# Longest chain is extended so stale is much older than chain tip
self.nodes[0].setmocktime(0)
- tip = self.nodes[0].generate(nblocks=1)[0]
+ tip = self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0]
assert_equal(self.nodes[0].getblockcount(), 14)
# Send getdata & getheaders to refresh last received getheader message
diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py
index e1f328ba77..0678b1a651 100755
--- a/test/functional/p2p_invalid_block.py
+++ b/test/functional/p2p_invalid_block.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid blocks.
@@ -12,9 +12,9 @@ re-requested.
"""
import copy
-from test_framework.blocktools import create_block, create_coinbase, create_transaction
+from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
from test_framework.messages import COIN
-from test_framework.mininode import network_thread_start, P2PDataStore
+from test_framework.mininode import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -29,9 +29,6 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
node = self.nodes[0] # convenience reference to the node
node.add_p2p_connection(P2PDataStore())
- network_thread_start()
- node.p2p.wait_for_verack()
-
best_block = node.getblock(node.getbestblockhash())
tip = int(node.getbestblockhash(), 16)
height = best_block["height"] + 1
@@ -45,10 +42,10 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
# Save the coinbase for later
block1 = block
tip = block.sha256
- node.p2p.send_blocks_and_test([block1], node, True)
+ node.p2p.send_blocks_and_test([block1], node, success=True)
self.log.info("Mature the block.")
- node.generate(100)
+ node.generatetoaddress(100, node.get_deterministic_priv_key().address)
best_block = node.getblock(node.getbestblockhash())
tip = int(node.getbestblockhash(), 16)
@@ -66,8 +63,8 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
block_time += 1
# b'0x51' is OP_TRUE
- tx1 = create_transaction(block1.vtx[0], 0, b'\x51', 50 * COIN)
- tx2 = create_transaction(tx1, 0, b'\x51', 50 * COIN)
+ tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\x51', amount=50 * COIN)
+ tx2 = create_tx_with_script(tx1, 0, script_sig=b'\x51', amount=50 * COIN)
block2.vtx.extend([tx1, tx2])
block2.hashMerkleRoot = block2.calc_merkle_root()
@@ -82,7 +79,17 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
assert_equal(orig_hash, block2.rehash())
assert(block2_orig.vtx != block2.vtx)
- node.p2p.send_blocks_and_test([block2], node, False, False, 16, b'bad-txns-duplicate')
+ node.p2p.send_blocks_and_test([block2], node, success=False, request_block=False, reject_reason='bad-txns-duplicate')
+
+ # Check transactions for duplicate inputs
+ self.log.info("Test duplicate input block.")
+
+ block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0])
+ block2_orig.vtx[2].rehash()
+ block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root()
+ block2_orig.rehash()
+ block2_orig.solve()
+ node.p2p.send_blocks_and_test([block2_orig], node, success=False, request_block=False, reject_reason='bad-txns-inputs-duplicate')
self.log.info("Test very broken block.")
@@ -95,7 +102,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
block3.rehash()
block3.solve()
- node.p2p.send_blocks_and_test([block3], node, False, False, 16, b'bad-cb-amount')
+ node.p2p.send_blocks_and_test([block3], node, success=False, request_block=False, reject_reason='bad-cb-amount')
if __name__ == '__main__':
InvalidBlockRequestTest().main()
diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py
new file mode 100755
index 0000000000..c8c752d1f7
--- /dev/null
+++ b/test/functional/p2p_invalid_locator.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test node responses to invalid locators.
+"""
+
+from test_framework.messages import msg_getheaders, msg_getblocks, MAX_LOCATOR_SZ
+from test_framework.mininode import P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class InvalidLocatorTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
+ def run_test(self):
+ node = self.nodes[0] # convenience reference to the node
+ node.generatetoaddress(1, node.get_deterministic_priv_key().address) # Get node out of IBD
+
+ self.log.info('Test max locator size')
+ block_count = node.getblockcount()
+ for msg in [msg_getheaders(), msg_getblocks()]:
+ self.log.info('Wait for disconnect when sending {} hashes in locator'.format(MAX_LOCATOR_SZ + 1))
+ node.add_p2p_connection(P2PInterface())
+ msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ + 1), -1)]
+ node.p2p.send_message(msg)
+ node.p2p.wait_for_disconnect()
+ node.disconnect_p2ps()
+
+ self.log.info('Wait for response when sending {} hashes in locator'.format(MAX_LOCATOR_SZ))
+ node.add_p2p_connection(P2PInterface())
+ msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ), -1)]
+ node.p2p.send_message(msg)
+ if type(msg) == msg_getheaders:
+ node.p2p.wait_for_header(int(node.getbestblockhash(), 16))
+ else:
+ node.p2p.wait_for_block(int(node.getbestblockhash(), 16))
+
+
+if __name__ == '__main__':
+ InvalidLocatorTest().main()
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 3fed872ccc..58e129b57d 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid transactions.
In this test we connect to one node over p2p, and test tx requests."""
-from test_framework.blocktools import create_block, create_coinbase, create_transaction
+from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
from test_framework.messages import (
COIN,
COutPoint,
@@ -13,7 +13,7 @@ from test_framework.messages import (
CTxIn,
CTxOut,
)
-from test_framework.mininode import network_thread_start, P2PDataStore, network_thread_join
+from test_framework.mininode import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -32,8 +32,6 @@ class InvalidTxRequestTest(BitcoinTestFramework):
Helper to connect and wait for version handshake."""
for _ in range(num_connections):
self.nodes[0].add_p2p_connection(P2PDataStore())
- network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
def reconnect_p2p(self, **kwargs):
"""Tear down and bootstrap the P2P connection to the node.
@@ -41,7 +39,6 @@ class InvalidTxRequestTest(BitcoinTestFramework):
The node gets disconnected several times in this test. This helper
method reconnects the p2p and restarts the network thread."""
self.nodes[0].disconnect_p2ps()
- network_thread_join()
self.bootstrap_p2p(**kwargs)
def run_test(self):
@@ -64,13 +61,13 @@ class InvalidTxRequestTest(BitcoinTestFramework):
node.p2p.send_blocks_and_test([block], node, success=True)
self.log.info("Mature the block.")
- self.nodes[0].generate(100)
+ self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address)
# b'\x64' is OP_NOTIF
# Transaction will be rejected with code 16 (REJECT_INVALID)
# and we get disconnected immediately
self.log.info('Test a transaction that is rejected')
- tx1 = create_transaction(block1.vtx[0], 0, b'\x64' * 35, 50 * COIN - 12000)
+ tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\x64' * 35, amount=50 * COIN - 12000)
node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
# Make two p2p connections to provide the node with orphans
@@ -79,7 +76,7 @@ class InvalidTxRequestTest(BitcoinTestFramework):
self.reconnect_p2p(num_connections=2)
self.log.info('Test orphan transaction handling ... ')
- # Create a root transaction that we withhold until all dependend transactions
+ # Create a root transaction that we withhold until all dependent transactions
# are sent out and in the orphan cache
SCRIPT_PUB_KEY_OP_TRUE = b'\x51\x75' * 15 + b'\x51'
tx_withhold = CTransaction()
@@ -119,7 +116,8 @@ class InvalidTxRequestTest(BitcoinTestFramework):
assert_equal(2, len(node.getpeerinfo())) # p2ps[1] is still connected
self.log.info('Send the withhold tx ... ')
- node.p2p.send_txs_and_test([tx_withhold], node, success=True)
+ with node.assert_debug_log(expected_msgs=["bad-txns-in-belowout"]):
+ node.p2p.send_txs_and_test([tx_withhold], node, success=True)
# Transactions that should end up in the mempool
expected_mempool = {
@@ -137,13 +135,6 @@ class InvalidTxRequestTest(BitcoinTestFramework):
wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12) # p2ps[1] is no longer connected
assert_equal(expected_mempool, set(node.getrawmempool()))
- # restart node with sending BIP61 messages disabled, check that it disconnects without sending the reject message
- self.log.info('Test a transaction that is rejected, with BIP61 disabled')
- self.restart_node(0, ['-enablebip61=0','-persistmempool=0'])
- self.reconnect_p2p(num_connections=1)
- node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
- # send_txs_and_test will have waited for disconnect, so we can safely check that no reject has been received
- assert_equal(node.p2p.reject_code_received, None)
if __name__ == '__main__':
InvalidTxRequestTest().main()
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 198dcc1490..336d34a81d 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test message sending before handshake completion.
@@ -8,15 +8,14 @@ A node should never send anything other than VERSION/VERACK/REJECT until it's
received a VERACK.
This test connects to a node and sends it a few messages, trying to entice it
-into sending us something it shouldn't.
+into sending us something it shouldn't."""
-Also test that nodes that send unsupported service bits to bitcoind are disconnected
-and don't receive a VERACK. Unsupported service bits are currently 1 << 5 and
-1 << 7 (until August 1st 2018)."""
+import time
-from test_framework.mininode import *
+from test_framework.messages import msg_getaddr, msg_ping, msg_verack
+from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import wait_until
banscore = 10
@@ -92,62 +91,36 @@ class CNodeNoVerackIdle(CLazyNode):
class P2PLeakTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-banscore='+str(banscore)]]
+ self.extra_args = [['-banscore=' + str(banscore)]]
def run_test(self):
- self.nodes[0].setmocktime(1501545600) # August 1st 2017
-
- no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False)
- no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False)
+ no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False)
+ no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False)
no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle())
- unsupported_service_bit5_node = self.nodes[0].add_p2p_connection(CLazyNode(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)
- unsupported_service_bit7_node = self.nodes[0].add_p2p_connection(CLazyNode(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)
-
- network_thread_start()
wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)
wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)
wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
- wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10, lock=mininode_lock)
- wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10, lock=mininode_lock)
# Mine a block and make sure that it's not sent to the connected nodes
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
#Give the node enough time to possibly leak out a message
time.sleep(5)
#This node should have been banned
- assert no_version_bannode.state != "connected"
-
- # These nodes should have been disconnected
- assert unsupported_service_bit5_node.state != "connected"
- assert unsupported_service_bit7_node.state != "connected"
+ assert not no_version_bannode.is_connected
self.nodes[0].disconnect_p2ps()
- # Wait until all connections are closed and the network thread has terminated
+ # Wait until all connections are closed
wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0)
- network_thread_join()
# Make sure no unexpected messages came in
assert(no_version_bannode.unexpected_msg == False)
assert(no_version_idlenode.unexpected_msg == False)
assert(no_verack_idlenode.unexpected_msg == False)
- assert not unsupported_service_bit5_node.unexpected_msg
- assert not unsupported_service_bit7_node.unexpected_msg
-
- self.log.info("Service bits 5 and 7 are allowed after August 1st 2018")
- self.nodes[0].setmocktime(1533168000) # August 2nd 2018
-
- allowed_service_bit5_node = self.nodes[0].add_p2p_connection(P2PInterface(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)
- allowed_service_bit7_node = self.nodes[0].add_p2p_connection(P2PInterface(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)
-
- # Network thread stopped when all previous P2PInterfaces disconnected. Restart it
- network_thread_start()
- wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock)
- wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock)
if __name__ == '__main__':
P2PLeakTest().main()
diff --git a/test/functional/p2p_mempool.py b/test/functional/p2p_mempool.py
index e54843b26f..a8fcb181e6 100755
--- a/test/functional/p2p_mempool.py
+++ b/test/functional/p2p_mempool.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test p2p mempool message.
@@ -8,9 +8,10 @@ Test that nodes are disconnected if they send mempool messages when bloom
filters are not enabled.
"""
-from test_framework.mininode import *
+from test_framework.messages import msg_mempool
+from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal
class P2PMempoolTests(BitcoinTestFramework):
def set_test_params(self):
@@ -21,8 +22,6 @@ class P2PMempoolTests(BitcoinTestFramework):
def run_test(self):
# Add a p2p connection
self.nodes[0].add_p2p_connection(P2PInterface())
- network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
#request mempool
self.nodes[0].p2p.send_message(msg_mempool())
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index 301d8c181a..ec3d336dc1 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests NODE_NETWORK_LIMITED.
@@ -8,10 +8,10 @@ Tests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correc
and that it responds to getdata requests for blocks correctly:
- send a block within 288 + 2 of the tip
- disconnect peers who request blocks older than that."""
-from test_framework.messages import CInv, msg_getdata, msg_verack
-from test_framework.mininode import NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS, P2PInterface, wait_until, mininode_lock, network_thread_start, network_thread_join
+from test_framework.messages import CInv, msg_getdata, msg_verack, NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS
+from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks
+from test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks, wait_until
class P2PIgnoreInv(P2PInterface):
firstAddrnServices = 0
@@ -48,8 +48,6 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
- network_thread_start()
- node.wait_for_verack()
expected_services = NODE_BLOOM | NODE_WITNESS | NODE_NETWORK_LIMITED
@@ -61,7 +59,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.")
connect_nodes_bi(self.nodes, 0, 1)
- blocks = self.nodes[1].generate(292)
+ blocks = self.nodes[1].generatetoaddress(292, self.nodes[1].get_deterministic_priv_key().address)
sync_blocks([self.nodes[0], self.nodes[1]])
self.log.info("Make sure we can max retrieve block at tip-288.")
@@ -74,10 +72,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.log.info("Check local address relay, do a fresh connection.")
self.nodes[0].disconnect_p2ps()
- network_thread_join()
node1 = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
- network_thread_start()
- node1.wait_for_verack()
node1.send_message(msg_verack())
node1.wait_for_addr()
@@ -94,7 +89,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
except:
pass
- # node2 must remain at heigh 0
+ # node2 must remain at height 0
assert_equal(self.nodes[2].getblockheader(self.nodes[2].getbestblockhash())['height'], 0)
# now connect also to node 1 (non pruned)
@@ -107,7 +102,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.disconnect_all()
# mine 10 blocks on node 0 (pruned node)
- self.nodes[0].generate(10)
+ self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
# connect node1 (non pruned) with node0 (pruned) and check if the can sync
connect_nodes_bi(self.nodes, 0, 1)
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index e80a764477..de12ab1ed6 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1,19 +1,87 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test segwit transactions and blocks on P2P network."""
+from binascii import hexlify
+import math
+import random
+import struct
+import time
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.script import *
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
from test_framework.key import CECKey, CPubKey
-import math
-import time
-import random
-from binascii import hexlify
+from test_framework.messages import (
+ BIP125_SEQUENCE_NUMBER,
+ CBlock,
+ CBlockHeader,
+ CInv,
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxInWitness,
+ CTxOut,
+ CTxWitness,
+ MAX_BLOCK_BASE_SIZE,
+ MSG_WITNESS_FLAG,
+ NODE_NETWORK,
+ NODE_WITNESS,
+ msg_block,
+ msg_getdata,
+ msg_headers,
+ msg_inv,
+ msg_tx,
+ msg_witness_block,
+ msg_witness_tx,
+ ser_uint256,
+ ser_vector,
+ sha256,
+ uint256_from_str,
+)
+from test_framework.mininode import (
+ P2PInterface,
+ mininode_lock,
+)
+from test_framework.script import (
+ CScript,
+ CScriptNum,
+ CScriptOp,
+ MAX_SCRIPT_ELEMENT_SIZE,
+ OP_0,
+ OP_1,
+ OP_16,
+ OP_2DROP,
+ OP_CHECKMULTISIG,
+ OP_CHECKSIG,
+ OP_DROP,
+ OP_DUP,
+ OP_ELSE,
+ OP_ENDIF,
+ OP_EQUAL,
+ OP_EQUALVERIFY,
+ OP_HASH160,
+ OP_IF,
+ OP_RETURN,
+ OP_TRUE,
+ SIGHASH_ALL,
+ SIGHASH_ANYONECANPAY,
+ SIGHASH_NONE,
+ SIGHASH_SINGLE,
+ SegwitVersion1SignatureHash,
+ SignatureHash,
+ hash160,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ connect_nodes,
+ disconnect_nodes,
+ get_bip9_status,
+ hex_str_to_bytes,
+ sync_blocks,
+ sync_mempools,
+)
# The versionbit bit used to signal activation of SegWit
VB_WITNESS_BIT = 1
@@ -22,47 +90,56 @@ VB_TOP_BITS = 0x20000000
MAX_SIGOP_COST = 80000
+class UTXO():
+ """Used to keep track of anyone-can-spend outputs that we can use in the tests."""
+ def __init__(self, sha256, n, value):
+ self.sha256 = sha256
+ self.n = n
+ self.nValue = value
+
+def get_p2pkh_script(pubkeyhash):
+ """Get the script associated with a P2PKH."""
+ return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
+
+def sign_p2pk_witness_input(script, tx_to, in_idx, hashtype, value, key):
+ """Add signature for a P2PK witness program."""
+ tx_hash = SegwitVersion1SignatureHash(script, tx_to, in_idx, hashtype, value)
+ signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
+ tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script]
+ tx_to.rehash()
-# Calculate the virtual size of a witness block:
-# (base + witness/4)
def get_virtual_size(witness_block):
+ """Calculate the virtual size of a witness block.
+
+ Virtual size is base + witness/4."""
base_size = len(witness_block.serialize(with_witness=False))
total_size = len(witness_block.serialize(with_witness=True))
# the "+3" is so we round up
- vsize = int((3*base_size + total_size + 3)/4)
+ vsize = int((3 * base_size + total_size + 3) / 4)
return vsize
-def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=None):
+def test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=None):
"""Send a transaction to the node and check that it's accepted to the mempool
- Submit the transaction over the p2p interface
- use the getrawmempool rpc to check for acceptance."""
- tx_message = msg_tx(tx)
- if with_witness:
- tx_message = msg_witness_tx(tx)
- p2p.send_message(tx_message)
- p2p.sync_with_ping()
- assert_equal(tx.hash in rpc.getrawmempool(), accepted)
- if (reason != None and not accepted):
- # Check the rejection reason as well.
- with mininode_lock:
- assert_equal(p2p.last_message["reject"].reason, reason)
+ reason = [reason] if reason else []
+ with node.assert_debug_log(expected_msgs=reason):
+ p2p.send_message(msg_witness_tx(tx) if with_witness else msg_tx(tx))
+ p2p.sync_with_ping()
+ assert_equal(tx.hash in node.getrawmempool(), accepted)
-def test_witness_block(rpc, p2p, block, accepted, with_witness=True, reason=None):
+def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=None):
"""Send a block to the node and check that it's accepted
- Submit the block over the p2p interface
- use the getbestblockhash rpc to check for acceptance."""
- if with_witness:
- p2p.send_message(msg_witness_block(block))
- else:
- p2p.send_message(msg_block(block))
- p2p.sync_with_ping()
- assert_equal(rpc.getbestblockhash() == block.hash, accepted)
- if (reason != None and not accepted):
- # Check the rejection reason as well.
- with mininode_lock:
- assert_equal(p2p.last_message["reject"].reason, reason)
+ reason = [reason] if reason else []
+ with node.assert_debug_log(expected_msgs=reason):
+ p2p.send_message(msg_witness_block(block) if with_witness else msg_block(block))
+ p2p.sync_with_ping()
+ assert_equal(node.getbestblockhash() == block.hash, accepted)
+
class TestP2PConn(P2PInterface):
def __init__(self):
@@ -88,7 +165,7 @@ class TestP2PConn(P2PInterface):
self.last_message.pop("getdata", None)
self.last_message.pop("getheaders", None)
msg = msg_headers()
- msg.headers = [ CBlockHeader(block) ]
+ msg.headers = [CBlockHeader(block)]
if use_header:
self.send_message(msg)
else:
@@ -104,25 +181,6 @@ class TestP2PConn(P2PInterface):
self.wait_for_block(blockhash, timeout)
return self.last_message["block"].block
-# Used to keep track of anyone-can-spend outputs that we can use in the tests
-class UTXO():
- def __init__(self, sha256, n, nValue):
- self.sha256 = sha256
- self.n = n
- self.nValue = nValue
-
-# Helper for getting the script associated with a P2PKH
-def GetP2PKHScript(pubkeyhash):
- return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
-
-# Add signature for a P2PK witness program.
-def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
- tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
- signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
- txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
- txTo.rehash()
-
-
class SegWitTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
@@ -130,49 +188,122 @@ class SegWitTest(BitcoinTestFramework):
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [["-whitelist=127.0.0.1", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)
self.sync_all()
- ''' Helpers '''
- # Build a block on top of node0's tip.
- def build_next_block(self, nVersion=4):
+ # Helper functions
+
+ def build_next_block(self, version=4):
+ """Build a block on top of node0's tip."""
tip = self.nodes[0].getbestblockhash()
height = self.nodes[0].getblockcount() + 1
block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1
block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.nVersion = nVersion
+ block.version = version
block.rehash()
return block
- # Adds list of transactions to block, adds witness commitment, then solves.
def update_witness_block_with_transactions(self, block, tx_list, nonce=0):
+ """Add list of transactions to block, adds witness commitment, then solves."""
block.vtx.extend(tx_list)
add_witness_commitment(block, nonce)
block.solve()
- return
- ''' Individual tests '''
- def test_witness_services(self):
- self.log.info("Verifying NODE_WITNESS service bit")
- assert((self.test_node.nServices & NODE_WITNESS) != 0)
+ def run_test(self):
+ # Setup the p2p connections
+ # self.test_node sets NODE_WITNESS|NODE_NETWORK
+ self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
+ # self.old_node sets only NODE_NETWORK
+ self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
+ # self.std_node is for testing node1 (fRequireStandard=true)
+ self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
+
+ assert self.test_node.nServices & NODE_WITNESS != 0
+
+ # Keep a place to store utxo's that can be used in later tests
+ self.utxo = []
+
+ # Segwit status 'defined'
+ self.segwit_status = 'defined'
+
+ self.test_non_witness_transaction()
+ self.test_unnecessary_witness_before_segwit_activation()
+ self.test_v0_outputs_arent_spendable()
+ self.test_block_relay()
+ self.advance_to_segwit_started()
+
+ # Segwit status 'started'
+
+ self.test_getblocktemplate_before_lockin()
+ self.advance_to_segwit_lockin()
+
+ # Segwit status 'locked_in'
+ self.test_unnecessary_witness_before_segwit_activation()
+ self.test_witness_tx_relay_before_segwit_activation()
+ self.test_block_relay()
+ self.test_standardness_v0()
+ self.advance_to_segwit_active()
- # See if sending a regular transaction works, and create a utxo
- # to use in later tests.
+ # Segwit status 'active'
+
+ self.test_p2sh_witness()
+ self.test_witness_commitments()
+ self.test_block_malleability()
+ self.test_witness_block_size()
+ self.test_submit_block()
+ self.test_extra_witness_data()
+ self.test_max_witness_push_length()
+ self.test_max_witness_program_length()
+ self.test_witness_input_length()
+ self.test_block_relay()
+ self.test_tx_relay_after_segwit_activation()
+ self.test_standardness_v0()
+ self.test_segwit_versions()
+ self.test_premature_coinbase_witness_spend()
+ self.test_uncompressed_pubkey()
+ self.test_signature_version_1()
+ self.test_non_standard_witness_blinding()
+ self.test_non_standard_witness()
+ self.test_upgrade_after_activation()
+ self.test_witness_sigops()
+
+ # Individual tests
+
+ def subtest(func): # noqa: N805
+ """Wraps the subtests for logging and state assertions."""
+ def func_wrapper(self, *args, **kwargs):
+ self.log.info("Subtest: {} (Segwit status = {})".format(func.__name__, self.segwit_status))
+ # Assert segwit status is as expected
+ assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
+ func(self, *args, **kwargs)
+ # Each subtest should leave some utxos for the next subtest
+ assert self.utxo
+ sync_blocks(self.nodes)
+ # Assert segwit status is as expected at end of subtest
+ assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
+
+ return func_wrapper
+
+ @subtest
def test_non_witness_transaction(self):
+ """See if sending a regular transaction works, and create a utxo to use in later tests."""
# Mine a block with an anyone-can-spend coinbase,
# let it mature, then try to spend it.
- self.log.info("Testing non-witness transaction")
- block = self.build_next_block(nVersion=1)
+
+ block = self.build_next_block(version=1)
block.solve()
self.test_node.send_message(msg_block(block))
- self.test_node.sync_with_ping() # make sure the block was processed
+ self.test_node.sync_with_ping() # make sure the block was processed
txid = block.vtx[0].sha256
- self.nodes[0].generate(99) # let the block mature
+ self.nodes[0].generate(99) # let the block mature
# Create a transaction that spends the coinbase
tx = CTransaction()
@@ -185,24 +316,19 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(msg_tx(tx).serialize(), msg_witness_tx(tx).serialize())
self.test_node.send_message(msg_witness_tx(tx))
- self.test_node.sync_with_ping() # make sure the tx was processed
+ self.test_node.sync_with_ping() # make sure the tx was processed
assert(tx.hash in self.nodes[0].getrawmempool())
# Save this transaction for later
- self.utxo.append(UTXO(tx.sha256, 0, 49*100000000))
+ self.utxo.append(UTXO(tx.sha256, 0, 49 * 100000000))
self.nodes[0].generate(1)
-
- # Verify that blocks with witnesses are rejected before activation.
+ @subtest
def test_unnecessary_witness_before_segwit_activation(self):
- self.log.info("Testing behavior of unnecessary witnesses")
- # For now, rely on earlier tests to have created at least one utxo for
- # us to use
- assert(len(self.utxo) > 0)
- assert(get_bip9_status(self.nodes[0], 'segwit')['status'] != 'active')
+ """Verify that blocks with witnesses are rejected before activation."""
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, CScript([OP_TRUE])))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE])))
tx.wit.vtxinwit.append(CTxInWitness())
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)])]
@@ -212,15 +338,11 @@ class SegWitTest(BitcoinTestFramework):
assert(tx.sha256 != tx.calc_sha256(with_witness=True))
# Construct a segwit-signaling block that includes the transaction.
- block = self.build_next_block(nVersion=(VB_TOP_BITS|(1 << VB_WITNESS_BIT)))
+ block = self.build_next_block(version=(VB_TOP_BITS | (1 << VB_WITNESS_BIT)))
self.update_witness_block_with_transactions(block, [tx])
# Sending witness data before activation is not allowed (anti-spam
# rule).
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
- # TODO: fix synchronization so we can test reject reason
- # Right now, bitcoind delays sending reject messages for blocks
- # until the future, making synchronization here difficult.
- #assert_equal(self.test_node.last_message["reject"].reason, "unexpected-witness")
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='unexpected-witness')
# But it should not be permanently marked bad...
# Resend without witness information.
@@ -228,83 +350,136 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.sync_with_ping()
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
- sync_blocks(self.nodes)
+ # Update our utxo list; we spent the first entry.
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
- # Create a p2sh output -- this is so we can pass the standardness
- # rules (an anyone-can-spend OP_TRUE would be rejected, if not wrapped
- # in P2SH).
- p2sh_program = CScript([OP_TRUE])
- p2sh_pubkey = hash160(p2sh_program)
- scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+ @subtest
+ def test_block_relay(self):
+ """Test that block requests to NODE_WITNESS peer are with MSG_WITNESS_FLAG.
- # Now check that unnecessary witnesses can't be used to blind a node
- # to a transaction, eg by violating standardness checks.
- tx2 = CTransaction()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptPubKey))
- tx2.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, False, True)
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ This is true regardless of segwit activation.
+ Also test that we don't ask for blocks from unupgraded peers."""
- # We'll add an unnecessary witness to this transaction that would cause
- # it to be non-standard, to test that violating policy with a witness before
- # segwit activation doesn't blind a node to a transaction. Transactions
- # rejected for having a witness before segwit activation shouldn't be added
- # to the rejection cache.
- tx3 = CTransaction()
- tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptPubKey))
- tx3.wit.vtxinwit.append(CTxInWitness())
- tx3.wit.vtxinwit[0].scriptWitness.stack = [b'a'*400000]
- tx3.rehash()
- # Note that this should be rejected for the premature witness reason,
- # rather than a policy check, since segwit hasn't activated yet.
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, True, False, b'no-witness-yet')
+ blocktype = 2 | MSG_WITNESS_FLAG
- # If we send without witness, it should be accepted.
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, False, True)
+ # test_node has set NODE_WITNESS, so all getdata requests should be for
+ # witness blocks.
+ # Test announcing a block via inv results in a getdata, and that
+ # announcing a version 4 or random VB block with a header results in a getdata
+ block1 = self.build_next_block()
+ block1.solve()
- # Now create a new anyone-can-spend utxo for the next test.
- tx4 = CTransaction()
- tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), CScript([p2sh_program])))
- tx4.vout.append(CTxOut(tx3.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
- tx4.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, False, True)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx4, False, True)
+ self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ test_witness_block(self.nodes[0], self.test_node, block1, True)
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ block2 = self.build_next_block(version=4)
+ block2.solve()
- # Update our utxo list; we spent the first entry.
- self.utxo.pop(0)
- self.utxo.append(UTXO(tx4.sha256, 0, tx4.vout[0].nValue))
-
- # ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
- # backdated so that it applies to all blocks, going back to the genesis
- # block.
- #
- # Consequently, version 0 witness outputs are never spendable without
- # witness, and so can't be spent before segwit activation (the point at which
- # blocks are permitted to contain witnesses).
+ self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ test_witness_block(self.nodes[0], self.test_node, block2, True)
+
+ block3 = self.build_next_block(version=(VB_TOP_BITS | (1 << 15)))
+ block3.solve()
+ self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ test_witness_block(self.nodes[0], self.test_node, block3, True)
+
+ # Check that we can getdata for witness blocks or regular blocks,
+ # and the right thing happens.
+ if self.segwit_status != 'active':
+ # Before activation, we should be able to request old blocks with
+ # or without witness, and they should be the same.
+ chain_height = self.nodes[0].getblockcount()
+ # Pick 10 random blocks on main chain, and verify that getdata's
+ # for MSG_BLOCK, MSG_WITNESS_BLOCK, and rpc getblock() are equal.
+ all_heights = list(range(chain_height + 1))
+ random.shuffle(all_heights)
+ all_heights = all_heights[0:10]
+ for height in all_heights:
+ block_hash = self.nodes[0].getblockhash(height)
+ rpc_block = self.nodes[0].getblock(block_hash, False)
+ block_hash = int(block_hash, 16)
+ block = self.test_node.request_block(block_hash, 2)
+ wit_block = self.test_node.request_block(block_hash, 2 | MSG_WITNESS_FLAG)
+ assert_equal(block.serialize(True), wit_block.serialize(True))
+ assert_equal(block.serialize(), hex_str_to_bytes(rpc_block))
+ else:
+ # After activation, witness blocks and non-witness blocks should
+ # be different. Verify rpc getblock() returns witness blocks, while
+ # getdata respects the requested type.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [])
+ # This gives us a witness commitment.
+ assert(len(block.vtx[0].wit.vtxinwit) == 1)
+ assert(len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+ # Now try to retrieve it...
+ rpc_block = self.nodes[0].getblock(block.hash, False)
+ non_wit_block = self.test_node.request_block(block.sha256, 2)
+ wit_block = self.test_node.request_block(block.sha256, 2 | MSG_WITNESS_FLAG)
+ assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block))
+ assert_equal(wit_block.serialize(False), non_wit_block.serialize())
+ assert_equal(wit_block.serialize(True), block.serialize(True))
+
+ # Test size, vsize, weight
+ rpc_details = self.nodes[0].getblock(block.hash, True)
+ assert_equal(rpc_details["size"], len(block.serialize(True)))
+ assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
+ weight = 3 * len(block.serialize(False)) + len(block.serialize(True))
+ assert_equal(rpc_details["weight"], weight)
+
+ # Upgraded node should not ask for blocks from unupgraded
+ block4 = self.build_next_block(version=4)
+ block4.solve()
+ self.old_node.getdataset = set()
+
+ # Blocks can be requested via direct-fetch (immediately upon processing the announcement)
+ # or via parallel download (with an indeterminate delay from processing the announcement)
+ # so to test that a block is NOT requested, we could guess a time period to sleep for,
+ # and then check. We can avoid the sleep() by taking advantage of transaction getdata's
+ # being processed after block getdata's, and announce a transaction as well,
+ # and then check to see if that particular getdata has been received.
+ # Since 0.14, inv's will only be responded to with a getheaders, so send a header
+ # to announce this block.
+ msg = msg_headers()
+ msg.headers = [CBlockHeader(block4)]
+ self.old_node.send_message(msg)
+ self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
+ assert(block4.sha256 not in self.old_node.getdataset)
+
+ @subtest
def test_v0_outputs_arent_spendable(self):
- self.log.info("Testing that v0 witness program outputs aren't spendable before activation")
+ """Test that v0 outputs aren't spendable before segwit activation.
+
+ ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
+ backdated so that it applies to all blocks, going back to the genesis
+ block.
+
+ Consequently, version 0 witness outputs are never spendable without
+ witness, and so can't be spent before segwit activation (the point at which
+ blocks are permitted to contain witnesses)."""
- assert len(self.utxo), "self.utxo is empty"
+ # node2 doesn't need to be connected for this test.
+ # (If it's connected, node0 may propagate an invalid block to it over
+ # compact blocks and the nodes would have inconsistent tips.)
+ disconnect_nodes(self.nodes[0], 2)
# Create two outputs, a p2wsh and p2sh-p2wsh
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
- p2sh_pubkey = hash160(scriptPubKey)
- p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+ p2sh_pubkey = hash160(script_pubkey)
+ p2sh_script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
value = self.utxo[0].nValue // 3
tx = CTransaction()
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b'')]
- tx.vout = [CTxOut(value, scriptPubKey), CTxOut(value, p2sh_scriptPubKey)]
+ tx.vout = [CTxOut(value, script_pubkey), CTxOut(value, p2sh_script_pubkey)]
tx.vout.append(CTxOut(value, CScript([OP_TRUE])))
tx.rehash()
txid = tx.sha256
@@ -314,7 +489,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx])
# Verify that segwit isn't activated. A block serialized with witness
# should be rejected prior to activation.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason = b'unexpected-witness')
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason='unexpected-witness')
# Now send the block without witness. It should be accepted
test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)
@@ -327,7 +502,7 @@ class SegWitTest(BitcoinTestFramework):
p2wsh_tx.rehash()
p2sh_p2wsh_tx = CTransaction()
- p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([scriptPubKey]))]
+ p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([script_pubkey]))]
p2sh_p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
p2sh_p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
p2sh_p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
@@ -340,7 +515,7 @@ class SegWitTest(BitcoinTestFramework):
# When the block is serialized with a witness, the block will be rejected because witness
# data isn't allowed in blocks that don't commit to witness data.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason='unexpected-witness')
# When the block is serialized without witness, validation fails because the transaction is
# invalid (transactions are always validated with SCRIPT_VERIFY_WITNESS so a segwit v0 transaction
@@ -352,50 +527,282 @@ class SegWitTest(BitcoinTestFramework):
# TODO: support multiple acceptable reject reasons.
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
+ connect_nodes(self.nodes[0], 2)
+
self.utxo.pop(0)
self.utxo.append(UTXO(txid, 2, value))
- # Mine enough blocks for segwit's vb state to be 'started'.
+ @subtest
def advance_to_segwit_started(self):
+ """Mine enough blocks for segwit's vb state to be 'started'."""
height = self.nodes[0].getblockcount()
# Will need to rewrite the tests here if we are past the first period
assert(height < VB_PERIOD - 1)
- # Genesis block is 'defined'.
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'defined')
# Advance to end of period, status should now be 'started'
- self.nodes[0].generate(VB_PERIOD-height-1)
+ self.nodes[0].generate(VB_PERIOD - height - 1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
+ self.segwit_status = 'started'
+
+ @subtest
+ def test_getblocktemplate_before_lockin(self):
+ # Node0 is segwit aware, node2 is not.
+ for node in [self.nodes[0], self.nodes[2]]:
+ gbt_results = node.getblocktemplate()
+ block_version = gbt_results['version']
+ # If we're not indicating segwit support, we will still be
+ # signalling for segwit activation.
+ assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0])
+ # If we don't specify the segwit rule, then we won't get a default
+ # commitment.
+ assert('default_witness_commitment' not in gbt_results)
+
+ # Workaround:
+ # Can either change the tip, or change the mempool and wait 5 seconds
+ # to trigger a recomputation of getblocktemplate.
+ txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
+ # Using mocktime lets us avoid sleep()
+ sync_mempools(self.nodes)
+ self.nodes[0].setmocktime(int(time.time()) + 10)
+ self.nodes[2].setmocktime(int(time.time()) + 10)
+
+ for node in [self.nodes[0], self.nodes[2]]:
+ gbt_results = node.getblocktemplate({"rules": ["segwit"]})
+ block_version = gbt_results['version']
+ if node == self.nodes[2]:
+ # If this is a non-segwit node, we should still not get a witness
+ # commitment, nor a version bit signalling segwit.
+ assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
+ assert('default_witness_commitment' not in gbt_results)
+ else:
+ # For segwit-aware nodes, check the version bit and the witness
+ # commitment are correct.
+ assert(block_version & (1 << VB_WITNESS_BIT) != 0)
+ assert('default_witness_commitment' in gbt_results)
+ witness_commitment = gbt_results['default_witness_commitment']
+
+ # Check that default_witness_commitment is present.
+ witness_root = CBlock.get_merkle_root([ser_uint256(0),
+ ser_uint256(txid)])
+ script = get_witness_script(witness_root, 0)
+ assert_equal(witness_commitment, bytes_to_hex_str(script))
- # Mine enough blocks to lock in segwit, but don't activate.
- # TODO: we could verify that lockin only happens at the right threshold of
- # signalling blocks, rather than just at the right period boundary.
+ # undo mocktime
+ self.nodes[0].setmocktime(0)
+ self.nodes[2].setmocktime(0)
+
+ @subtest
def advance_to_segwit_lockin(self):
+ """Mine enough blocks to lock in segwit, but don't activate."""
height = self.nodes[0].getblockcount()
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
# Advance to end of period, and verify lock-in happens at the end
- self.nodes[0].generate(VB_PERIOD-1)
+ self.nodes[0].generate(VB_PERIOD - 1)
height = self.nodes[0].getblockcount()
assert((height % VB_PERIOD) == VB_PERIOD - 2)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
self.nodes[0].generate(1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
+ self.segwit_status = 'locked_in'
+
+ @subtest
+ def test_witness_tx_relay_before_segwit_activation(self):
+ # Generate a transaction that doesn't require a witness, but send it
+ # with a witness. Should be rejected for premature-witness, but should
+ # not be added to recently rejected list.
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
+ tx.wit.vtxinwit.append(CTxInWitness())
+ tx.wit.vtxinwit[0].scriptWitness.stack = [b'a']
+ tx.rehash()
- # Mine enough blocks to activate segwit.
- # TODO: we could verify that activation only happens at the right threshold
- # of signalling blocks, rather than just at the right period boundary.
+ tx_hash = tx.sha256
+ tx_value = tx.vout[0].nValue
+
+ # Verify that if a peer doesn't set nServices to include NODE_WITNESS,
+ # the getdata is just for the non-witness portion.
+ self.old_node.announce_tx_and_wait_for_getdata(tx)
+ assert(self.old_node.last_message["getdata"].inv[0].type == 1)
+
+ # Since we haven't delivered the tx yet, inv'ing the same tx from
+ # a witness transaction ought not result in a getdata.
+ self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2, success=False)
+
+ # Delivering this transaction with witness should fail (no matter who
+ # its from)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+ test_transaction_acceptance(self.nodes[0], self.old_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)
+
+ # But eliminating the witness should fix it
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
+
+ # Cleanup: mine the first transaction and update utxo
+ self.nodes[0].generate(1)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx_hash, 0, tx_value))
+
+ @subtest
+ def test_standardness_v0(self):
+ """Test V0 txout standardness.
+
+ V0 segwit outputs and inputs are always standard.
+ V0 segwit inputs may only be mined after activation, but not before."""
+
+ witness_program = CScript([OP_TRUE])
+ witness_hash = sha256(witness_program)
+ script_pubkey = CScript([OP_0, witness_hash])
+
+ p2sh_pubkey = hash160(witness_program)
+ p2sh_script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+
+ # First prepare a p2sh output (so that spending it will pass standardness)
+ p2sh_tx = CTransaction()
+ p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
+ p2sh_tx.vout = [CTxOut(self.utxo[0].nValue - 1000, p2sh_script_pubkey)]
+ p2sh_tx.rehash()
+
+ # Mine it on test_node to create the confirmed output.
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_tx, with_witness=True, accepted=True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # Now test standardness of v0 P2WSH outputs.
+ # Start by creating a transaction with two outputs.
+ tx = CTransaction()
+ tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
+ tx.vout = [CTxOut(p2sh_tx.vout[0].nValue - 10000, script_pubkey)]
+ tx.vout.append(CTxOut(8000, script_pubkey)) # Might burn this later
+ tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER # Just to have the option to bump this tx from the mempool
+ tx.rehash()
+
+ # This is always accepted, since the mempool policy is to consider segwit as always active
+ # and thus allow segwit outputs
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx, with_witness=True, accepted=True)
+
+ # Now create something that looks like a P2PKH output. This won't be spendable.
+ script_pubkey = CScript([OP_0, hash160(witness_hash)])
+ tx2 = CTransaction()
+ # tx was accepted, so we spend the second output.
+ tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
+ tx2.vout = [CTxOut(7000, script_pubkey)]
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ tx2.rehash()
+
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=True)
+
+ # Now update self.utxo for later tests.
+ tx3 = CTransaction()
+ # tx and tx2 were both accepted. Don't bother trying to reclaim the
+ # P2PKH output; just send tx's first output back to an anyone-can-spend.
+ sync_mempools([self.nodes[0], self.nodes[1]])
+ tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
+ tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ tx3.rehash()
+ if self.segwit_status != 'active':
+ # Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
+ # in blocks and the tx is impossible to mine right now.
+ assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ # Create the same output as tx3, but by replacing tx
+ tx3_out = tx3.vout[0]
+ tx3 = tx
+ tx3.vout = [tx3_out]
+ tx3.rehash()
+ assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
+
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+
+ @subtest
def advance_to_segwit_active(self):
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
+ """Mine enough blocks to activate segwit."""
height = self.nodes[0].getblockcount()
- self.nodes[0].generate(VB_PERIOD - (height%VB_PERIOD) - 2)
+ self.nodes[0].generate(VB_PERIOD - (height % VB_PERIOD) - 2)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
self.nodes[0].generate(1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'active')
+ self.segwit_status = 'active'
+
+ @subtest
+ def test_p2sh_witness(self):
+ """Test P2SH wrapped witness programs."""
+
+ # Prepare the p2sh-wrapped witness output
+ witness_program = CScript([OP_DROP, OP_TRUE])
+ witness_hash = sha256(witness_program)
+ p2wsh_pubkey = CScript([OP_0, witness_hash])
+ p2sh_witness_hash = hash160(p2wsh_pubkey)
+ script_pubkey = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
+ script_sig = CScript([p2wsh_pubkey]) # a push of the redeem script
+
+ # Fund the P2SH output
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
+ tx.rehash()
+
+ # Verify mempool acceptance and block validity
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=True)
+ sync_blocks(self.nodes)
+
+ # Now test attempts to spend the output.
+ spend_tx = CTransaction()
+ spend_tx.vin.append(CTxIn(COutPoint(tx.sha256, 0), script_sig))
+ spend_tx.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))
+ spend_tx.rehash()
+
+ # This transaction should not be accepted into the mempool pre- or
+ # post-segwit. Mempool acceptance will use SCRIPT_VERIFY_WITNESS which
+ # will require a witness to spend a witness program regardless of
+ # segwit activation. Note that older bitcoind's that are not
+ # segwit-aware would also reject this for failing CLEANSTACK.
+ test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)
+
+ # Try to put the witness script in the script_sig, should also fail.
+ spend_tx.vin[0].script_sig = CScript([p2wsh_pubkey, b'a'])
+ spend_tx.rehash()
+ test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)
+
+ # Now put the witness script in the witness, should succeed after
+ # segwit activates.
+ spend_tx.vin[0].scriptSig = script_sig
+ spend_tx.rehash()
+ spend_tx.wit.vtxinwit.append(CTxInWitness())
+ spend_tx.wit.vtxinwit[0].scriptWitness.stack = [b'a', witness_program]
+
+ # Verify mempool acceptance
+ test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=True, accepted=True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [spend_tx])
+
+ # If we're after activation, then sending this with witnesses should be valid.
+ # This no longer works before activation, because SCRIPT_VERIFY_WITNESS
+ # is always set.
+ # TODO: rewrite this test to make clear that it only works after activation.
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+ # Update self.utxo
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(spend_tx.sha256, 0, spend_tx.vout[0].nValue))
- # This test can only be run after segwit has activated
+ @subtest
def test_witness_commitments(self):
- self.log.info("Testing witness commitments")
+ """Test witness commitments.
+
+ This test can only be run after segwit has activated."""
# First try a correct witness commitment.
block = self.build_next_block()
@@ -406,7 +813,7 @@ class SegWitTest(BitcoinTestFramework):
assert(msg_witness_block(block).serialize() != msg_block(block).serialize())
# This empty block should be valid.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Try to tweak the nonce
block_2 = self.build_next_block()
@@ -417,24 +824,23 @@ class SegWitTest(BitcoinTestFramework):
assert(block_2.vtx[0].vout[-1] != block.vtx[0].vout[-1])
# This should also be valid.
- test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_2, accepted=True)
# Now test commitments with actual transactions
- assert (len(self.utxo) > 0)
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
# Let's construct a witness program
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
+ script_pubkey = CScript([OP_0, witness_hash])
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
# tx2 will spend tx1, and send back to a regular anyone-can-spend address
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, witness_program))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, witness_program))
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
@@ -450,7 +856,7 @@ class SegWitTest(BitcoinTestFramework):
block_3.rehash()
block_3.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
# Add a different commitment with different nonce, but in the
# right location, and with some funds burned(!).
@@ -462,29 +868,28 @@ class SegWitTest(BitcoinTestFramework):
block_3.vtx[0].rehash()
block_3.hashMerkleRoot = block_3.calc_merkle_root()
block_3.rehash()
- assert(len(block_3.vtx[0].vout) == 4) # 3 OP_returns
+ assert(len(block_3.vtx[0].vout) == 4) # 3 OP_returns
block_3.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=True)
# Finally test that a block with no witness transactions can
# omit the commitment.
block_4 = self.build_next_block()
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
- tx3.vout.append(CTxOut(tx.vout[0].nValue-1000, witness_program))
+ tx3.vout.append(CTxOut(tx.vout[0].nValue - 1000, witness_program))
tx3.rehash()
block_4.vtx.append(tx3)
block_4.hashMerkleRoot = block_4.calc_merkle_root()
block_4.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block_4, with_witness=False, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_4, with_witness=False, accepted=True)
# Update available utxo's for use in later test.
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
-
+ @subtest
def test_block_malleability(self):
- self.log.info("Testing witness block malleability")
# Make sure that a block that has too big a virtual size
# because of a too-large coinbase witness is not permanently
@@ -493,7 +898,7 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a'*5000000)
+ block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 5000000)
assert(get_virtual_size(block) > MAX_BLOCK_BASE_SIZE)
# We can't send over the p2p network, because this is too big to relay
@@ -516,16 +921,15 @@ class SegWitTest(BitcoinTestFramework):
# Change the nonce -- should not cause the block to be permanently
# failed
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ ser_uint256(1) ]
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(1)]
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Changing the witness reserved value doesn't change the block hash
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ ser_uint256(0) ]
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
+ block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+ @subtest
def test_witness_block_size(self):
- self.log.info("Testing witness block size limit")
# TODO: Test that non-witness carrying blocks can't exceed 1MB
# Skipping this test for now; this is covered in p2p-fullblocktest.py
@@ -538,21 +942,21 @@ class SegWitTest(BitcoinTestFramework):
# The witness program will be a bunch of OP_2DROP's, followed by OP_TRUE.
# This should give us plenty of room to tweak the spending tx's
# virtual size.
- NUM_DROPS = 200 # 201 max ops per script!
+ NUM_DROPS = 200 # 201 max ops per script!
NUM_OUTPUTS = 50
- witness_program = CScript([OP_2DROP]*NUM_DROPS + [OP_TRUE])
+ witness_program = CScript([OP_2DROP] * NUM_DROPS + [OP_TRUE])
witness_hash = uint256_from_str(sha256(witness_program))
- scriptPubKey = CScript([OP_0, ser_uint256(witness_hash)])
+ script_pubkey = CScript([OP_0, ser_uint256(witness_hash)])
prevout = COutPoint(self.utxo[0].sha256, self.utxo[0].n)
value = self.utxo[0].nValue
parent_tx = CTransaction()
parent_tx.vin.append(CTxIn(prevout, b""))
- child_value = int(value/NUM_OUTPUTS)
+ child_value = int(value / NUM_OUTPUTS)
for i in range(NUM_OUTPUTS):
- parent_tx.vout.append(CTxOut(child_value, scriptPubKey))
+ parent_tx.vout.append(CTxOut(child_value, script_pubkey))
parent_tx.vout[0].nValue -= 50000
assert(parent_tx.vout[0].nValue > 0)
parent_tx.rehash()
@@ -563,17 +967,17 @@ class SegWitTest(BitcoinTestFramework):
child_tx.vout = [CTxOut(value - 100000, CScript([OP_TRUE]))]
for i in range(NUM_OUTPUTS):
child_tx.wit.vtxinwit.append(CTxInWitness())
- child_tx.wit.vtxinwit[-1].scriptWitness.stack = [b'a'*195]*(2*NUM_DROPS) + [witness_program]
+ child_tx.wit.vtxinwit[-1].scriptWitness.stack = [b'a' * 195] * (2 * NUM_DROPS) + [witness_program]
child_tx.rehash()
self.update_witness_block_with_transactions(block, [parent_tx, child_tx])
vsize = get_virtual_size(block)
- additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize)*4
+ additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize) * 4
i = 0
while additional_bytes > 0:
# Add some more bytes to each input until we hit MAX_BLOCK_BASE_SIZE+1
- extra_bytes = min(additional_bytes+1, 55)
- block.vtx[-1].wit.vtxinwit[int(i/(2*NUM_DROPS))].scriptWitness.stack[i%(2*NUM_DROPS)] = b'a'*(195+extra_bytes)
+ extra_bytes = min(additional_bytes + 1, 55)
+ block.vtx[-1].wit.vtxinwit[int(i / (2 * NUM_DROPS))].scriptWitness.stack[i % (2 * NUM_DROPS)] = b'a' * (195 + extra_bytes)
additional_bytes -= extra_bytes
i += 1
@@ -584,34 +988,33 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)
# Make sure that our test case would exceed the old max-network-message
# limit
- assert(len(block.serialize(True)) > 2*1024*1024)
+ assert(len(block.serialize(True)) > 2 * 1024 * 1024)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now resize the second transaction to make the block fit.
cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])
- block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0] = b'a'*(cur_length-1)
+ block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (cur_length - 1)
block.vtx[0].vout.pop()
add_witness_commitment(block)
block.solve()
assert(get_virtual_size(block) == MAX_BLOCK_BASE_SIZE)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update available utxo's
self.utxo.pop(0)
self.utxo.append(UTXO(block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue))
-
- # submitblock will try to add the nonce automatically, so that mining
- # software doesn't need to worry about doing so itself.
+ @subtest
def test_submit_block(self):
+ """Test that submitblock adds the nonce automatically when possible."""
block = self.build_next_block()
# Try using a custom nonce and then don't supply it.
# This shouldn't possibly work.
add_witness_commitment(block, nonce=1)
- block.vtx[0].wit = CTxWitness() # drop the nonce
+ block.vtx[0].wit = CTxWitness() # drop the nonce
block.solve()
self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
assert(self.nodes[0].getbestblockhash() != block.hash)
@@ -639,31 +1042,28 @@ class SegWitTest(BitcoinTestFramework):
# Tip should not advance!
assert(self.nodes[0].getbestblockhash() != block_2.hash)
-
- # Consensus tests of extra witness data in a transaction.
+ @subtest
def test_extra_witness_data(self):
- self.log.info("Testing extra witness data in tx")
-
- assert(len(self.utxo) > 0)
+ """Test extra witness data in a transaction."""
block = self.build_next_block()
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
# First try extra witness data on a tx that doesn't require a witness
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-2000, scriptPubKey))
- tx.vout.append(CTxOut(1000, CScript([OP_TRUE]))) # non-witness output
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 2000, script_pubkey))
+ tx.vout.append(CTxOut(1000, CScript([OP_TRUE]))) # non-witness output
tx.wit.vtxinwit.append(CTxInWitness())
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([])]
tx.rehash()
self.update_witness_block_with_transactions(block, [tx])
# Extra witness data should not be allowed.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Try extra signature data. Ok if we're not spending a witness output.
block.vtx[1].wit.vtxinwit = []
@@ -672,23 +1072,23 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now try extra witness/signature data on an input that DOES require a
# witness
tx2 = CTransaction()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b"")) # witness output
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 1), b"")) # non-witness
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b"")) # witness output
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 1), b"")) # non-witness
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
tx2.wit.vtxinwit.extend([CTxInWitness(), CTxInWitness()])
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ CScript([CScriptNum(1)]), CScript([CScriptNum(1)]), witness_program ]
- tx2.wit.vtxinwit[1].scriptWitness.stack = [ CScript([OP_TRUE]) ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), CScript([CScriptNum(1)]), witness_program]
+ tx2.wit.vtxinwit[1].scriptWitness.stack = [CScript([OP_TRUE])]
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2])
# This has extra witness data, so it should fail.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now get rid of the extra witness, but add extra scriptSig data
tx2.vin[0].scriptSig = CScript([OP_TRUE])
@@ -700,7 +1100,7 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
# This has extra signature data for a witness input, so it should fail.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now get rid of the extra scriptsig on the witness input, and verify
# success (even with extra scriptsig data in the non-witness input)
@@ -709,123 +1109,117 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update utxo for later tests
self.utxo.pop(0)
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
-
+ @subtest
def test_max_witness_push_length(self):
- ''' Should only allow up to 520 byte pushes in witness stack '''
- self.log.info("Testing maximum witness push size")
- MAX_SCRIPT_ELEMENT_SIZE = 520
- assert(len(self.utxo))
+ """Test that witness stack can only allow up to 520 byte pushes."""
block = self.build_next_block()
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE])))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))
tx2.wit.vtxinwit.append(CTxInWitness())
# First try a 521-byte stack element
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ b'a'*(MAX_SCRIPT_ELEMENT_SIZE+1), witness_program ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * (MAX_SCRIPT_ELEMENT_SIZE + 1), witness_program]
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now reduce the length of the stack element
- tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a'*(MAX_SCRIPT_ELEMENT_SIZE)
+ tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (MAX_SCRIPT_ELEMENT_SIZE)
add_witness_commitment(block)
block.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update the utxo for later tests
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
+ @subtest
def test_max_witness_program_length(self):
- # Can create witness outputs that are long, but can't be greater than
- # 10k bytes to successfully spend
- self.log.info("Testing maximum witness program length")
- assert(len(self.utxo))
+ """Test that witness outputs greater than 10kB can't be spent."""
+
MAX_PROGRAM_LENGTH = 10000
# This program is 19 max pushes (9937 bytes), then 64 more opcode-bytes.
- long_witness_program = CScript([b'a'*520]*19 + [OP_DROP]*63 + [OP_TRUE])
- assert(len(long_witness_program) == MAX_PROGRAM_LENGTH+1)
+ long_witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 63 + [OP_TRUE])
+ assert(len(long_witness_program) == MAX_PROGRAM_LENGTH + 1)
long_witness_hash = sha256(long_witness_program)
- long_scriptPubKey = CScript([OP_0, long_witness_hash])
+ long_script_pubkey = CScript([OP_0, long_witness_hash])
block = self.build_next_block()
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, long_scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, long_script_pubkey))
tx.rehash()
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE])))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))
tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a']*44 + [long_witness_program]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a'] * 44 + [long_witness_program]
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Try again with one less byte in the witness program
- witness_program = CScript([b'a'*520]*19 + [OP_DROP]*62 + [OP_TRUE])
+ witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 62 + [OP_TRUE])
assert(len(witness_program) == MAX_PROGRAM_LENGTH)
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
- tx.vout[0] = CTxOut(tx.vout[0].nValue, scriptPubKey)
+ tx.vout[0] = CTxOut(tx.vout[0].nValue, script_pubkey)
tx.rehash()
tx2.vin[0].prevout.hash = tx.sha256
- tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a']*43 + [witness_program]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a'] * 43 + [witness_program]
tx2.rehash()
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
-
+ @subtest
def test_witness_input_length(self):
- ''' Ensure that vin length must match vtxinwit length '''
- self.log.info("Testing witness input length")
- assert(len(self.utxo))
+ """Test that vin length must match vtxinwit length."""
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
# Create a transaction that splits our utxo into many outputs
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- nValue = self.utxo[0].nValue
+ value = self.utxo[0].nValue
for i in range(10):
- tx.vout.append(CTxOut(int(nValue/10), scriptPubKey))
+ tx.vout.append(CTxOut(int(value / 10), script_pubkey))
tx.vout[0].nValue -= 1000
assert(tx.vout[0].nValue >= 0)
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Try various ways to spend tx that should all break.
# This "broken" transaction serializer will not normalize
@@ -851,7 +1245,7 @@ class SegWitTest(BitcoinTestFramework):
tx2 = BrokenCTransaction()
for i in range(10):
tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b""))
- tx2.vout.append(CTxOut(nValue-3000, CScript([OP_TRUE])))
+ tx2.vout.append(CTxOut(value - 3000, CScript([OP_TRUE])))
# First try using a too long vtxinwit
for i in range(11):
@@ -860,7 +1254,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now try using a too short vtxinwit
tx2.wit.vtxinwit.pop()
@@ -868,85 +1262,43 @@ class SegWitTest(BitcoinTestFramework):
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now make one of the intermediate witnesses be incorrect
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[-1].scriptWitness.stack = [b'a', witness_program]
- tx2.wit.vtxinwit[5].scriptWitness.stack = [ witness_program ]
+ tx2.wit.vtxinwit[5].scriptWitness.stack = [witness_program]
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Fix the broken witness and the block should be accepted.
tx2.wit.vtxinwit[5].scriptWitness.stack = [b'a', witness_program]
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
+ @subtest
+ def test_tx_relay_after_segwit_activation(self):
+ """Test transaction relay after segwit activation.
- def test_witness_tx_relay_before_segwit_activation(self):
- self.log.info("Testing relay of witness transactions")
- # Generate a transaction that doesn't require a witness, but send it
- # with a witness. Should be rejected for premature-witness, but should
- # not be added to recently rejected list.
- assert(len(self.utxo))
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
- tx.wit.vtxinwit.append(CTxInWitness())
- tx.wit.vtxinwit[0].scriptWitness.stack = [ b'a' ]
- tx.rehash()
-
- tx_hash = tx.sha256
- tx_value = tx.vout[0].nValue
-
- # Verify that if a peer doesn't set nServices to include NODE_WITNESS,
- # the getdata is just for the non-witness portion.
- self.old_node.announce_tx_and_wait_for_getdata(tx)
- assert(self.old_node.last_message["getdata"].inv[0].type == 1)
-
- # Since we haven't delivered the tx yet, inv'ing the same tx from
- # a witness transaction ought not result in a getdata.
- self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2, success=False)
-
- # Delivering this transaction with witness should fail (no matter who
- # its from)
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
- assert_equal(len(self.nodes[1].getrawmempool()), 0)
- test_transaction_acceptance(self.nodes[0].rpc, self.old_node, tx, with_witness=True, accepted=False)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=False)
-
- # But eliminating the witness should fix it
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
-
- # Cleanup: mine the first transaction and update utxo
- self.nodes[0].generate(1)
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
-
- self.utxo.pop(0)
- self.utxo.append(UTXO(tx_hash, 0, tx_value))
-
+ After segwit activates, verify that mempool:
+ - rejects transactions with unnecessary/extra witnesses
+ - accepts transactions with valid witnesses
+ and that witness transactions are relayed to non-upgraded peers."""
- # After segwit activates, verify that mempool:
- # - rejects transactions with unnecessary/extra witnesses
- # - accepts transactions with valid witnesses
- # and that witness transactions are relayed to non-upgraded peers.
- def test_tx_relay_after_segwit_activation(self):
- self.log.info("Testing relay of witness transactions")
# Generate a transaction that doesn't require a witness, but send it
# with a witness. Should be rejected because we can't use a witness
# when spending a non-witness output.
- assert(len(self.utxo))
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
tx.wit.vtxinwit.append(CTxInWitness())
- tx.wit.vtxinwit[0].scriptWitness.stack = [ b'a' ]
+ tx.wit.vtxinwit[0].scriptWitness.stack = [b'a']
tx.rehash()
tx_hash = tx.sha256
@@ -954,19 +1306,19 @@ class SegWitTest(BitcoinTestFramework):
# Verify that unnecessary witnesses are rejected.
self.test_node.announce_tx_and_wait_for_getdata(tx)
assert_equal(len(self.nodes[0].getrawmempool()), 0)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)
# Verify that removing the witness succeeds.
self.test_node.announce_tx_and_wait_for_getdata(tx)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
# Now try to add extra witness data to a valid witness tx.
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx_hash, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptPubKey))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))
tx2.rehash()
tx3 = CTransaction()
@@ -976,31 +1328,31 @@ class SegWitTest(BitcoinTestFramework):
# Add too-large for IsStandard witness and check that it does not enter reject filter
p2sh_program = CScript([OP_TRUE])
p2sh_pubkey = hash160(p2sh_program)
- witness_program2 = CScript([b'a'*400000])
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))
+ witness_program2 = CScript([b'a' * 400000])
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))
tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program2]
tx3.rehash()
# Node will not be blinded to the transaction
self.std_node.announce_tx_and_wait_for_getdata(tx3)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, True, False, b'tx-size')
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')
self.std_node.announce_tx_and_wait_for_getdata(tx3)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, True, False, b'tx-size')
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')
# Remove witness stuffing, instead add extra witness push on stack
tx3.vout[0] = CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))
- tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program ]
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program]
tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, with_witness=True, accepted=True)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False)
# Get rid of the extra witness, and verify acceptance.
- tx3.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
# Also check that old_node gets a tx announcement, even though this is
# a witness transaction.
- self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
+ self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
self.old_node.wait_for_inv([CInv(1, tx3.sha256)])
# Test that getrawtransaction returns correct witness information
@@ -1008,7 +1360,7 @@ class SegWitTest(BitcoinTestFramework):
raw_tx = self.nodes[0].getrawtransaction(tx3.hash, 1)
assert_equal(int(raw_tx["hash"], 16), tx3.calc_sha256(True))
assert_equal(raw_tx["size"], len(tx3.serialize_with_witness()))
- weight = len(tx3.serialize_with_witness()) + 3*len(tx3.serialize_without_witness())
+ weight = len(tx3.serialize_with_witness()) + 3 * len(tx3.serialize_without_witness())
vsize = math.ceil(weight / 4)
assert_equal(raw_tx["vsize"], vsize)
assert_equal(raw_tx["weight"], weight)
@@ -1018,240 +1370,68 @@ class SegWitTest(BitcoinTestFramework):
# Cleanup: mine the transactions and update utxo for next test
self.nodes[0].generate(1)
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ @subtest
+ def test_segwit_versions(self):
+ """Test validity of future segwit version transactions.
- # Test that block requests to NODE_WITNESS peer are with MSG_WITNESS_FLAG
- # This is true regardless of segwit activation.
- # Also test that we don't ask for blocks from unupgraded peers
- def test_block_relay(self, segwit_activated):
- self.log.info("Testing block relay")
-
- blocktype = 2|MSG_WITNESS_FLAG
-
- # test_node has set NODE_WITNESS, so all getdata requests should be for
- # witness blocks.
- # Test announcing a block via inv results in a getdata, and that
- # announcing a version 4 or random VB block with a header results in a getdata
- block1 = self.build_next_block()
- block1.solve()
-
- self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block1, True)
-
- block2 = self.build_next_block(nVersion=4)
- block2.solve()
-
- self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, True)
-
- block3 = self.build_next_block(nVersion=(VB_TOP_BITS | (1<<15)))
- block3.solve()
- self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block3, True)
-
- # Check that we can getdata for witness blocks or regular blocks,
- # and the right thing happens.
- if segwit_activated == False:
- # Before activation, we should be able to request old blocks with
- # or without witness, and they should be the same.
- chain_height = self.nodes[0].getblockcount()
- # Pick 10 random blocks on main chain, and verify that getdata's
- # for MSG_BLOCK, MSG_WITNESS_BLOCK, and rpc getblock() are equal.
- all_heights = list(range(chain_height+1))
- random.shuffle(all_heights)
- all_heights = all_heights[0:10]
- for height in all_heights:
- block_hash = self.nodes[0].getblockhash(height)
- rpc_block = self.nodes[0].getblock(block_hash, False)
- block_hash = int(block_hash, 16)
- block = self.test_node.request_block(block_hash, 2)
- wit_block = self.test_node.request_block(block_hash, 2|MSG_WITNESS_FLAG)
- assert_equal(block.serialize(True), wit_block.serialize(True))
- assert_equal(block.serialize(), hex_str_to_bytes(rpc_block))
- else:
- # After activation, witness blocks and non-witness blocks should
- # be different. Verify rpc getblock() returns witness blocks, while
- # getdata respects the requested type.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [])
- # This gives us a witness commitment.
- assert(len(block.vtx[0].wit.vtxinwit) == 1)
- assert(len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
- # Now try to retrieve it...
- rpc_block = self.nodes[0].getblock(block.hash, False)
- non_wit_block = self.test_node.request_block(block.sha256, 2)
- wit_block = self.test_node.request_block(block.sha256, 2|MSG_WITNESS_FLAG)
- assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block))
- assert_equal(wit_block.serialize(False), non_wit_block.serialize())
- assert_equal(wit_block.serialize(True), block.serialize(True))
-
- # Test size, vsize, weight
- rpc_details = self.nodes[0].getblock(block.hash, True)
- assert_equal(rpc_details["size"], len(block.serialize(True)))
- assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
- weight = 3*len(block.serialize(False)) + len(block.serialize(True))
- assert_equal(rpc_details["weight"], weight)
-
- # Upgraded node should not ask for blocks from unupgraded
- block4 = self.build_next_block(nVersion=4)
- block4.solve()
- self.old_node.getdataset = set()
-
- # Blocks can be requested via direct-fetch (immediately upon processing the announcement)
- # or via parallel download (with an indeterminate delay from processing the announcement)
- # so to test that a block is NOT requested, we could guess a time period to sleep for,
- # and then check. We can avoid the sleep() by taking advantage of transaction getdata's
- # being processed after block getdata's, and announce a transaction as well,
- # and then check to see if that particular getdata has been received.
- # Since 0.14, inv's will only be responded to with a getheaders, so send a header
- # to announce this block.
- msg = msg_headers()
- msg.headers = [ CBlockHeader(block4) ]
- self.old_node.send_message(msg)
- self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
- assert(block4.sha256 not in self.old_node.getdataset)
-
- # V0 segwit outputs should be standard after activation, but not before.
- def test_standardness_v0(self, segwit_activated):
- self.log.info("Testing standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before"))
- assert(len(self.utxo))
-
- witness_program = CScript([OP_TRUE])
- witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
-
- p2sh_pubkey = hash160(witness_program)
- p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
-
- # First prepare a p2sh output (so that spending it will pass standardness)
- p2sh_tx = CTransaction()
- p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
- p2sh_tx.vout = [CTxOut(self.utxo[0].nValue-1000, p2sh_scriptPubKey)]
- p2sh_tx.rehash()
-
- # Mine it on test_node to create the confirmed output.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_tx, with_witness=True, accepted=True)
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
-
- # Now test standardness of v0 P2WSH outputs.
- # Start by creating a transaction with two outputs.
- tx = CTransaction()
- tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
- tx.vout = [CTxOut(p2sh_tx.vout[0].nValue-10000, scriptPubKey)]
- tx.vout.append(CTxOut(8000, scriptPubKey)) # Might burn this later
- tx.rehash()
-
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=segwit_activated)
-
- # Now create something that looks like a P2PKH output. This won't be spendable.
- scriptPubKey = CScript([OP_0, hash160(witness_hash)])
- tx2 = CTransaction()
- if segwit_activated:
- # if tx was accepted, then we spend the second output.
- tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
- tx2.vout = [CTxOut(7000, scriptPubKey)]
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
- else:
- # if tx wasn't accepted, we just re-spend the p2sh output we started with.
- tx2.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
- tx2.vout = [CTxOut(p2sh_tx.vout[0].nValue-1000, scriptPubKey)]
- tx2.rehash()
-
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=segwit_activated)
-
- # Now update self.utxo for later tests.
- tx3 = CTransaction()
- if segwit_activated:
- # tx and tx2 were both accepted. Don't bother trying to reclaim the
- # P2PKH output; just send tx's first output back to an anyone-can-spend.
- sync_mempools([self.nodes[0], self.nodes[1]])
- tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
- tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
- tx3.wit.vtxinwit.append(CTxInWitness())
- tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
- tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
- else:
- # tx and tx2 didn't go anywhere; just clean up the p2sh_tx output.
- tx3.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
- tx3.vout = [CTxOut(p2sh_tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
- tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
-
- self.nodes[0].generate(1)
- sync_blocks(self.nodes)
- self.utxo.pop(0)
- self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
- assert_equal(len(self.nodes[1].getrawmempool()), 0)
-
+ Future segwit version transactions are non-standard, but valid in blocks.
+ Can run this before and after segwit activation."""
- # Verify that future segwit upgraded transactions are non-standard,
- # but valid in blocks. Can run this before and after segwit activation.
- def test_segwit_versions(self):
- self.log.info("Testing standardness/consensus for segwit versions (0-16)")
- assert(len(self.utxo))
- NUM_TESTS = 17 # will test OP_0, OP1, ..., OP_16
- if (len(self.utxo) < NUM_TESTS):
+ NUM_SEGWIT_VERSIONS = 17 # will test OP_0, OP1, ..., OP_16
+ if len(self.utxo) < NUM_SEGWIT_VERSIONS:
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- split_value = (self.utxo[0].nValue - 4000) // NUM_TESTS
- for i in range(NUM_TESTS):
+ split_value = (self.utxo[0].nValue - 4000) // NUM_SEGWIT_VERSIONS
+ for i in range(NUM_SEGWIT_VERSIONS):
tx.vout.append(CTxOut(split_value, CScript([OP_TRUE])))
tx.rehash()
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.pop(0)
- for i in range(NUM_TESTS):
+ for i in range(NUM_SEGWIT_VERSIONS):
self.utxo.append(UTXO(tx.sha256, i, split_value))
sync_blocks(self.nodes)
temp_utxo = []
tx = CTransaction()
- count = 0
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
assert_equal(len(self.nodes[1].getrawmempool()), 0)
- for version in list(range(OP_1, OP_16+1)) + [OP_0]:
- count += 1
- # First try to spend to a future version segwit scriptPubKey.
- scriptPubKey = CScript([CScriptOp(version), witness_hash])
+ for version in list(range(OP_1, OP_16 + 1)) + [OP_0]:
+ # First try to spend to a future version segwit script_pubkey.
+ script_pubkey = CScript([CScriptOp(version), witness_hash])
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
- tx.vout = [CTxOut(self.utxo[0].nValue-1000, scriptPubKey)]
+ tx.vout = [CTxOut(self.utxo[0].nValue - 1000, script_pubkey)]
tx.rehash()
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=False)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=True)
self.utxo.pop(0)
temp_utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
- self.nodes[0].generate(1) # Mine all the transactions
+ self.nodes[0].generate(1) # Mine all the transactions
sync_blocks(self.nodes)
assert(len(self.nodes[0].getrawmempool()) == 0)
# Finally, verify that version 0 -> version 1 transactions
# are non-standard
- scriptPubKey = CScript([CScriptOp(OP_1), witness_hash])
+ script_pubkey = CScript([CScriptOp(OP_1), witness_hash])
tx2 = CTransaction()
tx2.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
- tx2.vout = [CTxOut(tx.vout[0].nValue-1000, scriptPubKey)]
+ tx2.vout = [CTxOut(tx.vout[0].nValue - 1000, script_pubkey)]
tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
# Gets accepted to test_node, because standardness of outputs isn't
# checked with fRequireStandard
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, with_witness=True, accepted=True)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=False)
- temp_utxo.pop() # last entry in temp_utxo was the output we just spent
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=False)
+ temp_utxo.pop() # last entry in temp_utxo was the output we just spent
temp_utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
# Spend everything in temp_utxo back to an OP_TRUE output.
@@ -1266,39 +1446,36 @@ class SegWitTest(BitcoinTestFramework):
tx3.rehash()
# Spending a higher version witness output is not allowed by policy,
# even with fRequireStandard=false.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=False)
- self.test_node.sync_with_ping()
- with mininode_lock:
- assert(b"reserved for soft-fork upgrades" in self.test_node.last_message["reject"].reason)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False, reason="reserved for soft-fork upgrades")
# Building a block with the transaction must be valid, however.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2, tx3])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
sync_blocks(self.nodes)
# Add utxo to our list
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
-
+ @subtest
def test_premature_coinbase_witness_spend(self):
- self.log.info("Testing premature coinbase witness spend")
+
block = self.build_next_block()
# Change the output of the block to be a witness output.
witness_program = CScript([OP_TRUE])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
- block.vtx[0].vout[0].scriptPubKey = scriptPubKey
+ script_pubkey = CScript([OP_0, witness_hash])
+ block.vtx[0].vout[0].scriptPubKey = script_pubkey
# This next line will rehash the coinbase and update the merkle
# root, and solve.
self.update_witness_block_with_transactions(block, [])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
spend_tx = CTransaction()
spend_tx.vin = [CTxIn(COutPoint(block.vtx[0].sha256, 0), b"")]
spend_tx.vout = [CTxOut(block.vtx[0].vout[0].nValue, witness_program)]
spend_tx.wit.vtxinwit.append(CTxInWitness())
- spend_tx.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
+ spend_tx.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
spend_tx.rehash()
# Now test a premature spend.
@@ -1306,95 +1483,200 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block2, accepted=False)
# Advancing one more block should allow the spend.
self.nodes[0].generate(1)
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block2, accepted=True)
sync_blocks(self.nodes)
+ @subtest
+ def test_uncompressed_pubkey(self):
+ """Test uncompressed pubkey validity in segwit transactions.
+
+ Uncompressed pubkeys are no longer supported in default relay policy,
+ but (for now) are still valid in blocks."""
+
+ # Segwit transactions using uncompressed pubkeys are not accepted
+ # under default policy, but should still pass consensus.
+ key = CECKey()
+ key.set_secretbytes(b"9")
+ key.set_compressed(False)
+ pubkey = CPubKey(key.get_pubkey())
+ assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
+
+ utxo = self.utxo.pop(0)
+ # Test 1: P2WPKH
+ # First create a P2WPKH output that uses an uncompressed pubkey
+ pubkeyhash = hash160(pubkey)
+ script_pkh = CScript([OP_0, pubkeyhash])
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
+ tx.vout.append(CTxOut(utxo.nValue - 1000, script_pkh))
+ tx.rehash()
+
+ # Confirm it in a block.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+
+ # Now try to spend it. Send it to a P2WSH output, which we'll
+ # use in the next test.
+ witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
+ witness_hash = sha256(witness_program)
+ script_wsh = CScript([OP_0, witness_hash])
+
+ tx2 = CTransaction()
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_wsh))
+ script = get_p2pkh_script(pubkeyhash)
+ sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [signature, pubkey]
+ tx2.rehash()
+
+ # Should fail policy test.
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ # But passes consensus.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx2])
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+
+ # Test 2: P2WSH
+ # Try to spend the P2WSH output created in last test.
+ # Send it to a P2SH(P2WSH) output, which we'll use in the next test.
+ p2sh_witness_hash = hash160(script_wsh)
+ script_p2sh = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
+ script_sig = CScript([script_wsh])
+
+ tx3 = CTransaction()
+ tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, script_p2sh))
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ sign_p2pk_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
+
+ # Should fail policy test.
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ # But passes consensus.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx3])
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+
+ # Test 3: P2SH(P2WSH)
+ # Try to spend the P2SH output created in the last test.
+ # Send it to a P2PKH output, which we'll use in the next test.
+ script_pubkey = get_p2pkh_script(pubkeyhash)
+ tx4 = CTransaction()
+ tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), script_sig))
+ tx4.vout.append(CTxOut(tx3.vout[0].nValue - 1000, script_pubkey))
+ tx4.wit.vtxinwit.append(CTxInWitness())
+ sign_p2pk_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
+
+ # Should fail policy test.
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx4, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx4])
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+
+ # Test 4: Uncompressed pubkeys should still be valid in non-segwit
+ # transactions.
+ tx5 = CTransaction()
+ tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
+ tx5.vout.append(CTxOut(tx4.vout[0].nValue - 1000, CScript([OP_TRUE])))
+ (sig_hash, err) = SignatureHash(script_pubkey, tx5, 0, SIGHASH_ALL)
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx5.vin[0].scriptSig = CScript([signature, pubkey])
+ tx5.rehash()
+ # Should pass policy and consensus.
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx5, True, True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx5])
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
+ self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
+
+ @subtest
def test_signature_version_1(self):
- self.log.info("Testing segwit signature hash version 1")
+
key = CECKey()
key.set_secretbytes(b"9")
pubkey = CPubKey(key.get_pubkey())
witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
+ script_pubkey = CScript([OP_0, witness_hash])
# First create a witness output for use in the tests.
- assert(len(self.utxo))
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=True)
# Mine this transaction in preparation for following tests.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
sync_blocks(self.nodes)
self.utxo.pop(0)
# Test each hashtype
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
- for sigflag in [ 0, SIGHASH_ANYONECANPAY ]:
+ for sigflag in [0, SIGHASH_ANYONECANPAY]:
for hashtype in [SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE]:
hashtype |= sigflag
block = self.build_next_block()
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(prev_utxo.sha256, prev_utxo.n), b""))
- tx.vout.append(CTxOut(prev_utxo.nValue - 1000, scriptPubKey))
+ tx.vout.append(CTxOut(prev_utxo.nValue - 1000, script_pubkey))
tx.wit.vtxinwit.append(CTxInWitness())
# Too-large input value
- sign_P2PK_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue+1, key)
+ sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue + 1, key)
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Too-small input value
- sign_P2PK_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue-1, key)
- block.vtx.pop() # remove last tx
+ sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue - 1, key)
+ block.vtx.pop() # remove last tx
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now try correct value
- sign_P2PK_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue, key)
block.vtx.pop()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
# Test combinations of signature hashes.
# Split the utxo into a lot of outputs.
# Randomly choose up to 10 to spend, sign with different hashtypes, and
- # output to a random number of outputs. Repeat NUM_TESTS times.
+ # output to a random number of outputs. Repeat NUM_SIGHASH_TESTS times.
# Ensure that we've tested a situation where we use SIGHASH_SINGLE with
# an input index > number of outputs.
- NUM_TESTS = 500
+ NUM_SIGHASH_TESTS = 500
temp_utxos = []
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(prev_utxo.sha256, prev_utxo.n), b""))
- split_value = prev_utxo.nValue // NUM_TESTS
- for i in range(NUM_TESTS):
- tx.vout.append(CTxOut(split_value, scriptPubKey))
+ split_value = prev_utxo.nValue // NUM_SIGHASH_TESTS
+ for i in range(NUM_SIGHASH_TESTS):
+ tx.vout.append(CTxOut(split_value, script_pubkey))
tx.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx, 0, SIGHASH_ALL, prev_utxo.nValue, key)
- for i in range(NUM_TESTS):
+ sign_p2pk_witness_input(witness_program, tx, 0, SIGHASH_ALL, prev_utxo.nValue, key)
+ for i in range(NUM_SIGHASH_TESTS):
temp_utxos.append(UTXO(tx.sha256, i, split_value))
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
block = self.build_next_block()
used_sighash_single_out_of_bounds = False
- for i in range(NUM_TESTS):
+ for i in range(NUM_SIGHASH_TESTS):
# Ping regularly to keep the connection alive
if (not i % 100):
self.test_node.sync_with_ping()
@@ -1412,14 +1694,14 @@ class SegWitTest(BitcoinTestFramework):
total_value += temp_utxos[i].nValue
split_value = total_value // num_outputs
for i in range(num_outputs):
- tx.vout.append(CTxOut(split_value, scriptPubKey))
+ tx.vout.append(CTxOut(split_value, script_pubkey))
for i in range(num_inputs):
# Now try to sign each input, using a random hashtype.
anyonecanpay = 0
if random.randint(0, 1):
anyonecanpay = SIGHASH_ANYONECANPAY
hashtype = random.randint(1, 3) | anyonecanpay
- sign_P2PK_witness_input(witness_program, tx, i, hashtype, temp_utxos[i].nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, i, hashtype, temp_utxos[i].nValue, key)
if (hashtype == SIGHASH_SINGLE and i >= num_outputs):
used_sighash_single_out_of_bounds = True
tx.rehash()
@@ -1432,7 +1714,7 @@ class SegWitTest(BitcoinTestFramework):
# Test the block periodically, if we're close to maxblocksize
if (get_virtual_size(block) > MAX_BLOCK_BASE_SIZE - 1000):
self.update_witness_block_with_transactions(block, [])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
block = self.build_next_block()
if (not used_sighash_single_out_of_bounds):
@@ -1440,29 +1722,29 @@ class SegWitTest(BitcoinTestFramework):
# Test the transactions we've added to the block
if (len(block.vtx) > 1):
self.update_witness_block_with_transactions(block, [])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now test witness version 0 P2PKH transactions
pubkeyhash = hash160(pubkey)
- scriptPKH = CScript([OP_0, pubkeyhash])
+ script_pkh = CScript([OP_0, pubkeyhash])
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(temp_utxos[0].sha256, temp_utxos[0].n), b""))
- tx.vout.append(CTxOut(temp_utxos[0].nValue, scriptPKH))
+ tx.vout.append(CTxOut(temp_utxos[0].nValue, script_pkh))
tx.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx, 0, SIGHASH_ALL, temp_utxos[0].nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, 0, SIGHASH_ALL, temp_utxos[0].nValue, key)
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
- script = GetP2PKHScript(pubkeyhash)
+ script = get_p2pkh_script(pubkeyhash)
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
# Check that we can't have a scriptSig
tx2.vin[0].scriptSig = CScript([signature, pubkey])
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Move the signature to the witness.
block.vtx.pop()
@@ -1472,7 +1754,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
temp_utxos.pop(0)
@@ -1489,374 +1771,72 @@ class SegWitTest(BitcoinTestFramework):
# the signatures as we go.
tx.vin.append(CTxIn(COutPoint(i.sha256, i.n), b""))
tx.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx, index, SIGHASH_ALL|SIGHASH_ANYONECANPAY, i.nValue, key)
+ sign_p2pk_witness_input(witness_program, tx, index, SIGHASH_ALL | SIGHASH_ANYONECANPAY, i.nValue, key)
index += 1
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
for i in range(len(tx.vout)):
self.utxo.append(UTXO(tx.sha256, i, tx.vout[i].nValue))
+ @subtest
+ def test_non_standard_witness_blinding(self):
+ """Test behavior of unnecessary witnesses in transactions does not blind the node for the transaction"""
- # Test P2SH wrapped witness programs.
- def test_p2sh_witness(self, segwit_activated):
- self.log.info("Testing P2SH witness transactions")
-
- assert(len(self.utxo))
-
- # Prepare the p2sh-wrapped witness output
- witness_program = CScript([OP_DROP, OP_TRUE])
- witness_hash = sha256(witness_program)
- p2wsh_pubkey = CScript([OP_0, witness_hash])
- p2sh_witness_hash = hash160(p2wsh_pubkey)
- scriptPubKey = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
- scriptSig = CScript([p2wsh_pubkey]) # a push of the redeem script
-
- # Fund the P2SH output
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- tx.vout.append(CTxOut(self.utxo[0].nValue-1000, scriptPubKey))
- tx.rehash()
-
- # Verify mempool acceptance and block validity
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True, with_witness=segwit_activated)
- sync_blocks(self.nodes)
-
- # Now test attempts to spend the output.
- spend_tx = CTransaction()
- spend_tx.vin.append(CTxIn(COutPoint(tx.sha256, 0), scriptSig))
- spend_tx.vout.append(CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE])))
- spend_tx.rehash()
-
- # This transaction should not be accepted into the mempool pre- or
- # post-segwit. Mempool acceptance will use SCRIPT_VERIFY_WITNESS which
- # will require a witness to spend a witness program regardless of
- # segwit activation. Note that older bitcoind's that are not
- # segwit-aware would also reject this for failing CLEANSTACK.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
-
- # Try to put the witness script in the scriptSig, should also fail.
- spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a'])
- spend_tx.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
-
- # Now put the witness script in the witness, should succeed after
- # segwit activates.
- spend_tx.vin[0].scriptSig = scriptSig
- spend_tx.rehash()
- spend_tx.wit.vtxinwit.append(CTxInWitness())
- spend_tx.wit.vtxinwit[0].scriptWitness.stack = [ b'a', witness_program ]
-
- # Verify mempool acceptance
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=True, accepted=segwit_activated)
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [spend_tx])
-
- # If we're after activation, then sending this with witnesses should be valid.
- # This no longer works before activation, because SCRIPT_VERIFY_WITNESS
- # is always set.
- # TODO: rewrite this test to make clear that it only works after activation.
- if segwit_activated:
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
- else:
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True, with_witness=False)
-
- # Update self.utxo
- self.utxo.pop(0)
- self.utxo.append(UTXO(spend_tx.sha256, 0, spend_tx.vout[0].nValue))
-
- # Test the behavior of starting up a segwit-aware node after the softfork
- # has activated. As segwit requires different block data than pre-segwit
- # nodes would have stored, this requires special handling.
- # To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to
- # the test.
- def test_upgrade_after_activation(self, node_id):
- self.log.info("Testing software upgrade after softfork activation")
-
- assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind
-
- # Make sure the nodes are all up
- sync_blocks(self.nodes)
-
- # Restart with the new binary
- self.stop_node(node_id)
- self.start_node(node_id, extra_args=["-vbparams=segwit:0:999999999999"])
- connect_nodes(self.nodes[0], node_id)
-
- sync_blocks(self.nodes)
-
- # Make sure that this peer thinks segwit has activated.
- assert(get_bip9_status(self.nodes[node_id], 'segwit')['status'] == "active")
-
- # Make sure this peer's blocks match those of node0.
- height = self.nodes[node_id].getblockcount()
- while height >= 0:
- block_hash = self.nodes[node_id].getblockhash(height)
- assert_equal(block_hash, self.nodes[0].getblockhash(height))
- assert_equal(self.nodes[0].getblock(block_hash), self.nodes[node_id].getblock(block_hash))
- height -= 1
-
-
- def test_witness_sigops(self):
- '''Ensure sigop counting is correct inside witnesses.'''
- self.log.info("Testing sigops limit")
-
- assert(len(self.utxo))
-
- # Keep this under MAX_OPS_PER_SCRIPT (201)
- witness_program = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKMULTISIG]*5 + [OP_CHECKSIG]*193 + [OP_ENDIF])
- witness_hash = sha256(witness_program)
- scriptPubKey = CScript([OP_0, witness_hash])
-
- sigops_per_script = 20*5 + 193*1
- # We'll produce 2 extra outputs, one with a program that would take us
- # over max sig ops, and one with a program that would exactly reach max
- # sig ops
- outputs = (MAX_SIGOP_COST // sigops_per_script) + 2
- extra_sigops_available = MAX_SIGOP_COST % sigops_per_script
-
- # We chose the number of checkmultisigs/checksigs to make this work:
- assert(extra_sigops_available < 100) # steer clear of MAX_OPS_PER_SCRIPT
-
- # This script, when spent with the first
- # N(=MAX_SIGOP_COST//sigops_per_script) outputs of our transaction,
- # would push us just over the block sigop limit.
- witness_program_toomany = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG]*(extra_sigops_available + 1) + [OP_ENDIF])
- witness_hash_toomany = sha256(witness_program_toomany)
- scriptPubKey_toomany = CScript([OP_0, witness_hash_toomany])
-
- # If we spend this script instead, we would exactly reach our sigop
- # limit (for witness sigops).
- witness_program_justright = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG]*(extra_sigops_available) + [OP_ENDIF])
- witness_hash_justright = sha256(witness_program_justright)
- scriptPubKey_justright = CScript([OP_0, witness_hash_justright])
+ # Create a p2sh output -- this is so we can pass the standardness
+ # rules (an anyone-can-spend OP_TRUE would be rejected, if not wrapped
+ # in P2SH).
+ p2sh_program = CScript([OP_TRUE])
+ p2sh_pubkey = hash160(p2sh_program)
+ script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
- # First split our available utxo into a bunch of outputs
- split_value = self.utxo[0].nValue // outputs
+ # Now check that unnecessary witnesses can't be used to blind a node
+ # to a transaction, eg by violating standardness checks.
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
- for i in range(outputs):
- tx.vout.append(CTxOut(split_value, scriptPubKey))
- tx.vout[-2].scriptPubKey = scriptPubKey_toomany
- tx.vout[-1].scriptPubKey = scriptPubKey_justright
+ tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
-
- block_1 = self.build_next_block()
- self.update_witness_block_with_transactions(block_1, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_1, accepted=True)
-
- tx2 = CTransaction()
- # If we try to spend the first n-1 outputs from tx, that should be
- # too many sigops.
- total_value = 0
- for i in range(outputs-1):
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b""))
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[-1].scriptWitness.stack = [ witness_program ]
- total_value += tx.vout[i].nValue
- tx2.wit.vtxinwit[-1].scriptWitness.stack = [ witness_program_toomany ]
- tx2.vout.append(CTxOut(total_value, CScript([OP_TRUE])))
- tx2.rehash()
-
- block_2 = self.build_next_block()
- self.update_witness_block_with_transactions(block_2, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=False)
-
- # Try dropping the last input in tx2, and add an output that has
- # too many sigops (contributing to legacy sigop count).
- checksig_count = (extra_sigops_available // 4) + 1
- scriptPubKey_checksigs = CScript([OP_CHECKSIG]*checksig_count)
- tx2.vout.append(CTxOut(0, scriptPubKey_checksigs))
- tx2.vin.pop()
- tx2.wit.vtxinwit.pop()
- tx2.vout[0].nValue -= tx.vout[-2].nValue
- tx2.rehash()
- block_3 = self.build_next_block()
- self.update_witness_block_with_transactions(block_3, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=False)
-
- # If we drop the last checksig in this output, the tx should succeed.
- block_4 = self.build_next_block()
- tx2.vout[-1].scriptPubKey = CScript([OP_CHECKSIG]*(checksig_count-1))
- tx2.rehash()
- self.update_witness_block_with_transactions(block_4, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_4, accepted=True)
-
- # Reset the tip back down for the next test
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, False, True)
+ self.nodes[0].generate(1)
sync_blocks(self.nodes)
- for x in self.nodes:
- x.invalidateblock(block_4.hash)
-
- # Try replacing the last input of tx2 to be spending the last
- # output of tx
- block_5 = self.build_next_block()
- tx2.vout.pop()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, outputs-1), b""))
- tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[-1].scriptWitness.stack = [ witness_program_justright ]
- tx2.rehash()
- self.update_witness_block_with_transactions(block_5, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_5, accepted=True)
-
- # TODO: test p2sh sigop counting
-
- def test_getblocktemplate_before_lockin(self):
- self.log.info("Testing getblocktemplate setting of segwit versionbit (before lockin)")
- # Node0 is segwit aware, node2 is not.
- for node in [self.nodes[0], self.nodes[2]]:
- gbt_results = node.getblocktemplate()
- block_version = gbt_results['version']
- # If we're not indicating segwit support, we will still be
- # signalling for segwit activation.
- assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0])
- # If we don't specify the segwit rule, then we won't get a default
- # commitment.
- assert('default_witness_commitment' not in gbt_results)
-
- # Workaround:
- # Can either change the tip, or change the mempool and wait 5 seconds
- # to trigger a recomputation of getblocktemplate.
- txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
- # Using mocktime lets us avoid sleep()
- sync_mempools(self.nodes)
- self.nodes[0].setmocktime(int(time.time())+10)
- self.nodes[2].setmocktime(int(time.time())+10)
-
- for node in [self.nodes[0], self.nodes[2]]:
- gbt_results = node.getblocktemplate({"rules" : ["segwit"]})
- block_version = gbt_results['version']
- if node == self.nodes[2]:
- # If this is a non-segwit node, we should still not get a witness
- # commitment, nor a version bit signalling segwit.
- assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
- assert('default_witness_commitment' not in gbt_results)
- else:
- # For segwit-aware nodes, check the version bit and the witness
- # commitment are correct.
- assert(block_version & (1 << VB_WITNESS_BIT) != 0)
- assert('default_witness_commitment' in gbt_results)
- witness_commitment = gbt_results['default_witness_commitment']
-
- # Check that default_witness_commitment is present.
- witness_root = CBlock.get_merkle_root([ser_uint256(0),
- ser_uint256(txid)])
- script = get_witness_script(witness_root, 0)
- assert_equal(witness_commitment, bytes_to_hex_str(script))
-
- # undo mocktime
- self.nodes[0].setmocktime(0)
- self.nodes[2].setmocktime(0)
-
- # Uncompressed pubkeys are no longer supported in default relay policy,
- # but (for now) are still valid in blocks.
- def test_uncompressed_pubkey(self):
- self.log.info("Testing uncompressed pubkeys")
- # Segwit transactions using uncompressed pubkeys are not accepted
- # under default policy, but should still pass consensus.
- key = CECKey()
- key.set_secretbytes(b"9")
- key.set_compressed(False)
- pubkey = CPubKey(key.get_pubkey())
- assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
-
- assert(len(self.utxo) > 0)
- utxo = self.utxo.pop(0)
-
- # Test 1: P2WPKH
- # First create a P2WPKH output that uses an uncompressed pubkey
- pubkeyhash = hash160(pubkey)
- scriptPKH = CScript([OP_0, pubkeyhash])
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
- tx.vout.append(CTxOut(utxo.nValue-1000, scriptPKH))
- tx.rehash()
-
- # Confirm it in a block.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Now try to spend it. Send it to a P2WSH output, which we'll
- # use in the next test.
- witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
- witness_hash = sha256(witness_program)
- scriptWSH = CScript([OP_0, witness_hash])
+ # We'll add an unnecessary witness to this transaction that would cause
+ # it to be non-standard, to test that violating policy with a witness
+ # doesn't blind a node to a transaction. Transactions
+ # rejected for having a witness shouldn't be added
+ # to the rejection cache.
tx2 = CTransaction()
- tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
- tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptWSH))
- script = GetP2PKHScript(pubkeyhash)
- sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), CScript([p2sh_program])))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))
tx2.wit.vtxinwit.append(CTxInWitness())
- tx2.wit.vtxinwit[0].scriptWitness.stack = [ signature, pubkey ]
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * 400]
tx2.rehash()
+ # This will be rejected due to a policy check:
+ # No witness is allowed, since it is not a witness program but a p2sh program
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, True, False, 'bad-witness-nonstandard')
- # Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
- # But passes consensus.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Test 2: P2WSH
- # Try to spend the P2WSH output created in last test.
- # Send it to a P2SH(P2WSH) output, which we'll use in the next test.
- p2sh_witness_hash = hash160(scriptWSH)
- scriptP2SH = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
- scriptSig = CScript([scriptWSH])
+ # If we send without witness, it should be accepted.
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, False, True)
+ # Now create a new anyone-can-spend utxo for the next test.
tx3 = CTransaction()
- tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptP2SH))
- tx3.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
-
- # Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
- # But passes consensus.
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx3])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
-
- # Test 3: P2SH(P2WSH)
- # Try to spend the P2SH output created in the last test.
- # Send it to a P2PKH output, which we'll use in the next test.
- scriptPubKey = GetP2PKHScript(pubkeyhash)
- tx4 = CTransaction()
- tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), scriptSig))
- tx4.vout.append(CTxOut(tx3.vout[0].nValue-1000, scriptPubKey))
- tx4.wit.vtxinwit.append(CTxInWitness())
- sign_P2PK_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
+ tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
+ tx3.rehash()
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, False, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, False, True)
- # Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx4])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
- # Test 4: Uncompressed pubkeys should still be valid in non-segwit
- # transactions.
- tx5 = CTransaction()
- tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
- tx5.vout.append(CTxOut(tx4.vout[0].nValue-1000, CScript([OP_TRUE])))
- (sig_hash, err) = SignatureHash(scriptPubKey, tx5, 0, SIGHASH_ALL)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
- tx5.vin[0].scriptSig = CScript([signature, pubkey])
- tx5.rehash()
- # Should pass policy and consensus.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx5, True, True)
- block = self.build_next_block()
- self.update_witness_block_with_transactions(block, [tx5])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
- self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
+ # Update our utxo list; we spent the first entry.
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ @subtest
def test_non_standard_witness(self):
- self.log.info("Testing detection of non-standard P2WSH witness")
+ """Test detection of non-standard P2WSH witness"""
pad = chr(1).encode('latin-1')
# Create scripts for tests
@@ -1868,7 +1848,6 @@ class SegWitTest(BitcoinTestFramework):
p2wsh_scripts = []
- assert(len(self.utxo))
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
@@ -1882,7 +1861,7 @@ class SegWitTest(BitcoinTestFramework):
tx.vout.append(CTxOut(outputvalue, CScript([OP_HASH160, p2sh, OP_EQUAL])))
tx.rehash()
txid = tx.sha256
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -1892,13 +1871,13 @@ class SegWitTest(BitcoinTestFramework):
p2sh_txs = []
for i in range(len(scripts)):
p2wsh_tx = CTransaction()
- p2wsh_tx.vin.append(CTxIn(COutPoint(txid,i*2)))
+ p2wsh_tx.vin.append(CTxIn(COutPoint(txid, i * 2)))
p2wsh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
p2wsh_tx.rehash()
p2wsh_txs.append(p2wsh_tx)
p2sh_tx = CTransaction()
- p2sh_tx.vin.append(CTxIn(COutPoint(txid,i*2+1), CScript([p2wsh_scripts[i]])))
+ p2sh_tx.vin.append(CTxIn(COutPoint(txid, i * 2 + 1), CScript([p2wsh_scripts[i]])))
p2sh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
p2sh_tx.wit.vtxinwit.append(CTxInWitness())
p2sh_tx.rehash()
@@ -1907,45 +1886,45 @@ class SegWitTest(BitcoinTestFramework):
# Testing native P2WSH
# Witness stack size, excluding witnessScript, over 100 is non-standard
p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[0], True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[0], True, False, 'bad-witness-nonstandard')
# Non-standard nodes should accept
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[0], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[0], True, True)
# Stack element size over 80 bytes is non-standard
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[1], True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, False, 'bad-witness-nonstandard')
# Non-standard nodes should accept
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[1], True, True)
# Standard nodes should accept if element size is not over 80 bytes
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, True)
# witnessScript size at 3600 bytes is standard
p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[2], True, True)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[2], True, True)
# witnessScript size at 3601 bytes is non-standard
p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[3], True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[3], True, False, 'bad-witness-nonstandard')
# Non-standard nodes should accept
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[3], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[3], True, True)
# Repeating the same tests with P2SH-P2WSH
p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[0], True, False, b'bad-witness-nonstandard')
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[0], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[0], True, False, 'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[0], True, True)
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[1], True, False, b'bad-witness-nonstandard')
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, False, 'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[1], True, True)
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, True)
p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[2], True, True)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[2], True, True)
p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[3], True, False, b'bad-witness-nonstandard')
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[3], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[3], True, False, 'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[3], True, True)
self.nodes[0].generate(1) # Mine and clean up the mempool of non-standard node
# Valid but non-standard transactions in a block should be accepted by standard node
@@ -1955,79 +1934,128 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
+ @subtest
+ def test_upgrade_after_activation(self):
+ """Test the behavior of starting up a segwit-aware node after the softfork has activated."""
- def run_test(self):
- # Setup the p2p connections and start up the network thread.
- # self.test_node sets NODE_WITNESS|NODE_NETWORK
- self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
- # self.old_node sets only NODE_NETWORK
- self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
- # self.std_node is for testing node1 (fRequireStandard=true)
- self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK|NODE_WITNESS)
+ # Restart with the new binary
+ self.stop_node(2)
+ self.start_node(2, extra_args=["-vbparams=segwit:0:999999999999"])
+ connect_nodes(self.nodes[0], 2)
- network_thread_start()
+ sync_blocks(self.nodes)
- # Keep a place to store utxo's that can be used in later tests
- self.utxo = []
+ # Make sure that this peer thinks segwit has activated.
+ assert(get_bip9_status(self.nodes[2], 'segwit')['status'] == "active")
- # Test logic begins here
- self.test_node.wait_for_verack()
+ # Make sure this peer's blocks match those of node0.
+ height = self.nodes[2].getblockcount()
+ while height >= 0:
+ block_hash = self.nodes[2].getblockhash(height)
+ assert_equal(block_hash, self.nodes[0].getblockhash(height))
+ assert_equal(self.nodes[0].getblock(block_hash), self.nodes[2].getblock(block_hash))
+ height -= 1
- self.log.info("Starting tests before segwit lock in:")
+ @subtest
+ def test_witness_sigops(self):
+ """Test sigop counting is correct inside witnesses."""
- self.test_witness_services() # Verifies NODE_WITNESS
- self.test_non_witness_transaction() # non-witness tx's are accepted
- self.test_unnecessary_witness_before_segwit_activation()
- self.test_v0_outputs_arent_spendable()
- self.test_block_relay(segwit_activated=False)
+ # Keep this under MAX_OPS_PER_SCRIPT (201)
+ witness_program = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKMULTISIG] * 5 + [OP_CHECKSIG] * 193 + [OP_ENDIF])
+ witness_hash = sha256(witness_program)
+ script_pubkey = CScript([OP_0, witness_hash])
- # Advance to segwit being 'started'
- self.advance_to_segwit_started()
- sync_blocks(self.nodes)
- self.test_getblocktemplate_before_lockin()
+ sigops_per_script = 20 * 5 + 193 * 1
+ # We'll produce 2 extra outputs, one with a program that would take us
+ # over max sig ops, and one with a program that would exactly reach max
+ # sig ops
+ outputs = (MAX_SIGOP_COST // sigops_per_script) + 2
+ extra_sigops_available = MAX_SIGOP_COST % sigops_per_script
- sync_blocks(self.nodes)
+ # We chose the number of checkmultisigs/checksigs to make this work:
+ assert(extra_sigops_available < 100) # steer clear of MAX_OPS_PER_SCRIPT
- # At lockin, nothing should change.
- self.log.info("Testing behavior post lockin, pre-activation")
- self.advance_to_segwit_lockin()
+ # This script, when spent with the first
+ # N(=MAX_SIGOP_COST//sigops_per_script) outputs of our transaction,
+ # would push us just over the block sigop limit.
+ witness_program_toomany = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG] * (extra_sigops_available + 1) + [OP_ENDIF])
+ witness_hash_toomany = sha256(witness_program_toomany)
+ script_pubkey_toomany = CScript([OP_0, witness_hash_toomany])
- # Retest unnecessary witnesses
- self.test_unnecessary_witness_before_segwit_activation()
- self.test_witness_tx_relay_before_segwit_activation()
- self.test_block_relay(segwit_activated=False)
- self.test_standardness_v0(segwit_activated=False)
+ # If we spend this script instead, we would exactly reach our sigop
+ # limit (for witness sigops).
+ witness_program_justright = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG] * (extra_sigops_available) + [OP_ENDIF])
+ witness_hash_justright = sha256(witness_program_justright)
+ script_pubkey_justright = CScript([OP_0, witness_hash_justright])
- sync_blocks(self.nodes)
+ # First split our available utxo into a bunch of outputs
+ split_value = self.utxo[0].nValue // outputs
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+ for i in range(outputs):
+ tx.vout.append(CTxOut(split_value, script_pubkey))
+ tx.vout[-2].scriptPubKey = script_pubkey_toomany
+ tx.vout[-1].scriptPubKey = script_pubkey_justright
+ tx.rehash()
- # Now activate segwit
- self.log.info("Testing behavior after segwit activation")
- self.advance_to_segwit_active()
+ block_1 = self.build_next_block()
+ self.update_witness_block_with_transactions(block_1, [tx])
+ test_witness_block(self.nodes[0], self.test_node, block_1, accepted=True)
- sync_blocks(self.nodes)
+ tx2 = CTransaction()
+ # If we try to spend the first n-1 outputs from tx, that should be
+ # too many sigops.
+ total_value = 0
+ for i in range(outputs - 1):
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b""))
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program]
+ total_value += tx.vout[i].nValue
+ tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_toomany]
+ tx2.vout.append(CTxOut(total_value, CScript([OP_TRUE])))
+ tx2.rehash()
- # Test P2SH witness handling again
- self.test_p2sh_witness(segwit_activated=True)
- self.test_witness_commitments()
- self.test_block_malleability()
- self.test_witness_block_size()
- self.test_submit_block()
- self.test_extra_witness_data()
- self.test_max_witness_push_length()
- self.test_max_witness_program_length()
- self.test_witness_input_length()
- self.test_block_relay(segwit_activated=True)
- self.test_tx_relay_after_segwit_activation()
- self.test_standardness_v0(segwit_activated=True)
- self.test_segwit_versions()
- self.test_premature_coinbase_witness_spend()
- self.test_uncompressed_pubkey()
- self.test_signature_version_1()
- self.test_non_standard_witness()
+ block_2 = self.build_next_block()
+ self.update_witness_block_with_transactions(block_2, [tx2])
+ test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False)
+
+ # Try dropping the last input in tx2, and add an output that has
+ # too many sigops (contributing to legacy sigop count).
+ checksig_count = (extra_sigops_available // 4) + 1
+ script_pubkey_checksigs = CScript([OP_CHECKSIG] * checksig_count)
+ tx2.vout.append(CTxOut(0, script_pubkey_checksigs))
+ tx2.vin.pop()
+ tx2.wit.vtxinwit.pop()
+ tx2.vout[0].nValue -= tx.vout[-2].nValue
+ tx2.rehash()
+ block_3 = self.build_next_block()
+ self.update_witness_block_with_transactions(block_3, [tx2])
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
+
+ # If we drop the last checksig in this output, the tx should succeed.
+ block_4 = self.build_next_block()
+ tx2.vout[-1].scriptPubKey = CScript([OP_CHECKSIG] * (checksig_count - 1))
+ tx2.rehash()
+ self.update_witness_block_with_transactions(block_4, [tx2])
+ test_witness_block(self.nodes[0], self.test_node, block_4, accepted=True)
+
+ # Reset the tip back down for the next test
sync_blocks(self.nodes)
- self.test_upgrade_after_activation(node_id=2)
- self.test_witness_sigops()
+ for x in self.nodes:
+ x.invalidateblock(block_4.hash)
+ # Try replacing the last input of tx2 to be spending the last
+ # output of tx
+ block_5 = self.build_next_block()
+ tx2.vout.pop()
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, outputs - 1), b""))
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_justright]
+ tx2.rehash()
+ self.update_witness_block_with_transactions(block_5, [tx2])
+ test_witness_block(self.nodes[0], self.test_node, block_5, accepted=True)
+
+ # TODO: test p2sh sigop counting
if __name__ == '__main__':
SegWitTest().main()
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index ff377721cb..c7ae57de86 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test behavior of headers messages to announce blocks.
@@ -86,11 +86,10 @@ e. Announce one more that doesn't connect.
Expect: disconnect.
"""
from test_framework.blocktools import create_block, create_coinbase
+from test_framework.messages import CInv
from test_framework.mininode import (
CBlockHeader,
- CInv,
NODE_WITNESS,
- network_thread_start,
P2PInterface,
mininode_lock,
msg_block,
@@ -214,7 +213,7 @@ class SendHeadersTest(BitcoinTestFramework):
# Clear out block announcements from each p2p listener
[x.clear_block_announcements() for x in self.nodes[0].p2ps]
- self.nodes[0].generate(count)
+ self.nodes[0].generatetoaddress(count, self.nodes[0].get_deterministic_priv_key().address)
return int(self.nodes[0].getbestblockhash(), 16)
def mine_reorg(self, length):
@@ -224,7 +223,8 @@ class SendHeadersTest(BitcoinTestFramework):
to-be-reorged-out blocks are mined, so that we don't break later tests.
return the list of block hashes newly mined."""
- self.nodes[0].generate(length) # make sure all invalidated blocks are node0's
+ # make sure all invalidated blocks are node0's
+ self.nodes[0].generatetoaddress(length, self.nodes[0].get_deterministic_priv_key().address)
sync_blocks(self.nodes, wait=0.1)
for x in self.nodes[0].p2ps:
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
@@ -233,23 +233,17 @@ class SendHeadersTest(BitcoinTestFramework):
tip_height = self.nodes[1].getblockcount()
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
self.nodes[1].invalidateblock(hash_to_invalidate)
- all_hashes = self.nodes[1].generate(length + 1) # Must be longer than the orig chain
+ all_hashes = self.nodes[1].generatetoaddress(length + 1, self.nodes[1].get_deterministic_priv_key().address) # Must be longer than the orig chain
sync_blocks(self.nodes, wait=0.1)
return [int(x, 16) for x in all_hashes]
def run_test(self):
- # Setup the p2p connections and start up the network thread.
+ # Setup the p2p connections
inv_node = self.nodes[0].add_p2p_connection(BaseNode())
# Make sure NODE_NETWORK is not set for test_node, so no block download
# will occur outside of direct fetching
test_node = self.nodes[0].add_p2p_connection(BaseNode(), services=NODE_WITNESS)
- network_thread_start()
-
- # Test logic begins here
- inv_node.wait_for_verack()
- test_node.wait_for_verack()
-
# Ensure verack's have been processed by our peer
inv_node.sync_with_ping()
test_node.sync_with_ping()
@@ -258,7 +252,7 @@ class SendHeadersTest(BitcoinTestFramework):
self.test_nonnull_locators(test_node, inv_node)
def test_null_locators(self, test_node, inv_node):
- tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
+ tip = self.nodes[0].getblockheader(self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0])
tip_hash = int(tip["hash"], 16)
inv_node.check_last_inv_announcement(inv=[tip_hash])
@@ -288,6 +282,7 @@ class SendHeadersTest(BitcoinTestFramework):
# 1. Mine a block; expect inv announcements each time
self.log.info("Part 1: headers don't start before sendheaders message...")
for i in range(4):
+ self.log.debug("Part 1.{}: starting...".format(i))
old_tip = tip
tip = self.mine_blocks(1)
inv_node.check_last_inv_announcement(inv=[tip])
@@ -305,6 +300,7 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.clear_block_announcements() # since we requested headers...
elif i == 2:
# this time announce own block via headers
+ inv_node.clear_block_announcements()
height = self.nodes[0].getblockcount()
last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time']
block_time = last_time + 1
@@ -314,6 +310,7 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.wait_for_getdata([new_block.sha256])
test_node.send_message(msg_block(new_block))
test_node.sync_with_ping() # make sure this block is processed
+ wait_until(lambda: inv_node.block_announced, timeout=60, lock=mininode_lock)
inv_node.clear_block_announcements()
test_node.clear_block_announcements()
@@ -335,11 +332,13 @@ class SendHeadersTest(BitcoinTestFramework):
height = self.nodes[0].getblockcount() + 1
block_time += 10 # Advance far enough ahead
for i in range(10):
+ self.log.debug("Part 2.{}: starting...".format(i))
# Mine i blocks, and alternate announcing either via
# inv (of tip) or via headers. After each, new blocks
# mined by the node should successfully be announced
# with block header, even though the blocks are never requested
for j in range(2):
+ self.log.debug("Part 2.{}.{}: starting...".format(i, j))
blocks = []
for b in range(i + 1):
blocks.append(create_block(tip, create_coinbase(height), block_time))
@@ -386,6 +385,7 @@ class SendHeadersTest(BitcoinTestFramework):
# PART 3. Headers announcements can stop after large reorg, and resume after
# getheaders or inv from peer.
for j in range(2):
+ self.log.debug("Part 3.{}: starting...".format(j))
# First try mining a reorg that can propagate with header announcement
new_block_hashes = self.mine_reorg(length=7)
tip = new_block_hashes[-1]
@@ -412,23 +412,28 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.wait_for_block(new_block_hashes[-1])
for i in range(3):
+ self.log.debug("Part 3.{}.{}: starting...".format(j, i))
+
# Mine another block, still should get only an inv
tip = self.mine_blocks(1)
inv_node.check_last_inv_announcement(inv=[tip])
test_node.check_last_inv_announcement(inv=[tip])
if i == 0:
- self.log.debug("Just get the data -- shouldn't cause headers announcements to resume")
+ # Just get the data -- shouldn't cause headers announcements to resume
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
elif i == 1:
- self.log.debug("Send a getheaders message that shouldn't trigger headers announcements to resume (best header sent will be too old)")
+ # Send a getheaders message that shouldn't trigger headers announcements
+ # to resume (best header sent will be too old)
test_node.send_get_headers(locator=[fork_point], hashstop=new_block_hashes[1])
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
elif i == 2:
+ # This time, try sending either a getheaders to trigger resumption
+ # of headers announcements, or mine a new block and inv it, also
+ # triggering resumption of headers announcements.
test_node.send_get_data([tip])
test_node.wait_for_block(tip)
- self.log.debug("This time, try sending either a getheaders to trigger resumption of headers announcements, or mine a new block and inv it, also triggering resumption of headers announcements.")
if j == 0:
test_node.send_get_headers(locator=[tip], hashstop=0)
test_node.sync_with_ping()
@@ -532,6 +537,7 @@ class SendHeadersTest(BitcoinTestFramework):
# First we test that receipt of an unconnecting header doesn't prevent
# chain sync.
for i in range(10):
+ self.log.debug("Part 5.{}: starting...".format(i))
test_node.last_message.pop("getdata", None)
blocks = []
# Create two more blocks.
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index 6a21b693b4..2459a9f243 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test various net timeouts.
@@ -23,9 +23,9 @@
from time import sleep
-from test_framework.mininode import *
+from test_framework.messages import msg_ping
+from test_framework.mininode import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
class TestP2PConn(P2PInterface):
def on_version(self, message):
@@ -38,18 +38,16 @@ class TimeoutsTest(BitcoinTestFramework):
self.num_nodes = 1
def run_test(self):
- # Setup the p2p connections and start up the network thread.
+ # Setup the p2p connections
no_verack_node = self.nodes[0].add_p2p_connection(TestP2PConn())
- no_version_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False)
- no_send_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False)
-
- network_thread_start()
+ no_version_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)
+ no_send_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)
sleep(1)
- assert no_verack_node.connected
- assert no_version_node.connected
- assert no_send_node.connected
+ assert no_verack_node.is_connected
+ assert no_version_node.is_connected
+ assert no_send_node.is_connected
no_verack_node.send_message(msg_ping())
no_version_node.send_message(msg_ping())
@@ -58,18 +56,18 @@ class TimeoutsTest(BitcoinTestFramework):
assert "version" in no_verack_node.last_message
- assert no_verack_node.connected
- assert no_version_node.connected
- assert no_send_node.connected
+ assert no_verack_node.is_connected
+ assert no_version_node.is_connected
+ assert no_send_node.is_connected
no_verack_node.send_message(msg_ping())
no_version_node.send_message(msg_ping())
sleep(31)
- assert not no_verack_node.connected
- assert not no_version_node.connected
- assert not no_send_node.connected
+ assert not no_verack_node.is_connected
+ assert not no_version_node.is_connected
+ assert not no_send_node.is_connected
if __name__ == '__main__':
TimeoutsTest().main()
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 49c619a4ce..11299cbc00 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test processing of unrequested blocks.
@@ -51,11 +51,13 @@ Node1 is unused in tests 3-7:
work on its chain).
"""
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
import time
-from test_framework.blocktools import create_block, create_coinbase, create_transaction
+
+from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
+from test_framework.messages import CBlockHeader, CInv, msg_block, msg_headers, msg_inv
+from test_framework.mininode import mininode_lock, P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, sync_blocks
class AcceptBlockTest(BitcoinTestFramework):
@@ -73,21 +75,15 @@ class AcceptBlockTest(BitcoinTestFramework):
self.setup_nodes()
def run_test(self):
- # Setup the p2p connections and start up the network thread.
+ # Setup the p2p connections
# test_node connects to node0 (not whitelisted)
test_node = self.nodes[0].add_p2p_connection(P2PInterface())
# min_work_node connects to node1 (whitelisted)
min_work_node = self.nodes[1].add_p2p_connection(P2PInterface())
- network_thread_start()
-
- # Test logic begins here
- test_node.wait_for_verack()
- min_work_node.wait_for_verack()
-
# 1. Have nodes mine a block (leave IBD)
- [ n.generate(1) for n in self.nodes ]
- tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ]
+ [n.generatetoaddress(1, n.get_deterministic_priv_key().address) for n in self.nodes]
+ tips = [int("0x" + n.getbestblockhash(), 0) for n in self.nodes]
# 2. Send one block that builds on each tip.
# This should be accepted by node0
@@ -204,11 +200,8 @@ class AcceptBlockTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
self.nodes[1].disconnect_p2ps()
- network_thread_join()
test_node = self.nodes[0].add_p2p_connection(P2PInterface())
- network_thread_start()
- test_node.wait_for_verack()
test_node.send_message(msg_block(block_h1f))
@@ -250,7 +243,7 @@ class AcceptBlockTest(BitcoinTestFramework):
block_290f.solve()
block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1)
# block_291 spends a coinbase below maturity!
- block_291.vtx.append(create_transaction(block_290f.vtx[0], 0, b"42", 1))
+ block_291.vtx.append(create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1))
block_291.hashMerkleRoot = block_291.calc_merkle_root()
block_291.solve()
block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1)
@@ -294,9 +287,6 @@ class AcceptBlockTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
test_node = self.nodes[0].add_p2p_connection(P2PInterface())
- network_thread_start()
- test_node.wait_for_verack()
-
# We should have failed reorg and switched back to 290 (but have block 291)
assert_equal(self.nodes[0].getblockcount(), 290)
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py
index 343e162058..53916d5290 100755
--- a/test/functional/rpc_bind.py
+++ b/test/functional/rpc_bind.py
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test running bitcoind with the -rpcbind and -rpcallowip options."""
import sys
+from test_framework.netutil import all_interfaces, addr_to_hex, get_bind_addrs, test_ipv6_local
from test_framework.test_framework import BitcoinTestFramework, SkipTest
-from test_framework.util import *
-from test_framework.netutil import *
+from test_framework.util import assert_equal, assert_raises_rpc_error, get_rpc_proxy, rpc_port, rpc_url
class RPCBindTest(BitcoinTestFramework):
def set_test_params(self):
@@ -20,9 +20,9 @@ class RPCBindTest(BitcoinTestFramework):
self.add_nodes(self.num_nodes, None)
def add_options(self, parser):
- parser.add_option("--ipv4", action='store_true', dest="run_ipv4", help="Run ipv4 tests only", default=False)
- parser.add_option("--ipv6", action='store_true', dest="run_ipv6", help="Run ipv6 tests only", default=False)
- parser.add_option("--nonloopback", action='store_true', dest="run_nonloopback", help="Run non-loopback tests only", default=False)
+ parser.add_argument("--ipv4", action='store_true', dest="run_ipv4", help="Run ipv4 tests only", default=False)
+ parser.add_argument("--ipv6", action='store_true', dest="run_ipv6", help="Run ipv6 tests only", default=False)
+ parser.add_argument("--nonloopback", action='store_true', dest="run_nonloopback", help="Run non-loopback tests only", default=False)
def run_bind_test(self, allow_ips, connect_to, addresses, expected):
'''
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index a908596ab3..92b690176d 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPCs related to blockchainstate.
@@ -41,16 +41,16 @@ from test_framework.messages import (
)
from test_framework.mininode import (
P2PInterface,
- network_thread_start,
)
class BlockchainTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-stopatheight=207', '-prune=1']]
def run_test(self):
+ self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete
+
self._test_getblockchaininfo()
self._test_getchaintxstats()
self._test_gettxoutsetinfo()
@@ -172,7 +172,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['transactions'], 200)
assert_equal(res['height'], 200)
assert_equal(res['txouts'], 200)
- assert_equal(res['bogosize'], 17000),
+ assert_equal(res['bogosize'], 15000),
assert_equal(res['bestblock'], node.getblockhash(200))
size = res['disk_size']
assert size > 6400
@@ -197,13 +197,10 @@ class BlockchainTest(BitcoinTestFramework):
node.reconsiderblock(b1hash)
res3 = node.gettxoutsetinfo()
- assert_equal(res['total_amount'], res3['total_amount'])
- assert_equal(res['transactions'], res3['transactions'])
- assert_equal(res['height'], res3['height'])
- assert_equal(res['txouts'], res3['txouts'])
- assert_equal(res['bogosize'], res3['bogosize'])
- assert_equal(res['bestblock'], res3['bestblock'])
- assert_equal(res['hash_serialized_2'], res3['hash_serialized_2'])
+ # The field 'disk_size' is non-deterministic and can thus not be
+ # compared between res and res3. Everything else should be the same.
+ del res['disk_size'], res3['disk_size']
+ assert_equal(res, res3)
def _test_getblockheader(self):
node = self.nodes[0]
@@ -221,6 +218,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(header['confirmations'], 1)
assert_equal(header['previousblockhash'], secondbesthash)
assert_is_hex_string(header['chainwork'])
+ assert_equal(header['nTx'], 1)
assert_is_hash_string(header['hash'])
assert_is_hash_string(header['previousblockhash'])
assert_is_hash_string(header['merkleroot'])
@@ -245,12 +243,12 @@ class BlockchainTest(BitcoinTestFramework):
def _test_stopatheight(self):
assert_equal(self.nodes[0].getblockcount(), 200)
- self.nodes[0].generate(6)
+ self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address)
assert_equal(self.nodes[0].getblockcount(), 206)
self.log.debug('Node should not stop at this height')
assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
try:
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
except (ConnectionError, http.client.BadStatusLine):
pass # The node already shut down before response
self.log.debug('Node should stop at this height...')
@@ -260,13 +258,8 @@ class BlockchainTest(BitcoinTestFramework):
def _test_waitforblockheight(self):
self.log.info("Test waitforblockheight")
-
node = self.nodes[0]
-
- # Start a P2P connection since we'll need to create some blocks.
node.add_p2p_connection(P2PInterface())
- network_thread_start()
- node.p2p.wait_for_verack()
current_height = node.getblock(node.getbestblockhash())['height']
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
new file mode 100755
index 0000000000..3cc35a7b9a
--- /dev/null
+++ b/test/functional/rpc_createmultisig.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test transaction signing using the signrawtransaction* RPCs."""
+
+from test_framework.test_framework import BitcoinTestFramework
+import decimal
+
+class RpcCreateMultiSigTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def get_keys(self):
+ node0, node1, node2 = self.nodes
+ self.add = [node1.getnewaddress() for _ in range(self.nkeys)]
+ self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add]
+ self.priv = [node1.dumpprivkey(a) for a in self.add]
+ self.final = node2.getnewaddress()
+
+ def run_test(self):
+ node0,node1,node2 = self.nodes
+
+ # 50 BTC each, rest will be 25 BTC each
+ node0.generate(149)
+ self.sync_all()
+
+ self.moved = 0
+ for self.nkeys in [3,5]:
+ for self.nsigs in [2,3]:
+ for self.output_type in ["bech32", "p2sh-segwit", "legacy"]:
+ self.get_keys()
+ self.do_multisig()
+
+ self.checkbalances()
+
+ def checkbalances(self):
+ node0,node1,node2 = self.nodes
+ node0.generate(100)
+ self.sync_all()
+
+ bal0 = node0.getbalance()
+ bal1 = node1.getbalance()
+ bal2 = node2.getbalance()
+
+ height = node0.getblockchaininfo()["blocks"]
+ assert 150 < height < 350
+ total = 149*50 + (height-149-100)*25
+ assert bal1 == 0
+ assert bal2 == self.moved
+ assert bal0+bal1+bal2 == total
+
+ def do_multisig(self):
+ node0,node1,node2 = self.nodes
+
+ msig = node2.createmultisig(self.nsigs, self.pub, self.output_type)
+ madd = msig["address"]
+ mredeem = msig["redeemScript"]
+ if self.output_type == 'bech32':
+ assert madd[0:4] == "bcrt" # actually a bech32 address
+
+ # compare against addmultisigaddress
+ msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)
+ maddw = msigw["address"]
+ mredeemw = msigw["redeemScript"]
+ # addmultisigiaddress and createmultisig work the same
+ assert maddw == madd
+ assert mredeemw == mredeem
+
+ txid = node0.sendtoaddress(madd, 40)
+
+ tx = node0.getrawtransaction(txid, True)
+ vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses",[])]
+ assert len(vout) == 1
+ vout = vout[0]
+ scriptPubKey = tx["vout"][vout]["scriptPubKey"]["hex"]
+ value = tx["vout"][vout]["value"]
+ prevtxs = [{"txid": txid, "vout": vout, "scriptPubKey": scriptPubKey, "redeemScript": mredeem, "amount": value}]
+
+ node0.generate(1)
+
+ outval = value - decimal.Decimal("0.00001000")
+ rawtx = node2.createrawtransaction([{"txid": txid, "vout": vout}], [{self.final: outval}])
+
+ rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], prevtxs)
+ rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs)
+
+ self.moved += outval
+ tx = node0.sendrawtransaction(rawtx3["hex"], True)
+ blk = node0.generate(1)[0]
+ assert tx in node0.getblock(blk)["tx"]
+
+ txinfo = node0.getrawtransaction(tx, True, blk)
+ self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"]))
+
+if __name__ == '__main__':
+ RpcCreateMultiSigTest().main()
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index d588151768..940386eee7 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -1,12 +1,13 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test decoding scripts via decodescript RPC command."""
+from test_framework.messages import CTransaction, sha256
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import *
+from test_framework.util import assert_equal, bytes_to_hex_str, hex_str_to_bytes
+
from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index 2e0500e7c4..58074803cc 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -1,16 +1,15 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test deprecation of RPC calls."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_raises_rpc_error
class DeprecatedRpcTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
- self.extra_args = [[], ["-deprecatedrpc=validateaddress", "-deprecatedrpc=accounts"]]
+ self.extra_args = [[], ["-deprecatedrpc=validateaddress"]]
def run_test(self):
# This test should be used to verify correct behaviour of deprecated
@@ -19,95 +18,7 @@ class DeprecatedRpcTest(BitcoinTestFramework):
# self.log.info("Make sure that -deprecatedrpc=createmultisig allows it to take addresses")
# assert_raises_rpc_error(-5, "Invalid public key", self.nodes[0].createmultisig, 1, [self.nodes[0].getnewaddress()])
# self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()])
-
- self.log.info("Test validateaddress deprecation")
- SOME_ADDRESS = "mnvGjUy3NMj67yJ6gkK5o9e5RS33Z2Vqcu" # This is just some random address to pass as a parameter to validateaddress
- dep_validate_address = self.nodes[0].validateaddress(SOME_ADDRESS)
- assert "ismine" not in dep_validate_address
- not_dep_val = self.nodes[1].validateaddress(SOME_ADDRESS)
- assert "ismine" in not_dep_val
-
- self.log.info("Test accounts deprecation")
- # The following account RPC methods are deprecated:
- # - getaccount
- # - getaccountaddress
- # - getaddressesbyaccount
- # - getreceivedbyaccount
- # - listaccouts
- # - listreceivedbyaccount
- # - move
- # - setaccount
- #
- # The following 'label' RPC methods are usable both with and without the
- # -deprecatedrpc=accounts switch enabled.
- # - getlabeladdress
- # - getaddressesbylabel
- # - getreceivedbylabel
- # - listlabels
- # - listreceivedbylabel
- # - setlabel
- #
- address0 = self.nodes[0].getnewaddress()
- self.nodes[0].generatetoaddress(101, address0)
- self.sync_all()
- address1 = self.nodes[1].getnewaddress()
- self.nodes[1].generatetoaddress(101, address1)
-
- self.log.info("- getaccount")
- assert_raises_rpc_error(-32, "getaccount is deprecated", self.nodes[0].getaccount, address0)
- self.nodes[1].getaccount(address1)
-
- self.log.info("- setaccount")
- assert_raises_rpc_error(-32, "setaccount is deprecated", self.nodes[0].setaccount, address0, "label0")
- self.nodes[1].setaccount(address1, "label1")
-
- self.log.info("- setlabel")
- self.nodes[0].setlabel(address0, "label0")
- self.nodes[1].setlabel(address1, "label1")
-
- self.log.info("- getaccountaddress")
- assert_raises_rpc_error(-32, "getaccountaddress is deprecated", self.nodes[0].getaccountaddress, "label0")
- self.nodes[1].getaccountaddress("label1")
-
- self.log.info("- getlabeladdress")
- self.nodes[0].getlabeladdress("label0")
- self.nodes[1].getlabeladdress("label1")
-
- self.log.info("- getaddressesbyaccount")
- assert_raises_rpc_error(-32, "getaddressesbyaccount is deprecated", self.nodes[0].getaddressesbyaccount, "label0")
- self.nodes[1].getaddressesbyaccount("label1")
-
- self.log.info("- getaddressesbylabel")
- self.nodes[0].getaddressesbylabel("label0")
- self.nodes[1].getaddressesbylabel("label1")
-
- self.log.info("- getreceivedbyaccount")
- assert_raises_rpc_error(-32, "getreceivedbyaccount is deprecated", self.nodes[0].getreceivedbyaccount, "label0")
- self.nodes[1].getreceivedbyaccount("label1")
-
- self.log.info("- getreceivedbylabel")
- self.nodes[0].getreceivedbylabel("label0")
- self.nodes[1].getreceivedbylabel("label1")
-
- self.log.info("- listaccounts")
- assert_raises_rpc_error(-32, "listaccounts is deprecated", self.nodes[0].listaccounts)
- self.nodes[1].listaccounts()
-
- self.log.info("- listlabels")
- self.nodes[0].listlabels()
- self.nodes[1].listlabels()
-
- self.log.info("- listreceivedbyaccount")
- assert_raises_rpc_error(-32, "listreceivedbyaccount is deprecated", self.nodes[0].listreceivedbyaccount)
- self.nodes[1].listreceivedbyaccount()
-
- self.log.info("- listreceivedbylabel")
- self.nodes[0].listreceivedbylabel()
- self.nodes[1].listreceivedbylabel()
-
- self.log.info("- move")
- assert_raises_rpc_error(-32, "move is deprecated", self.nodes[0].move, "label0", "label0b", 10)
- self.nodes[1].move("label1", "label1b", 10)
+ pass
if __name__ == '__main__':
DeprecatedRpcTest().main()
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 1e91cf598c..0c61e9ab62 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the fundrawtransaction RPC."""
@@ -29,6 +29,9 @@ class RawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
self.setup_nodes()
@@ -475,10 +478,8 @@ class RawTransactionsTest(BitcoinTestFramework):
############################################################
# locked wallet test
- self.stop_node(0)
- self.nodes[1].node_encrypt_wallet("test")
- self.stop_node(2)
- self.stop_node(3)
+ self.nodes[1].encryptwallet("test")
+ self.stop_nodes()
self.start_nodes()
# This test is not meant to test fee estimation and we'd like
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 060a2373b1..b24bed6adf 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -27,7 +27,7 @@ class GetblockstatsTest(BitcoinTestFramework):
'maxfee',
'maxfeerate',
'medianfee',
- 'medianfeerate',
+ 'feerate_percentiles',
'minfee',
'minfeerate',
'totalfee',
@@ -35,13 +35,13 @@ class GetblockstatsTest(BitcoinTestFramework):
]
def add_options(self, parser):
- parser.add_option('--gen-test-data', dest='gen_test_data',
- default=False, action='store_true',
- help='Generate test data')
- parser.add_option('--test-data', dest='test_data',
- default='data/rpc_getblockstats.json',
- action='store', metavar='FILE',
- help='Test data file')
+ parser.add_argument('--gen-test-data', dest='gen_test_data',
+ default=False, action='store_true',
+ help='Generate test data')
+ parser.add_argument('--test-data', dest='test_data',
+ default='data/rpc_getblockstats.json',
+ action='store', metavar='FILE',
+ help='Test data file')
def set_test_params(self):
self.num_nodes = 2
@@ -81,11 +81,11 @@ class GetblockstatsTest(BitcoinTestFramework):
'mocktime': int(mocktime),
'stats': self.expected_stats,
}
- with open(filename, 'w') as f:
+ with open(filename, 'w', encoding="utf8") as f:
json.dump(to_dump, f, sort_keys=True, indent=2)
def load_test_data(self, filename):
- with open(filename, 'r') as f:
+ with open(filename, 'r', encoding="utf8") as f:
d = json.load(f)
blocks = d['blocks']
mocktime = d['mocktime']
diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py
index 277930bb1a..c869c7262f 100755
--- a/test/functional/rpc_getchaintips.py
+++ b/test/functional/rpc_getchaintips.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the getchaintips RPC.
@@ -17,17 +17,17 @@ class GetChainTipsTest (BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
- def run_test (self):
- tips = self.nodes[0].getchaintips ()
- assert_equal (len (tips), 1)
- assert_equal (tips[0]['branchlen'], 0)
- assert_equal (tips[0]['height'], 200)
- assert_equal (tips[0]['status'], 'active')
+ def run_test(self):
+ tips = self.nodes[0].getchaintips()
+ assert_equal(len(tips), 1)
+ assert_equal(tips[0]['branchlen'], 0)
+ assert_equal(tips[0]['height'], 200)
+ assert_equal(tips[0]['status'], 'active')
# Split the network and build two chains of different lengths.
- self.split_network ()
- self.nodes[0].generate(10)
- self.nodes[2].generate(20)
+ self.split_network()
+ self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
+ self.nodes[2].generatetoaddress(20, self.nodes[2].get_deterministic_priv_key().address)
self.sync_all([self.nodes[:2], self.nodes[2:]])
tips = self.nodes[1].getchaintips ()
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
new file mode 100755
index 0000000000..be096af892
--- /dev/null
+++ b/test/functional/rpc_help.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test RPC help output."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error
+
+
+class HelpRpcTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ node = self.nodes[0]
+
+ # wrong argument count
+ assert_raises_rpc_error(-1, 'help', node.help, 'foo', 'bar')
+
+ # invalid argument
+ assert_raises_rpc_error(-1, 'JSON value is not a string as expected', node.help, 0)
+
+ # help of unknown command
+ assert_equal(node.help('foo'), 'help: unknown command: foo')
+
+ # command titles
+ titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
+
+ components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util']
+
+ if self.is_wallet_compiled():
+ components.append('Wallet')
+
+ if self.is_zmq_compiled():
+ components.append('Zmq')
+
+ assert_equal(titles, components)
+
+
+if __name__ == '__main__':
+ HelpRpcTest().main()
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index b037c2431d..d8ecdd573a 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the invalidateblock RPC."""
+import time
+
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, connect_nodes_bi, sync_blocks
class InvalidateTest(BitcoinTestFramework):
def set_test_params(self):
@@ -18,12 +20,12 @@ class InvalidateTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
self.log.info("Mine 4 blocks on Node 0")
- self.nodes[0].generate(4)
+ self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address)
assert(self.nodes[0].getblockcount() == 4)
besthash = self.nodes[0].getbestblockhash()
self.log.info("Mine competing 6 blocks on Node 1")
- self.nodes[1].generate(6)
+ self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address)
assert(self.nodes[1].getblockcount() == 6)
self.log.info("Connect nodes to force a reorg")
@@ -51,7 +53,7 @@ class InvalidateTest(BitcoinTestFramework):
self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3))
assert(self.nodes[2].getblockcount() == 2)
self.log.info("..and then mine a block")
- self.nodes[2].generate(1)
+ self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address)
self.log.info("Verify all nodes are at the right height")
time.sleep(5)
assert_equal(self.nodes[2].getblockcount(), 3)
diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py
index 97bee39614..6c5c29dfdf 100755
--- a/test/functional/rpc_named_arguments.py
+++ b/test/functional/rpc_named_arguments.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test using named arguments for RPCs."""
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 72b5f4748f..1e525214fa 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC calls related to net.
@@ -7,20 +7,26 @@
Tests correspond to code in rpc/net.cpp.
"""
+from decimal import Decimal
+
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_greater_than_or_equal,
+ assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
p2p_port,
wait_until,
)
+from test_framework.mininode import P2PInterface
+from test_framework.messages import CAddress, msg_addr, NODE_NETWORK, NODE_WITNESS
class NetTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
+ self.extra_args = [["-minrelaytxfee=0.00001000"],["-minrelaytxfee=0.00000500"]]
def run_test(self):
self._test_connection_count()
@@ -28,6 +34,7 @@ class NetTest(BitcoinTestFramework):
self._test_getnetworkinginfo()
self._test_getaddednodeinfo()
self._test_getpeerinfo()
+ self._test_getnodeaddresses()
def _test_connection_count(self):
# connect_nodes_bi connects each node to the other
@@ -95,6 +102,43 @@ class NetTest(BitcoinTestFramework):
# the address bound to on one side will be the source address for the other node
assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])
assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])
+ assert_equal(peer_info[0][0]['minfeefilter'], Decimal("0.00000500"))
+ assert_equal(peer_info[1][0]['minfeefilter'], Decimal("0.00001000"))
+
+ def _test_getnodeaddresses(self):
+ self.nodes[0].add_p2p_connection(P2PInterface())
+
+ # send some addresses to the node via the p2p message addr
+ msg = msg_addr()
+ imported_addrs = []
+ for i in range(256):
+ a = "123.123.123.{}".format(i)
+ imported_addrs.append(a)
+ addr = CAddress()
+ addr.time = 100000000
+ addr.nServices = NODE_NETWORK | NODE_WITNESS
+ addr.ip = a
+ addr.port = 8333
+ msg.addrs.append(addr)
+ self.nodes[0].p2p.send_and_ping(msg)
+
+ # obtain addresses via rpc call and check they were ones sent in before
+ REQUEST_COUNT = 10
+ node_addresses = self.nodes[0].getnodeaddresses(REQUEST_COUNT)
+ assert_equal(len(node_addresses), REQUEST_COUNT)
+ for a in node_addresses:
+ assert_greater_than(a["time"], 1527811200) # 1st June 2018
+ assert_equal(a["services"], NODE_NETWORK | NODE_WITNESS)
+ assert a["address"] in imported_addrs
+ assert_equal(a["port"], 8333)
+
+ assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1)
+
+ # addrman's size cannot be known reliably after insertion, as hash collisions may occur
+ # so only test that requesting a large number of addresses returns less than that
+ LARGE_REQUEST_COUNT = 10000
+ node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT)
+ assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses))
if __name__ == '__main__':
NetTest().main()
diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py
index 796a2edbef..72e6e6329f 100755
--- a/test/functional/rpc_preciousblock.py
+++ b/test/functional/rpc_preciousblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the preciousblock RPC."""
@@ -43,18 +43,19 @@ class PreciousTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Ensure submitblock can in principle reorg to a competing chain")
- self.nodes[0].generate(1)
+ gen_address = lambda i: self.nodes[i].get_deterministic_priv_key().address # A non-wallet address to mine to
+ self.nodes[0].generatetoaddress(1, gen_address(0))
assert_equal(self.nodes[0].getblockcount(), 1)
- hashZ = self.nodes[1].generate(2)[-1]
+ hashZ = self.nodes[1].generatetoaddress(2, gen_address(1))[-1]
assert_equal(self.nodes[1].getblockcount(), 2)
node_sync_via_rpc(self.nodes[0:3])
assert_equal(self.nodes[0].getbestblockhash(), hashZ)
self.log.info("Mine blocks A-B-C on Node 0")
- hashC = self.nodes[0].generate(3)[-1]
+ hashC = self.nodes[0].generatetoaddress(3, gen_address(0))[-1]
assert_equal(self.nodes[0].getblockcount(), 5)
self.log.info("Mine competing blocks E-F-G on Node 1")
- hashG = self.nodes[1].generate(3)[-1]
+ hashG = self.nodes[1].generatetoaddress(3, gen_address(1))[-1]
assert_equal(self.nodes[1].getblockcount(), 5)
assert(hashC != hashG)
self.log.info("Connect nodes and check no reorg occurs")
@@ -83,7 +84,7 @@ class PreciousTest(BitcoinTestFramework):
self.nodes[1].preciousblock(hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashC)
self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, gen_address(0))
assert_equal(self.nodes[0].getblockcount(), 6)
sync_blocks(self.nodes[0:2])
hashH = self.nodes[0].getbestblockhash()
@@ -92,7 +93,7 @@ class PreciousTest(BitcoinTestFramework):
self.nodes[1].preciousblock(hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashH)
self.log.info("Mine competing blocks I-J-K-L on Node 2")
- self.nodes[2].generate(4)
+ self.nodes[2].generatetoaddress(4, gen_address(2))
assert_equal(self.nodes[2].getblockcount(), 6)
hashL = self.nodes[2].getbestblockhash()
self.log.info("Connect nodes and check no reorg occurs")
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
new file mode 100755
index 0000000000..54dc871448
--- /dev/null
+++ b/test/functional/rpc_psbt.py
@@ -0,0 +1,229 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test the Partially Signed Transaction RPCs.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error, find_output
+
+import json
+import os
+
+MAX_BIP125_RBF_SEQUENCE = 0xfffffffd
+
+# Create one-input, one-output, no-fee transaction:
+class PSBTTest(BitcoinTestFramework):
+
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 3
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ # Create and fund a raw tx for sending 10 BTC
+ psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt']
+
+ # Node 1 should not be able to add anything to it but still return the psbtx same as before
+ psbtx = self.nodes[1].walletprocesspsbt(psbtx1)['psbt']
+ assert_equal(psbtx1, psbtx)
+
+ # Sign the transaction and send
+ signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']
+ final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
+ self.nodes[0].sendrawtransaction(final_tx)
+
+ # Create p2sh, p2wpkh, and p2wsh addresses
+ pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey']
+ pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']
+ pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey']
+ p2sh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "legacy")['address']
+ p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "bech32")['address']
+ p2sh_p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], "", "p2sh-segwit")['address']
+ p2wpkh = self.nodes[1].getnewaddress("", "bech32")
+ p2pkh = self.nodes[1].getnewaddress("", "legacy")
+ p2sh_p2wpkh = self.nodes[1].getnewaddress("", "p2sh-segwit")
+
+ # fund those addresses
+ rawtx = self.nodes[0].createrawtransaction([], {p2sh:10, p2wsh:10, p2wpkh:10, p2sh_p2wsh:10, p2sh_p2wpkh:10, p2pkh:10})
+ rawtx = self.nodes[0].fundrawtransaction(rawtx, {"changePosition":3})
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])['hex']
+ txid = self.nodes[0].sendrawtransaction(signed_tx)
+ self.nodes[0].generate(6)
+ self.sync_all()
+
+ # Find the output pos
+ p2sh_pos = -1
+ p2wsh_pos = -1
+ p2wpkh_pos = -1
+ p2pkh_pos = -1
+ p2sh_p2wsh_pos = -1
+ p2sh_p2wpkh_pos = -1
+ decoded = self.nodes[0].decoderawtransaction(signed_tx)
+ for out in decoded['vout']:
+ if out['scriptPubKey']['addresses'][0] == p2sh:
+ p2sh_pos = out['n']
+ elif out['scriptPubKey']['addresses'][0] == p2wsh:
+ p2wsh_pos = out['n']
+ elif out['scriptPubKey']['addresses'][0] == p2wpkh:
+ p2wpkh_pos = out['n']
+ elif out['scriptPubKey']['addresses'][0] == p2sh_p2wsh:
+ p2sh_p2wsh_pos = out['n']
+ elif out['scriptPubKey']['addresses'][0] == p2sh_p2wpkh:
+ p2sh_p2wpkh_pos = out['n']
+ elif out['scriptPubKey']['addresses'][0] == p2pkh:
+ p2pkh_pos = out['n']
+
+ # spend single key from node 1
+ rawtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']
+ walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(rawtx)
+ assert_equal(walletprocesspsbt_out['complete'], True)
+ self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])
+
+ # partially sign multisig things with node 1
+ psbtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']
+ walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
+ psbtx = walletprocesspsbt_out['psbt']
+ assert_equal(walletprocesspsbt_out['complete'], False)
+
+ # partially sign with node 2. This should be complete and sendable
+ walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)
+ assert_equal(walletprocesspsbt_out['complete'], True)
+ self.nodes[2].sendrawtransaction(self.nodes[2].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])
+
+ # check that walletprocesspsbt fails to decode a non-psbt
+ rawtx = self.nodes[1].createrawtransaction([{"txid":txid,"vout":p2wpkh_pos}], {self.nodes[1].getnewaddress():9.99})
+ assert_raises_rpc_error(-22, "TX decode failed", self.nodes[1].walletprocesspsbt, rawtx)
+
+ # Convert a non-psbt to psbt and make sure we can decode it
+ rawtx = self.nodes[0].createrawtransaction([], {self.nodes[1].getnewaddress():10})
+ rawtx = self.nodes[0].fundrawtransaction(rawtx)
+ new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
+ self.nodes[0].decodepsbt(new_psbt)
+
+ # Make sure that a psbt with signatures cannot be converted
+ signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
+ assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex'])
+
+ # Explicitly allow converting non-empty txs
+ new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
+ self.nodes[0].decodepsbt(new_psbt)
+
+ # Create outputs to nodes 1 and 2
+ node1_addr = self.nodes[1].getnewaddress()
+ node2_addr = self.nodes[2].getnewaddress()
+ txid1 = self.nodes[0].sendtoaddress(node1_addr, 13)
+ txid2 =self.nodes[0].sendtoaddress(node2_addr, 13)
+ self.nodes[0].generate(6)
+ self.sync_all()
+ vout1 = find_output(self.nodes[1], txid1, 13)
+ vout2 = find_output(self.nodes[2], txid2, 13)
+
+ # Create a psbt spending outputs from nodes 1 and 2
+ psbt_orig = self.nodes[0].createpsbt([{"txid":txid1, "vout":vout1}, {"txid":txid2, "vout":vout2}], {self.nodes[0].getnewaddress():25.999})
+
+ # Update psbts, should only have data for one input and not the other
+ psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
+ psbt1_decoded = self.nodes[0].decodepsbt(psbt1)
+ assert psbt1_decoded['inputs'][0] and not psbt1_decoded['inputs'][1]
+ psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']
+ psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
+ assert not psbt2_decoded['inputs'][0] and psbt2_decoded['inputs'][1]
+
+ # Combine, finalize, and send the psbts
+ combined = self.nodes[0].combinepsbt([psbt1, psbt2])
+ finalized = self.nodes[0].finalizepsbt(combined)['hex']
+ self.nodes[0].sendrawtransaction(finalized)
+ self.nodes[0].generate(6)
+ self.sync_all()
+
+ # Test additional args in walletcreatepsbt
+ # Make sure both pre-included and funded inputs
+ # have the correct sequence numbers based on
+ # replaceable arg
+ block_height = self.nodes[0].getblockcount()
+ unspent = self.nodes[0].listunspent()[0]
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True}, False)
+ decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
+ for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
+ assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
+ assert "bip32_derivs" not in psbt_in
+ assert_equal(decoded_psbt["tx"]["locktime"], block_height+2)
+
+ # Same construction with only locktime set
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height, {}, True)
+ decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
+ for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
+ assert tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE
+ assert "bip32_derivs" in psbt_in
+ assert_equal(decoded_psbt["tx"]["locktime"], block_height)
+
+ # Same construction without optional arguments
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}])
+ decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
+ for tx_in in decoded_psbt["tx"]["vin"]:
+ assert tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE
+ assert_equal(decoded_psbt["tx"]["locktime"], 0)
+
+
+ # BIP 174 Test Vectors
+
+ # Check that unknown values are just passed through
+ unknown_psbt = "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA="
+ unknown_out = self.nodes[0].walletprocesspsbt(unknown_psbt)['psbt']
+ assert_equal(unknown_psbt, unknown_out)
+
+ # Open the data file
+ with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_psbt.json'), encoding='utf-8') as f:
+ d = json.load(f)
+ invalids = d['invalid']
+ valids = d['valid']
+ creators = d['creator']
+ signers = d['signer']
+ combiners = d['combiner']
+ finalizers = d['finalizer']
+ extractors = d['extractor']
+
+ # Invalid PSBTs
+ for invalid in invalids:
+ assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decodepsbt, invalid)
+
+ # Valid PSBTs
+ for valid in valids:
+ self.nodes[0].decodepsbt(valid)
+
+ # Creator Tests
+ for creator in creators:
+ created_tx = self.nodes[0].createpsbt(creator['inputs'], creator['outputs'])
+ assert_equal(created_tx, creator['result'])
+
+ # Signer tests
+ for i, signer in enumerate(signers):
+ self.nodes[2].createwallet("wallet{}".format(i))
+ wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
+ for key in signer['privkeys']:
+ wrpc.importprivkey(key)
+ signed_tx = wrpc.walletprocesspsbt(signer['psbt'])['psbt']
+ assert_equal(signed_tx, signer['result'])
+
+ # Combiner test
+ for combiner in combiners:
+ combined = self.nodes[2].combinepsbt(combiner['combine'])
+ assert_equal(combined, combiner['result'])
+
+ # Finalizer test
+ for finalizer in finalizers:
+ finalized = self.nodes[2].finalizepsbt(finalizer['finalize'], False)['psbt']
+ assert_equal(finalized, finalizer['result'])
+
+ # Extractor test
+ for extractor in extractors:
+ extracted = self.nodes[2].finalizepsbt(extractor['extract'], True)['hex']
+ assert_equal(extracted, extractor['result'])
+
+
+if __name__ == '__main__':
+ PSBTTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index a1bfb00e16..8ed490f552 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the rawtransaction RPCs.
@@ -13,10 +13,11 @@ Test the following RPCs:
"""
from collections import OrderedDict
+from decimal import Decimal
from io import BytesIO
from test_framework.messages import CTransaction, ToHex
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes
class multidict(dict):
"""Dictionary that allows duplicate keys.
@@ -43,6 +44,9 @@ class RawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 3
self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"], ["-addresstype=legacy"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
super().setup_network()
connect_nodes_bi(self.nodes, 0, 2)
@@ -138,6 +142,61 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {'data': '99'}, {'data': '99'}]),
)
+ for type in ["bech32", "p2sh-segwit", "legacy"]:
+ addr = self.nodes[0].getnewaddress("", type)
+ addrinfo = self.nodes[0].getaddressinfo(addr)
+ pubkey = addrinfo["scriptPubKey"]
+
+ self.log.info('sendrawtransaction with missing prevtx info (%s)' %(type))
+
+ # Test `signrawtransactionwithwallet` invalid `prevtxs`
+ inputs = [ {'txid' : txid, 'vout' : 3, 'sequence' : 1000}]
+ outputs = { self.nodes[0].getnewaddress() : 1 }
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+
+ prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
+ succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
+ assert succ["complete"]
+ if type == "legacy":
+ del prevtx["amount"]
+ succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
+ assert succ["complete"]
+
+ if type != "legacy":
+ assert_raises_rpc_error(-3, "Missing amount", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "txid": txid,
+ "scriptPubKey": pubkey,
+ "vout": 3,
+ }
+ ])
+
+ assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "txid": txid,
+ "scriptPubKey": pubkey,
+ "amount": 1,
+ }
+ ])
+ assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "scriptPubKey": pubkey,
+ "vout": 3,
+ "amount": 1,
+ }
+ ])
+ assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "txid": txid,
+ "vout": 3,
+ "amount": 1
+ }
+ ])
+
+ #########################################
+ # sendrawtransaction with missing input #
+ #########################################
+
self.log.info('sendrawtransaction with missing input')
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1}] #won't exists
outputs = { self.nodes[0].getnewaddress() : 4.998 }
@@ -304,7 +363,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# decoderawtransaction tests
# witness transaction
- encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000000000000"
+ encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction
assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
new file mode 100755
index 0000000000..96f9ccdbdb
--- /dev/null
+++ b/test/functional/rpc_scantxoutset.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test the scantxoutset rpc call."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+from decimal import Decimal
+import shutil
+import os
+
+class ScantxoutsetTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ self.log.info("Mining blocks...")
+ self.nodes[0].generate(110)
+
+ addr_P2SH_SEGWIT = self.nodes[0].getnewaddress("", "p2sh-segwit")
+ pubk1 = self.nodes[0].getaddressinfo(addr_P2SH_SEGWIT)['pubkey']
+ addr_LEGACY = self.nodes[0].getnewaddress("", "legacy")
+ pubk2 = self.nodes[0].getaddressinfo(addr_LEGACY)['pubkey']
+ addr_BECH32 = self.nodes[0].getnewaddress("", "bech32")
+ pubk3 = self.nodes[0].getaddressinfo(addr_BECH32)['pubkey']
+ self.nodes[0].sendtoaddress(addr_P2SH_SEGWIT, 0.001)
+ self.nodes[0].sendtoaddress(addr_LEGACY, 0.002)
+ self.nodes[0].sendtoaddress(addr_BECH32, 0.004)
+
+ #send to child keys of tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK
+ self.nodes[0].sendtoaddress("mkHV1C6JLheLoUSSZYk7x3FH5tnx9bu7yc", 0.008) # (m/0'/0'/0')
+ self.nodes[0].sendtoaddress("mipUSRmJAj2KrjSvsPQtnP8ynUon7FhpCR", 0.016) # (m/0'/0'/1')
+ self.nodes[0].sendtoaddress("n37dAGe6Mq1HGM9t4b6rFEEsDGq7Fcgfqg", 0.032) # (m/0'/0'/1500')
+ self.nodes[0].sendtoaddress("mqS9Rpg8nNLAzxFExsgFLCnzHBsoQ3PRM6", 0.064) # (m/0'/0'/0)
+ self.nodes[0].sendtoaddress("mnTg5gVWr3rbhHaKjJv7EEEc76ZqHgSj4S", 0.128) # (m/0'/0'/1)
+ self.nodes[0].sendtoaddress("mketCd6B9U9Uee1iCsppDJJBHfvi6U6ukC", 0.256) # (m/0'/0'/1500)
+ self.nodes[0].sendtoaddress("mj8zFzrbBcdaWXowCQ1oPZ4qioBVzLzAp7", 0.512) # (m/1/1/0')
+ self.nodes[0].sendtoaddress("mfnKpKQEftniaoE1iXuMMePQU3PUpcNisA", 1.024) # (m/1/1/1')
+ self.nodes[0].sendtoaddress("mou6cB1kaP1nNJM1sryW6YRwnd4shTbXYQ", 2.048) # (m/1/1/1500')
+ self.nodes[0].sendtoaddress("mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", 4.096) # (m/1/1/0)
+ self.nodes[0].sendtoaddress("mxp7w7j8S1Aq6L8StS2PqVvtt4HGxXEvdy", 8.192) # (m/1/1/1)
+ self.nodes[0].sendtoaddress("mpQ8rokAhp1TAtJQR6F6TaUmjAWkAWYYBq", 16.384) # (m/1/1/1500)
+
+
+ self.nodes[0].generate(1)
+
+ self.log.info("Stop node, remove wallet, mine again some blocks...")
+ self.stop_node(0)
+ shutil.rmtree(os.path.join(self.nodes[0].datadir, "regtest", 'wallets'))
+ self.start_node(0)
+ self.nodes[0].generate(110)
+
+ self.restart_node(0, ['-nowallet'])
+ self.log.info("Test if we have found the non HD unspent outputs.")
+ assert_equal(self.nodes[0].scantxoutset("start", [ "pkh(" + pubk1 + ")", "pkh(" + pubk2 + ")", "pkh(" + pubk3 + ")"])['total_amount'], Decimal("0.002"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "wpkh(" + pubk1 + ")", "wpkh(" + pubk2 + ")", "wpkh(" + pubk3 + ")"])['total_amount'], Decimal("0.004"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "sh(wpkh(" + pubk1 + "))", "sh(wpkh(" + pubk2 + "))", "sh(wpkh(" + pubk3 + "))"])['total_amount'], Decimal("0.001"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(" + pubk1 + ")", "combo(" + pubk2 + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "addr(" + addr_BECH32 + ")"])['total_amount'], Decimal("0.007"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
+
+ self.log.info("Test extended key derivation.")
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/0h)"])['total_amount'], Decimal("0.008"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/1h)"])['total_amount'], Decimal("0.016"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500')"])['total_amount'], Decimal("0.032"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/0)"])['total_amount'], Decimal("0.064"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/1)"])['total_amount'], Decimal("0.128"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500)"])['total_amount'], Decimal("0.256"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*h)", "range": 1499}])['total_amount'], Decimal("0.024"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/*h)", "range": 1500}])['total_amount'], Decimal("0.056"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])['total_amount'], Decimal("0.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*)", "range": 1500}])['total_amount'], Decimal("0.448"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0')"])['total_amount'], Decimal("0.512"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1')"])['total_amount'], Decimal("1.024"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500h)"])['total_amount'], Decimal("2.048"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])['total_amount'], Decimal("4.096"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1)"])['total_amount'], Decimal("8.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500)"])['total_amount'], Decimal("16.384"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"])['total_amount'], Decimal("4.096"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"])['total_amount'], Decimal("8.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500)"])['total_amount'], Decimal("16.384"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1499}])['total_amount'], Decimal("1.536"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1500}])['total_amount'], Decimal("3.584"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
+
+if __name__ == '__main__':
+ ScantxoutsetTest().main()
diff --git a/test/functional/rpc_signmessage.py b/test/functional/rpc_signmessage.py
index 5b6935ceea..ad0e29b451 100755
--- a/test/functional/rpc_signmessage.py
+++ b/test/functional/rpc_signmessage.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC commands for signing and verifying messages."""
@@ -13,6 +13,9 @@ class SignMessagesTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-addresstype=legacy"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
message = 'This is just a test message'
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index 18829ef4b8..5c07f2ccae 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test transaction signing using the signrawtransaction* RPCs."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error
class SignRawTransactionsTest(BitcoinTestFramework):
@@ -14,6 +14,9 @@ class SignRawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-deprecatedrpc=signrawtransaction"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def successful_signing_test(self):
"""Create and sign a valid raw transaction with one input.
@@ -42,10 +45,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
# 2) No script verification error occurred
assert 'errors' not in rawTxSigned
- # Perform the same test on signrawtransaction
- rawTxSigned2 = self.nodes[0].signrawtransaction(rawTx, inputs, privKeys)
- assert_equal(rawTxSigned, rawTxSigned2)
-
def script_verification_error_test(self):
"""Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.
@@ -112,10 +111,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout'])
assert not rawTxSigned['errors'][0]['witness']
- # Perform same test with signrawtransaction
- rawTxSigned2 = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys)
- assert_equal(rawTxSigned, rawTxSigned2)
-
# Now test signing failure for transaction with input witnesses
p2wpkh_raw_tx = "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
@@ -140,10 +135,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
assert_equal(rawTxSigned['errors'][1]['witness'], ["304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01", "025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"])
assert not rawTxSigned['errors'][0]['witness']
- # Perform same test with signrawtransaction
- rawTxSigned2 = self.nodes[0].signrawtransaction(p2wpkh_raw_tx)
- assert_equal(rawTxSigned, rawTxSigned2)
-
def run_test(self):
self.successful_signing_test()
self.script_verification_error_test()
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index 26abed414a..8913b8698d 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -1,11 +1,12 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test gettxoutproof and verifytxoutproof RPCs."""
+from test_framework.messages import CMerkleBlock, FromHex, ToHex
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes
class MerkleBlockTest(BitcoinTestFramework):
def set_test_params(self):
@@ -14,6 +15,9 @@ class MerkleBlockTest(BitcoinTestFramework):
# Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing
self.extra_args = [[], [], [], ["-txindex"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
connect_nodes(self.nodes[0], 1)
@@ -84,6 +88,27 @@ class MerkleBlockTest(BitcoinTestFramework):
# We can't get a proof if we specify transactions from different blocks
assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[2].gettxoutproof, [txid1, txid3])
+ # Now we'll try tweaking a proof.
+ proof = self.nodes[3].gettxoutproof([txid1, txid2])
+ assert txid1 in self.nodes[0].verifytxoutproof(proof)
+ assert txid2 in self.nodes[1].verifytxoutproof(proof)
+
+ tweaked_proof = FromHex(CMerkleBlock(), proof)
+
+ # Make sure that our serialization/deserialization is working
+ assert txid1 in self.nodes[2].verifytxoutproof(ToHex(tweaked_proof))
+
+ # Check to see if we can go up the merkle tree and pass this off as a
+ # single-transaction block
+ tweaked_proof.txn.nTransactions = 1
+ tweaked_proof.txn.vHash = [tweaked_proof.header.hashMerkleRoot]
+ tweaked_proof.txn.vBits = [True] + [False]*7
+
+ for n in self.nodes:
+ assert not n.verifytxoutproof(ToHex(tweaked_proof))
+
+ # TODO: try more variants, eg transactions at different depths, and
+ # verify that the proofs are invalid
if __name__ == '__main__':
MerkleBlockTest().main()
diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py
index 78236b2393..20b6341550 100755
--- a/test/functional/rpc_uptime.py
+++ b/test/functional/rpc_uptime.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the RPC call related to the uptime command.
diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py
index 1ef59da5ad..102dd22594 100755
--- a/test/functional/rpc_users.py
+++ b/test/functional/rpc_users.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test multiple RPC users."""
@@ -18,6 +18,7 @@ import subprocess
from random import SystemRandom
import string
import configparser
+import sys
class HTTPBasicsTest(BitcoinTestFramework):
@@ -36,7 +37,7 @@ class HTTPBasicsTest(BitcoinTestFramework):
config = configparser.ConfigParser()
config.read_file(open(self.options.configfile))
gen_rpcauth = config['environment']['RPCAUTH']
- p = subprocess.Popen([gen_rpcauth, self.user], stdout=subprocess.PIPE, universal_newlines=True)
+ p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, universal_newlines=True)
lines = p.stdout.read().splitlines()
rpcauth3 = lines[1]
self.password = lines[3]
@@ -59,7 +60,7 @@ class HTTPBasicsTest(BitcoinTestFramework):
#Old authpair
authpair = url.username + ':' + url.password
- #New authpair generated via share/rpcuser tool
+ #New authpair generated via share/rpcauth tool
password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM="
#Second authpair with different username
diff --git a/test/functional/rpc_zmq.py b/test/functional/rpc_zmq.py
new file mode 100755
index 0000000000..bfa6b06f67
--- /dev/null
+++ b/test/functional/rpc_zmq.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test for the ZMQ RPC methods."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class RPCZMQTest(BitcoinTestFramework):
+
+ address = "tcp://127.0.0.1:28332"
+
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_py3_zmq()
+ self.skip_if_no_bitcoind_zmq()
+
+ def run_test(self):
+ self._test_getzmqnotifications()
+
+ def _test_getzmqnotifications(self):
+ self.restart_node(0, extra_args=[])
+ assert_equal(self.nodes[0].getzmqnotifications(), [])
+
+ self.restart_node(0, extra_args=["-zmqpubhashtx=%s" % self.address])
+ assert_equal(self.nodes[0].getzmqnotifications(), [
+ {"type": "pubhashtx", "address": self.address},
+ ])
+
+
+if __name__ == '__main__':
+ RPCZMQTest().main()
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index b076c9dd43..d1fb97b024 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Encode and decode BASE58, P2PKH and P2SH addresses."""
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 5c2b1815e5..35004fb588 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for manipulating blocks and transactions."""
@@ -39,6 +39,7 @@ from .script import (
hash160,
)
from .util import assert_equal
+from io import BytesIO
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
@@ -117,17 +118,41 @@ def create_coinbase(height, pubkey=None):
coinbase.calc_sha256()
return coinbase
-def create_transaction(prevtx, n, sig, value, script_pub_key=CScript()):
- """Create a transaction.
+def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=CScript()):
+ """Return one-input, one-output transaction object
+ spending the prevtx's n-th output with the given amount.
- If the script_pub_key is not specified, make it anyone-can-spend."""
+ Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output.
+ """
tx = CTransaction()
assert(n < len(prevtx.vout))
- tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), sig, 0xffffffff))
- tx.vout.append(CTxOut(value, script_pub_key))
+ tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, 0xffffffff))
+ tx.vout.append(CTxOut(amount, script_pub_key))
tx.calc_sha256()
return tx
+def create_transaction(node, txid, to_address, *, amount):
+ """ Return signed transaction spending the first output of the
+ input txid. Note that the node must be able to sign for the
+ output that is being spent, and the node must not be running
+ multiple wallets.
+ """
+ raw_tx = create_raw_transaction(node, txid, to_address, amount=amount)
+ tx = CTransaction()
+ tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx)))
+ return tx
+
+def create_raw_transaction(node, txid, to_address, *, amount):
+ """ Return raw signed transaction spending the first output of the
+ input txid. Note that the node must be able to sign for the
+ output that is being spent, and the node must not be running
+ multiple wallets.
+ """
+ rawtx = node.createrawtransaction(inputs=[{"txid": txid, "vout": 0}], outputs={to_address: amount})
+ signresult = node.signrawtransactionwithwallet(rawtx)
+ assert_equal(signresult["complete"], True)
+ return signresult['hex']
+
def get_legacy_sigopcount_block(block, accurate=True):
count = 0
for tx in block.vtx:
diff --git a/test/functional/test_framework/coverage.py b/test/functional/test_framework/coverage.py
index f8761f2bb3..7705dd3e4d 100644
--- a/test/functional/test_framework/coverage.py
+++ b/test/functional/test_framework/coverage.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for doing coverage analysis on the RPC interface.
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index ca2e425bd6..0a3907cba4 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2017 The Bitcoin Core developers
+# Copyright (c) 2010-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Bitcoin test framework primitive and message structures
@@ -32,6 +32,7 @@ MY_SUBVERSION = b"/python-mininode-tester:0.0.3/"
MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)
MAX_INV_SZ = 50000
+MAX_LOCATOR_SZ = 101
MAX_BLOCK_BASE_SIZE = 1000000
COIN = 100000000 # 1 btc in satoshis
@@ -42,8 +43,6 @@ NODE_NETWORK = (1 << 0)
# NODE_GETUTXO = (1 << 1)
NODE_BLOOM = (1 << 2)
NODE_WITNESS = (1 << 3)
-NODE_UNSUPPORTED_SERVICE_BIT_5 = (1 << 5)
-NODE_UNSUPPORTED_SERVICE_BIT_7 = (1 << 7)
NODE_NETWORK_LIMITED = (1 << 10)
MSG_TX = 1
@@ -841,6 +840,52 @@ class BlockTransactions():
def __repr__(self):
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
+class CPartialMerkleTree():
+ def __init__(self):
+ self.nTransactions = 0
+ self.vHash = []
+ self.vBits = []
+ self.fBad = False
+
+ def deserialize(self, f):
+ self.nTransactions = struct.unpack("<i", f.read(4))[0]
+ self.vHash = deser_uint256_vector(f)
+ vBytes = deser_string(f)
+ self.vBits = []
+ for i in range(len(vBytes) * 8):
+ self.vBits.append(vBytes[i//8] & (1 << (i % 8)) != 0)
+
+ def serialize(self):
+ r = b""
+ r += struct.pack("<i", self.nTransactions)
+ r += ser_uint256_vector(self.vHash)
+ vBytesArray = bytearray([0x00] * ((len(self.vBits) + 7)//8))
+ for i in range(len(self.vBits)):
+ vBytesArray[i // 8] |= self.vBits[i] << (i % 8)
+ r += ser_string(bytes(vBytesArray))
+ return r
+
+ def __repr__(self):
+ return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits))
+
+class CMerkleBlock():
+ def __init__(self):
+ self.header = CBlockHeader()
+ self.txn = CPartialMerkleTree()
+
+ def deserialize(self, f):
+ self.header.deserialize(f)
+ self.txn.deserialize(f)
+
+ def serialize(self):
+ r = b""
+ r += self.header.serialize()
+ r += self.txn.serialize()
+ return r
+
+ def __repr__(self):
+ return "CMerkleBlock(header=%s, txn=%s)" % (repr(self.header), repr(self.txn))
+
# Objects that correspond to messages on the wire
class msg_version():
@@ -859,28 +904,17 @@ class msg_version():
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
- if self.nVersion == 10300:
- self.nVersion = 300
self.nServices = struct.unpack("<Q", f.read(8))[0]
self.nTime = struct.unpack("<q", f.read(8))[0]
self.addrTo = CAddress()
self.addrTo.deserialize(f, False)
- if self.nVersion >= 106:
- self.addrFrom = CAddress()
- self.addrFrom.deserialize(f, False)
- self.nNonce = struct.unpack("<Q", f.read(8))[0]
- self.strSubVer = deser_string(f)
- else:
- self.addrFrom = None
- self.nNonce = None
- self.strSubVer = None
- self.nStartingHeight = None
+ self.addrFrom = CAddress()
+ self.addrFrom.deserialize(f, False)
+ self.nNonce = struct.unpack("<Q", f.read(8))[0]
+ self.strSubVer = deser_string(f)
- if self.nVersion >= 209:
- self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
- else:
- self.nStartingHeight = None
+ self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
if self.nVersion >= 70001:
# Relay field is optional for version 70001 onwards
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index 7c2125a177..f8caa57250 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2017 The Bitcoin Core developers
+# Copyright (c) 2010-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Bitcoin P2P network half-a-node.
@@ -13,16 +13,15 @@ P2PConnection: A low-level connection object to a node's P2P interface
P2PInterface: A high-level interface object for communicating to a node over P2P
P2PDataStore: A p2p interface class that keeps a store of transactions and blocks
and can respond correctly to getdata and getheaders messages"""
-import asyncore
+import asyncio
from collections import defaultdict
from io import BytesIO
import logging
-import socket
import struct
import sys
import threading
-from test_framework.messages import *
+from test_framework.messages import CBlockHeader, MIN_VERSION_SUPPORTED, msg_addr, msg_block, MSG_BLOCK, msg_blocktxn, msg_cmpctblock, msg_feefilter, msg_getaddr, msg_getblocks, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_mempool, msg_ping, msg_pong, msg_reject, msg_sendcmpct, msg_sendheaders, msg_tx, MSG_TX, MSG_TYPE_MASK, msg_verack, msg_version, NODE_NETWORK, NODE_WITNESS, sha256
from test_framework.util import wait_until
logger = logging.getLogger("TestFramework.mininode")
@@ -57,7 +56,8 @@ MAGIC_BYTES = {
"regtest": b"\xfa\xbf\xb5\xda", # regtest
}
-class P2PConnection(asyncore.dispatcher):
+
+class P2PConnection(asyncio.Protocol):
"""A low-level connection object to a node's P2P interface.
This class is responsible for:
@@ -71,68 +71,59 @@ class P2PConnection(asyncore.dispatcher):
sub-classed and the on_message() callback overridden."""
def __init__(self):
- # All P2PConnections must be created before starting the NetworkThread.
- # assert that the network thread is not running.
- assert not network_thread_running()
+ # The underlying transport of the connection.
+ # Should only call methods on this from the NetworkThread, c.f. call_soon_threadsafe
+ self._transport = None
- super().__init__(map=mininode_socket_map)
+ @property
+ def is_connected(self):
+ return self._transport is not None
def peer_connect(self, dstaddr, dstport, net="regtest"):
+ assert not self.is_connected
self.dstaddr = dstaddr
self.dstport = dstport
- self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- self.sendbuf = b""
+ # The initial message to send after the connection was made:
+ self.on_connection_send_msg = None
self.recvbuf = b""
- self.state = "connecting"
self.network = net
- self.disconnect = False
-
logger.debug('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport))
- try:
- self.connect((dstaddr, dstport))
- except:
- self.handle_close()
+ loop = NetworkThread.network_event_loop
+ conn_gen_unsafe = loop.create_connection(lambda: self, host=self.dstaddr, port=self.dstport)
+ conn_gen = lambda: loop.call_soon_threadsafe(loop.create_task, conn_gen_unsafe)
+ return conn_gen
def peer_disconnect(self):
# Connection could have already been closed by other end.
- if self.state == "connected":
- self.disconnect_node()
+ NetworkThread.network_event_loop.call_soon_threadsafe(lambda: self._transport and self._transport.abort())
# Connection and disconnection methods
- def handle_connect(self):
- """asyncore callback when a connection is opened."""
- if self.state != "connected":
- logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport))
- self.state = "connected"
- self.on_open()
-
- def handle_close(self):
- """asyncore callback when a connection is closed."""
- logger.debug("Closing connection to: %s:%d" % (self.dstaddr, self.dstport))
- self.state = "closed"
+ def connection_made(self, transport):
+ """asyncio callback when a connection is opened."""
+ assert not self._transport
+ logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport))
+ self._transport = transport
+ if self.on_connection_send_msg:
+ self.send_message(self.on_connection_send_msg)
+ self.on_connection_send_msg = None # Never used again
+ self.on_open()
+
+ def connection_lost(self, exc):
+ """asyncio callback when a connection is closed."""
+ if exc:
+ logger.warning("Connection lost to {}:{} due to {}".format(self.dstaddr, self.dstport, exc))
+ else:
+ logger.debug("Closed connection to: %s:%d" % (self.dstaddr, self.dstport))
+ self._transport = None
self.recvbuf = b""
- self.sendbuf = b""
- try:
- self.close()
- except:
- pass
self.on_close()
- def disconnect_node(self):
- """Disconnect the p2p connection.
-
- Called by the test logic thread. Causes the p2p connection
- to be disconnected on the next iteration of the asyncore loop."""
- self.disconnect = True
-
# Socket read methods
- def handle_read(self):
- """asyncore callback when data is read from the socket."""
- t = self.recv(8192)
+ def data_received(self, t):
+ """asyncio callback when data is read from the socket."""
if len(t) > 0:
self.recvbuf += t
self._on_data()
@@ -179,39 +170,31 @@ class P2PConnection(asyncore.dispatcher):
# Socket write methods
- def writable(self):
- """asyncore method to determine whether the handle_write() callback should be called on the next loop."""
- with mininode_lock:
- pre_connection = self.state == "connecting"
- length = len(self.sendbuf)
- return (length > 0 or pre_connection)
-
- def handle_write(self):
- """asyncore callback when data should be written to the socket."""
- with mininode_lock:
- # asyncore does not expose socket connection, only the first read/write
- # event, thus we must check connection manually here to know when we
- # actually connect
- if self.state == "connecting":
- self.handle_connect()
- if not self.writable():
- return
-
- try:
- sent = self.send(self.sendbuf)
- except:
- self.handle_close()
- return
- self.sendbuf = self.sendbuf[sent:]
-
- def send_message(self, message, pushbuf=False):
+ def send_message(self, message):
"""Send a P2P message over the socket.
This method takes a P2P payload, builds the P2P header and adds
the message to the send buffer to be sent over the socket."""
- if self.state != "connected" and not pushbuf:
- raise IOError('Not connected, no pushbuf')
+ if not self.is_connected:
+ raise IOError('Not connected')
self._log_message("send", message)
+ tmsg = self._build_message(message)
+
+ def maybe_write():
+ if not self._transport:
+ return
+ # Python <3.4.4 does not have is_closing, so we have to check for
+ # its existence explicitly as long as Bitcoin Core supports all
+ # Python 3.4 versions.
+ if hasattr(self._transport, 'is_closing') and self._transport.is_closing():
+ return
+ self._transport.write(tmsg)
+ NetworkThread.network_event_loop.call_soon_threadsafe(maybe_write)
+
+ # Class utility methods
+
+ def _build_message(self, message):
+ """Build a serialized P2P message"""
command = message.command
data = message.serialize()
tmsg = MAGIC_BYTES[self.network]
@@ -222,17 +205,7 @@ class P2PConnection(asyncore.dispatcher):
h = sha256(th)
tmsg += h[:4]
tmsg += data
- with mininode_lock:
- if (len(self.sendbuf) == 0 and not pushbuf):
- try:
- sent = self.send(tmsg)
- self.sendbuf = tmsg[sent:]
- except BlockingIOError:
- self.sendbuf = tmsg
- else:
- self.sendbuf += tmsg
-
- # Class utility methods
+ return tmsg
def _log_message(self, direction, msg):
"""Logs a message being sent or received over the connection."""
@@ -270,7 +243,7 @@ class P2PInterface(P2PConnection):
self.nServices = 0
def peer_connect(self, *args, services=NODE_NETWORK|NODE_WITNESS, send_version=True, **kwargs):
- super().peer_connect(*args, **kwargs)
+ create_conn = super().peer_connect(*args, **kwargs)
if send_version:
# Send a version msg
@@ -280,7 +253,9 @@ class P2PInterface(P2PConnection):
vt.addrTo.port = self.dstport
vt.addrFrom.ip = "0.0.0.0"
vt.addrFrom.port = 0
- self.send_message(vt, True)
+ self.on_connection_send_msg = vt # Will be sent soon after connection_made
+
+ return create_conn
# Message receiving methods
@@ -348,7 +323,7 @@ class P2PInterface(P2PConnection):
# Connection helper methods
def wait_for_disconnect(self, timeout=60):
- test_function = lambda: self.state != "connected"
+ test_function = lambda: not self.is_connected
wait_until(test_function, timeout=timeout, lock=mininode_lock)
# Message receiving helper methods
@@ -357,6 +332,15 @@ class P2PInterface(P2PConnection):
test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
wait_until(test_function, timeout=timeout, lock=mininode_lock)
+ def wait_for_header(self, blockhash, timeout=60):
+ def test_function():
+ last_headers = self.last_message.get('headers')
+ if not last_headers:
+ return False
+ return last_headers.headers[0].rehash() == blockhash
+
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
+
def wait_for_getdata(self, timeout=60):
"""Waits for a getdata message.
@@ -404,56 +388,35 @@ class P2PInterface(P2PConnection):
self.ping_counter += 1
-# Keep our own socket map for asyncore, so that we can track disconnects
-# ourselves (to work around an issue with closing an asyncore socket when
-# using select)
-mininode_socket_map = dict()
-
-# One lock for synchronizing all data access between the networking thread (see
+# One lock for synchronizing all data access between the network event loop (see
# NetworkThread below) and the thread running the test logic. For simplicity,
-# P2PConnection acquires this lock whenever delivering a message to a P2PInterface,
-# and whenever adding anything to the send buffer (in send_message()). This
-# lock should be acquired in the thread running the test logic to synchronize
+# P2PConnection acquires this lock whenever delivering a message to a P2PInterface.
+# This lock should be acquired in the thread running the test logic to synchronize
# access to any data shared with the P2PInterface or P2PConnection.
mininode_lock = threading.RLock()
+
class NetworkThread(threading.Thread):
+ network_event_loop = None
+
def __init__(self):
super().__init__(name="NetworkThread")
+ # There is only one event loop and no more than one thread must be created
+ assert not self.network_event_loop
+
+ NetworkThread.network_event_loop = asyncio.new_event_loop()
def run(self):
- while mininode_socket_map:
- # We check for whether to disconnect outside of the asyncore
- # loop to work around the behavior of asyncore when using
- # select
- disconnected = []
- for fd, obj in mininode_socket_map.items():
- if obj.disconnect:
- disconnected.append(obj)
- [obj.handle_close() for obj in disconnected]
- asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1)
- logger.debug("Network thread closing")
-
-def network_thread_start():
- """Start the network thread."""
- # Only one network thread may run at a time
- assert not network_thread_running()
-
- NetworkThread().start()
-
-def network_thread_running():
- """Return whether the network thread is running."""
- return any([thread.name == "NetworkThread" for thread in threading.enumerate()])
-
-def network_thread_join(timeout=10):
- """Wait timeout seconds for the network thread to terminate.
-
- Throw if the network thread doesn't terminate in timeout seconds."""
- network_threads = [thread for thread in threading.enumerate() if thread.name == "NetworkThread"]
- assert len(network_threads) <= 1
- for thread in network_threads:
- thread.join(timeout)
- assert not thread.is_alive()
+ """Start the network thread."""
+ self.network_event_loop.run_forever()
+
+ def close(self, timeout=10):
+ """Close the connections and network event loop."""
+ self.network_event_loop.call_soon_threadsafe(self.network_event_loop.stop)
+ wait_until(lambda: not self.network_event_loop.is_running(), timeout=timeout)
+ self.network_event_loop.close()
+ self.join(timeout)
+
class P2PDataStore(P2PInterface):
"""A P2P data store class.
@@ -462,8 +425,6 @@ class P2PDataStore(P2PInterface):
def __init__(self):
super().__init__()
- self.reject_code_received = None
- self.reject_reason_received = None
# store of blocks. key is block hash, value is a CBlock object
self.block_store = {}
self.last_block_hash = ''
@@ -514,12 +475,7 @@ class P2PDataStore(P2PInterface):
if response is not None:
self.send_message(response)
- def on_reject(self, message):
- """Store reject reason and code for testing."""
- self.reject_code_received = message.code
- self.reject_reason_received = message.reason
-
- def send_blocks_and_test(self, blocks, rpc, success=True, request_block=True, reject_code=None, reject_reason=None, timeout=60):
+ def send_blocks_and_test(self, blocks, node, *, success=True, request_block=True, reject_reason=None, expect_disconnect=False, timeout=60):
"""Send blocks to test node and test whether the tip advances.
- add all blocks to our block_store
@@ -529,66 +485,59 @@ class P2PDataStore(P2PInterface):
ensure that any getdata messages are responded to
- if success is True: assert that the node's tip advances to the most recent block
- if success is False: assert that the node's tip doesn't advance
- - if reject_code and reject_reason are set: assert that the correct reject message is received"""
+ - if reject_reason is set: assert that the correct reject message is logged"""
with mininode_lock:
- self.reject_code_received = None
- self.reject_reason_received = None
-
for block in blocks:
self.block_store[block.sha256] = block
self.last_block_hash = block.sha256
- self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
+ reject_reason = [reject_reason] if reject_reason else []
+ with node.assert_debug_log(expected_msgs=reject_reason):
+ self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
- if request_block:
- wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
+ if request_block:
+ wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
- if success:
- wait_until(lambda: rpc.getbestblockhash() == blocks[-1].hash, timeout=timeout)
- else:
- assert rpc.getbestblockhash() != blocks[-1].hash
+ if expect_disconnect:
+ self.wait_for_disconnect()
+ else:
+ self.sync_with_ping()
- if reject_code is not None:
- wait_until(lambda: self.reject_code_received == reject_code, lock=mininode_lock)
- if reject_reason is not None:
- wait_until(lambda: self.reject_reason_received == reject_reason, lock=mininode_lock)
+ if success:
+ wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout)
+ else:
+ assert node.getbestblockhash() != blocks[-1].hash
- def send_txs_and_test(self, txs, rpc, success=True, expect_disconnect=False, reject_code=None, reject_reason=None):
+ def send_txs_and_test(self, txs, node, *, success=True, expect_disconnect=False, reject_reason=None):
"""Send txs to test node and test whether they're accepted to the mempool.
- add all txs to our tx_store
- send tx messages for all txs
- if success is True/False: assert that the txs are/are not accepted to the mempool
- if expect_disconnect is True: Skip the sync with ping
- - if reject_code and reject_reason are set: assert that the correct reject message is received."""
+ - if reject_reason is set: assert that the correct reject message is logged."""
with mininode_lock:
- self.reject_code_received = None
- self.reject_reason_received = None
-
for tx in txs:
self.tx_store[tx.sha256] = tx
- for tx in txs:
- self.send_message(msg_tx(tx))
-
- if expect_disconnect:
- self.wait_for_disconnect()
- else:
- self.sync_with_ping()
-
- raw_mempool = rpc.getrawmempool()
- if success:
- # Check that all txs are now in the mempool
- for tx in txs:
- assert tx.hash in raw_mempool, "{} not found in mempool".format(tx.hash)
- else:
- # Check that none of the txs are now in the mempool
+ reject_reason = [reject_reason] if reject_reason else []
+ with node.assert_debug_log(expected_msgs=reject_reason):
for tx in txs:
- assert tx.hash not in raw_mempool, "{} tx found in mempool".format(tx.hash)
+ self.send_message(msg_tx(tx))
- if reject_code is not None:
- wait_until(lambda: self.reject_code_received == reject_code, lock=mininode_lock)
- if reject_reason is not None:
- wait_until(lambda: self.reject_reason_received == reject_reason, lock=mininode_lock)
+ if expect_disconnect:
+ self.wait_for_disconnect()
+ else:
+ self.sync_with_ping()
+
+ raw_mempool = node.getrawmempool()
+ if success:
+ # Check that all txs are now in the mempool
+ for tx in txs:
+ assert tx.hash in raw_mempool, "{} not found in mempool".format(tx.hash)
+ else:
+ # Check that none of the txs are now in the mempool
+ for tx in txs:
+ assert tx.hash not in raw_mempool, "{} tx found in mempool".format(tx.hash)
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index 36d1a2f856..45c182f630 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Linux network utilities.
@@ -107,7 +107,7 @@ def all_interfaces():
max_possible *= 2
else:
break
- namestr = names.tostring()
+ namestr = names.tobytes()
return [(namestr[i:i+16].split(b'\0', 1)[0],
socket.inet_ntoa(namestr[i+20:i+24]))
for i in range(0, outbytes, struct_size)]
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 44650d7584..375d6334f7 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Functionality to build scripts, as well as SignatureHash().
@@ -7,7 +7,8 @@
This file is modified from python-bitcoinlib.
"""
-from .mininode import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string
+from .messages import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string
+
from binascii import hexlify
import hashlib
import struct
diff --git a/test/functional/test_framework/siphash.py b/test/functional/test_framework/siphash.py
index 6ffc982cea..85836845d4 100644
--- a/test/functional/test_framework/siphash.py
+++ b/test/functional/test_framework/siphash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Specialized SipHash-2-4 implementations.
diff --git a/test/functional/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index 581de0ed5d..dd0f209268 100644
--- a/test/functional/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Dummy Socks5 server for testing."""
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 75a8986793..9a589240a8 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Base class for RPC testing."""
@@ -7,7 +7,7 @@
import configparser
from enum import Enum
import logging
-import optparse
+import argparse
import os
import pdb
import shutil
@@ -18,6 +18,7 @@ import time
from .authproxy import JSONRPCException
from . import coverage
from .test_node import TestNode
+from .mininode import NetworkThread
from .util import (
MAX_NODES,
PortSeed,
@@ -43,6 +44,13 @@ TEST_EXIT_FAILED = 1
TEST_EXIT_SKIPPED = 77
+class SkipTest(Exception):
+ """This exception is raised to skip a test"""
+
+ def __init__(self, message):
+ self.message = message
+
+
class BitcoinTestMetaClass(type):
"""Metaclass for BitcoinTestFramework.
@@ -83,7 +91,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method"""
self.setup_clean_chain = False
self.nodes = []
+ self.network_thread = None
self.mocktime = 0
+ self.rpc_timewait = 60 # Wait for up to 60 seconds for the RPC server to respond
self.supports_cli = False
self.bind_to_localhost_only = True
self.set_test_params()
@@ -93,31 +103,31 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def main(self):
"""Main function. This should not be overridden by the subclass test scripts."""
- 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("--noshutdown", dest="noshutdown", default=False, action="store_true",
- help="Don't stop bitcoinds after the test execution")
- parser.add_option("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../cache"),
- help="Directory for caching pregenerated datadirs (default: %default)")
- parser.add_option("--tmpdir", dest="tmpdir", help="Root directory for datadirs")
- parser.add_option("-l", "--loglevel", dest="loglevel", default="INFO",
- help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.")
- 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")
- parser.add_option("--configfile", dest="configfile",
- default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../config.ini"),
- help="Location of the test framework config file (default: %default)")
- parser.add_option("--pdbonfailure", dest="pdbonfailure", default=False, action="store_true",
- help="Attach a python debugger if test fails")
- parser.add_option("--usecli", dest="usecli", default=False, action="store_true",
- help="use bitcoin-cli instead of RPC for all commands")
+ parser = argparse.ArgumentParser(usage="%(prog)s [options]")
+ parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true",
+ help="Leave bitcoinds and test.* datadir on exit or error")
+ parser.add_argument("--noshutdown", dest="noshutdown", default=False, action="store_true",
+ help="Don't stop bitcoinds after the test execution")
+ parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../cache"),
+ help="Directory for caching pregenerated datadirs (default: %(default)s)")
+ parser.add_argument("--tmpdir", dest="tmpdir", help="Root directory for datadirs")
+ parser.add_argument("-l", "--loglevel", dest="loglevel", default="INFO",
+ help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.")
+ parser.add_argument("--tracerpc", dest="trace_rpc", default=False, action="store_true",
+ help="Print out all RPC calls as they are made")
+ parser.add_argument("--portseed", dest="port_seed", default=os.getpid(), type=int,
+ help="The seed to use for assigning port numbers (default: current process id)")
+ parser.add_argument("--coveragedir", dest="coveragedir",
+ help="Write tested RPC commands into this directory")
+ parser.add_argument("--configfile", dest="configfile",
+ default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../config.ini"),
+ help="Location of the test framework config file (default: %(default)s)")
+ parser.add_argument("--pdbonfailure", dest="pdbonfailure", default=False, action="store_true",
+ help="Attach a python debugger if test fails")
+ parser.add_argument("--usecli", dest="usecli", default=False, action="store_true",
+ help="use bitcoin-cli instead of RPC for all commands")
self.add_options(parser)
- (self.options, self.args) = parser.parse_args()
+ self.options = parser.parse_args()
PortSeed.n = self.options.port_seed
@@ -144,13 +154,19 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.options.tmpdir = tempfile.mkdtemp(prefix="test")
self._start_logging()
+ self.log.debug('Setting up network thread')
+ self.network_thread = NetworkThread()
+ self.network_thread.start()
+
success = TestStatus.FAILED
try:
if self.options.usecli and not self.supports_cli:
raise SkipTest("--usecli specified but test does not support using CLI")
+ self.skip_test_if_missing_module()
self.setup_chain()
self.setup_network()
+ self.import_deterministic_coinbase_privkeys()
self.run_test()
success = TestStatus.PASSED
except JSONRPCException as e:
@@ -171,6 +187,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
print("Testcase failed. Attaching python debugger. Enter ? for help")
pdb.set_trace()
+ self.log.debug('Closing down network thread')
+ self.network_thread.close()
if not self.options.noshutdown:
self.log.info("Stopping nodes")
if self.nodes:
@@ -211,6 +229,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""Override this method to add command-line options to the test"""
pass
+ def skip_test_if_missing_module(self):
+ """Override this method to skip a test if a module is not compiled"""
+ pass
+
def setup_chain(self):
"""Override this method to customize blockchain setup"""
self.log.info("Initializing test directory " + self.options.tmpdir)
@@ -238,13 +260,26 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.add_nodes(self.num_nodes, extra_args)
self.start_nodes()
+ def import_deterministic_coinbase_privkeys(self):
+ if self.setup_clean_chain:
+ return
+
+ for n in self.nodes:
+ try:
+ n.getwalletinfo()
+ except JSONRPCException as e:
+ assert str(e).startswith('Method not found')
+ continue
+
+ n.importprivkey(n.get_deterministic_priv_key().key)
+
def run_test(self):
"""Tests must override this method to define test logic"""
raise NotImplementedError
# Public helper methods. These can be accessed by the subclass test scripts.
- def add_nodes(self, num_nodes, extra_args=None, rpchost=None, timewait=None, binary=None):
+ def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None):
"""Instantiate TestNode objects"""
if self.bind_to_localhost_only:
extra_confs = [["bind=127.0.0.1"]] * num_nodes
@@ -258,7 +293,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
assert_equal(len(extra_args), num_nodes)
assert_equal(len(binary), num_nodes)
for i in range(num_nodes):
- self.nodes.append(TestNode(i, get_datadir_path(self.options.tmpdir, i), rpchost=rpchost, timewait=timewait, bitcoind=binary[i], bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=self.options.coveragedir, extra_conf=extra_confs[i], extra_args=extra_args[i], use_cli=self.options.usecli))
+ self.nodes.append(TestNode(i, get_datadir_path(self.options.tmpdir, i), rpchost=rpchost, timewait=self.rpc_timewait, bitcoind=binary[i], bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=self.options.coveragedir, extra_conf=extra_confs[i], extra_args=extra_args[i], use_cli=self.options.usecli))
def start_node(self, i, *args, **kwargs):
"""Start a bitcoind"""
@@ -359,7 +394,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.log = logging.getLogger('TestFramework')
self.log.setLevel(logging.DEBUG)
# Create file handler to log all messages
- fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log')
+ fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log', encoding='utf-8')
fh.setLevel(logging.DEBUG)
# Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel.
ch = logging.StreamHandler(sys.stdout)
@@ -406,10 +441,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Create cache directories, run bitcoinds:
for i in range(MAX_NODES):
datadir = initialize_datadir(self.options.cachedir, i)
- args = [self.options.bitcoind, "-datadir=" + datadir]
+ args = [self.options.bitcoind, "-datadir=" + datadir, '-disablewallet']
if i > 0:
args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
- self.nodes.append(TestNode(i, get_datadir_path(self.options.cachedir, i), extra_conf=["bind=127.0.0.1"], extra_args=[], rpchost=None, timewait=None, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=None))
+ self.nodes.append(TestNode(i, get_datadir_path(self.options.cachedir, i), extra_conf=["bind=127.0.0.1"], extra_args=[], rpchost=None, timewait=self.rpc_timewait, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=None))
self.nodes[i].args = args
self.start_node(i)
@@ -430,7 +465,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
for peer in range(4):
for j in range(25):
set_node_times(self.nodes, block_time)
- self.nodes[peer].generate(1)
+ self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key().address)
block_time += 10 * 60
# Must sync before next peer starts generating blocks
sync_blocks(self.nodes)
@@ -444,8 +479,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths)
for i in range(MAX_NODES):
+ os.rmdir(cache_path(i, 'wallets')) # Remove empty wallets dir
for entry in os.listdir(cache_path(i)):
- if entry not in ['wallets', 'chainstate', 'blocks']:
+ if entry not in ['chainstate', 'blocks']:
os.remove(cache_path(i, entry))
for i in range(self.num_nodes):
@@ -462,8 +498,45 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
for i in range(self.num_nodes):
initialize_datadir(self.options.tmpdir, i)
+ def skip_if_no_py3_zmq(self):
+ """Attempt to import the zmq package and skip the test if the import fails."""
+ try:
+ import zmq # noqa
+ except ImportError:
+ raise SkipTest("python3-zmq module not available.")
+
+ def skip_if_no_bitcoind_zmq(self):
+ """Skip the running test if bitcoind has not been compiled with zmq support."""
+ if not self.is_zmq_compiled():
+ raise SkipTest("bitcoind has not been built with zmq enabled.")
+
+ def skip_if_no_wallet(self):
+ """Skip the running test if wallet has not been compiled."""
+ if not self.is_wallet_compiled():
+ raise SkipTest("wallet has not been compiled.")
+
+ def skip_if_no_cli(self):
+ """Skip the running test if bitcoin-cli has not been compiled."""
+ if not self.is_cli_compiled():
+ raise SkipTest("bitcoin-cli has not been compiled.")
+
+ def is_cli_compiled(self):
+ """Checks whether bitcoin-cli was compiled."""
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
-class SkipTest(Exception):
- """This exception is raised to skip a test"""
- def __init__(self, message):
- self.message = message
+ return config["components"].getboolean("ENABLE_UTILS")
+
+ def is_wallet_compiled(self):
+ """Checks whether the wallet module was compiled."""
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
+
+ return config["components"].getboolean("ENABLE_WALLET")
+
+ def is_zmq_compiled(self):
+ """Checks whether the zmq module was compiled."""
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
+
+ return config["components"].getboolean("ENABLE_ZMQ")
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 0353fc0712..7ab7fcfcb4 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Class for bitcoind node under test"""
+import contextlib
import decimal
import errno
from enum import Enum
@@ -15,6 +16,8 @@ import re
import subprocess
import tempfile
import time
+import urllib.parse
+import collections
from .authproxy import JSONRPCException
from .util import (
@@ -56,17 +59,13 @@ class TestNode():
To make things easier for the test writer, any unrecognised messages will
be dispatched to the RPC connection."""
- def __init__(self, i, datadir, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, extra_conf=None, extra_args=None, use_cli=False):
+ def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, extra_conf=None, extra_args=None, use_cli=False):
self.index = i
self.datadir = datadir
self.stdout_dir = os.path.join(self.datadir, "stdout")
self.stderr_dir = os.path.join(self.datadir, "stderr")
self.rpchost = rpchost
- if timewait:
- self.rpc_timeout = timewait
- else:
- # Wait for up to 60 seconds for the RPC server to respond
- self.rpc_timeout = 60
+ self.rpc_timeout = timewait
self.binary = bitcoind
self.coverage_dir = coverage_dir
if extra_conf != None:
@@ -99,6 +98,23 @@ class TestNode():
self.p2ps = []
+ def get_deterministic_priv_key(self):
+ """Return a deterministic priv key in base58, that only depends on the node's index"""
+ AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
+ PRIV_KEYS = [
+ # address , privkey
+ AddressKeyPair('mjTkW3DjgyZck4KbiRusZsqTgaYTxdSz6z', 'cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW'),
+ AddressKeyPair('msX6jQXvxiNhx3Q62PKeLPrhrqZQdSimTg', 'cUxsWyKyZ9MAQTaAhUQWJmBbSvHMwSmuv59KgxQV7oZQU3PXN3KE'),
+ AddressKeyPair('mnonCMyH9TmAsSj3M59DsbH8H63U3RKoFP', 'cTrh7dkEAeJd6b3MRX9bZK8eRmNqVCMH3LSUkE3dSFDyzjU38QxK'),
+ AddressKeyPair('mqJupas8Dt2uestQDvV2NH3RU8uZh2dqQR', 'cVuKKa7gbehEQvVq717hYcbE9Dqmq7KEBKqWgWrYBa2CKKrhtRim'),
+ AddressKeyPair('msYac7Rvd5ywm6pEmkjyxhbCDKqWsVeYws', 'cQDCBuKcjanpXDpCqacNSjYfxeQj8G6CAtH1Dsk3cXyqLNC4RPuh'),
+ AddressKeyPair('n2rnuUnwLgXqf9kk2kjvVm8R5BZK1yxQBi', 'cQakmfPSLSqKHyMFGwAqKHgWUiofJCagVGhiB4KCainaeCSxeyYq'),
+ AddressKeyPair('myzuPxRwsf3vvGzEuzPfK9Nf2RfwauwYe6', 'cQMpDLJwA8DBe9NcQbdoSb1BhmFxVjWD5gRyrLZCtpuF9Zi3a9RK'),
+ AddressKeyPair('mumwTaMtbxEPUswmLBBN3vM9oGRtGBrys8', 'cSXmRKXVcoouhNNVpcNKFfxsTsToY5pvB9DVsFksF1ENunTzRKsy'),
+ AddressKeyPair('mpV7aGShMkJCZgbW7F6iZgrvuPHjZjH9qg', 'cSoXt6tm3pqy43UMabY6eUTmR3eSUYFtB2iNQDGgb3VUnRsQys2k'),
+ ]
+ return PRIV_KEYS[self.index]
+
def _node_msg(self, msg: str) -> str:
"""Return a modified msg that identifies this node by its index as a debugging aid."""
return "[node %d] %s" % (self.index, msg)
@@ -125,7 +141,7 @@ class TestNode():
assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection")
return getattr(self.rpc, name)
- def start(self, extra_args=None, stdout=None, stderr=None, *args, **kwargs):
+ def start(self, extra_args=None, *, stdout=None, stderr=None, **kwargs):
"""Start the node."""
if extra_args is None:
extra_args = self.extra_args
@@ -146,7 +162,7 @@ class TestNode():
# add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal
subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1")
- self.process = subprocess.Popen(self.args + extra_args, env=subp_env, stdout=stdout, stderr=stderr, *args, **kwargs)
+ self.process = subprocess.Popen(self.args + extra_args, env=subp_env, stdout=stdout, stderr=stderr, **kwargs)
self.running = True
self.log.debug("bitcoind started, waiting for RPC to come up")
@@ -184,7 +200,7 @@ class TestNode():
return self.cli("-rpcwallet={}".format(wallet_name))
else:
assert self.rpc_connected and self.rpc, self._node_msg("RPC not connected")
- wallet_path = "wallet/%s" % wallet_name
+ wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name))
return self.rpc / wallet_path
def stop_node(self, expected_stderr=''):
@@ -203,6 +219,9 @@ class TestNode():
if stderr != expected_stderr:
raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr))
+ self.stdout.close()
+ self.stderr.close()
+
del self.p2ps[:]
def is_node_stopped(self):
@@ -229,6 +248,23 @@ class TestNode():
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
wait_until(self.is_node_stopped, timeout=timeout)
+ @contextlib.contextmanager
+ def assert_debug_log(self, expected_msgs):
+ debug_log = os.path.join(self.datadir, 'regtest', 'debug.log')
+ with open(debug_log, encoding='utf-8') as dl:
+ dl.seek(0, 2)
+ prev_size = dl.tell()
+ try:
+ yield
+ finally:
+ with open(debug_log, encoding='utf-8') as dl:
+ dl.seek(prev_size)
+ log = dl.read()
+ print_log = " - " + "\n - ".join(log.splitlines())
+ for expected_msg in expected_msgs:
+ if re.search(re.escape(expected_msg), log, flags=re.MULTILINE) is None:
+ self._raise_assertion_error('Expected message "{}" does not partially match log:\n\n{}\n\n'.format(expected_msg, print_log))
+
def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs):
"""Attempt to start the node and expect it to raise an error.
@@ -271,15 +307,7 @@ class TestNode():
assert_msg = "bitcoind should have exited with expected error " + expected_msg
self._raise_assertion_error(assert_msg)
- def node_encrypt_wallet(self, passphrase):
- """"Encrypts the wallet.
-
- This causes bitcoind to shutdown, so this method takes
- care of cleaning up resources."""
- self.encryptwallet(passphrase)
- self.wait_until_stopped()
-
- def add_p2p_connection(self, p2p_conn, *args, **kwargs):
+ def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):
"""Add a p2p connection to the node.
This method adds the p2p connection to the self.p2ps list and also
@@ -289,8 +317,10 @@ class TestNode():
if 'dstaddr' not in kwargs:
kwargs['dstaddr'] = '127.0.0.1'
- p2p_conn.peer_connect(*args, **kwargs)
+ p2p_conn.peer_connect(**kwargs)()
self.p2ps.append(p2p_conn)
+ if wait_for_verack:
+ p2p_conn.wait_for_verack()
return p2p_conn
@@ -343,16 +373,15 @@ class TestNodeCLI():
def batch(self, requests):
results = []
for request in requests:
- try:
- results.append(dict(result=request()))
- except JSONRPCException as e:
- results.append(dict(error=e))
+ try:
+ results.append(dict(result=request()))
+ except JSONRPCException as e:
+ results.append(dict(error=e))
return results
def send_cli(self, command=None, *args, **kwargs):
"""Run bitcoin-cli command. Deserializes returned string as python object."""
-
- pos_args = [str(arg) for arg in args]
+ pos_args = [str(arg).lower() if type(arg) is bool else str(arg) for arg in args]
named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()]
assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call"
p_args = [self.binary, "-datadir=" + self.datadir] + self.options
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index e016148f70..b355816d8b 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Helpful routines for regression testing."""
@@ -327,7 +327,7 @@ def get_auth_cookie(datadir):
assert password is None # Ensure that there is only one rpcpassword line
password = line.split("=")[1].strip("\n")
if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")):
- with open(os.path.join(datadir, "regtest", ".cookie"), 'r') as f:
+ with open(os.path.join(datadir, "regtest", ".cookie"), 'r', encoding="ascii") as f:
userpass = f.read()
split_userpass = userpass.split(':')
user = split_userpass[0]
@@ -526,14 +526,6 @@ def gen_return_txouts():
txouts = txouts + script_pubkey
return txouts
-def create_tx(node, coinbase, to_address, amount):
- inputs = [{"txid": coinbase, "vout": 0}]
- outputs = {to_address: amount}
- rawtx = node.createrawtransaction(inputs, outputs)
- signresult = node.signrawtransactionwithwallet(rawtx)
- assert_equal(signresult["complete"], True)
- return signresult["hex"]
-
# Create a spend of each passed-in utxo, splicing in "txouts" to each raw
# transaction to make it large. See gen_return_txouts() above.
def create_lots_of_big_transactions(node, txouts, utxos, num, fee):
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 65e4c0817e..37a3c1c602 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Run regression test suite.
@@ -58,9 +58,12 @@ TRAVIS_TIMEOUT_DURATION = 20 * 60
BASE_SCRIPTS = [
# Scripts that are run by the travis build process.
# Longest test should go first, to favor running tests in parallel
+ 'feature_fee_estimation.py',
'wallet_hd.py',
'wallet_backup.py',
# vv Tests less than 5m vv
+ 'mining_getblocktemplate_longpoll.py',
+ 'feature_maxuploadtarget.py',
'feature_block.py',
'rpc_fundrawtransaction.py',
'p2p_compactblocks.py',
@@ -69,6 +72,7 @@ BASE_SCRIPTS = [
'wallet_basic.py',
'wallet_labels.py',
'p2p_segwit.py',
+ 'p2p_timeouts.py',
'wallet_dump.py',
'wallet_listtransactions.py',
# vv Tests less than 60s vv
@@ -82,6 +86,8 @@ BASE_SCRIPTS = [
'feature_csv_activation.py',
'rpc_rawtransaction.py',
'wallet_address_types.py',
+ 'feature_bip68_sequence.py',
+ 'p2p_feefilter.py',
'feature_reindex.py',
# vv Tests less than 30s vv
'wallet_keypool_topup.py',
@@ -98,10 +104,14 @@ BASE_SCRIPTS = [
'mempool_persist.py',
'wallet_multiwallet.py',
'wallet_multiwallet.py --usecli',
+ 'wallet_disableprivatekeys.py',
+ 'wallet_disableprivatekeys.py --usecli',
'interface_http.py',
+ 'rpc_psbt.py',
'rpc_users.py',
'feature_proxy.py',
'rpc_signrawtransaction.py',
+ 'wallet_groups.py',
'p2p_disconnect_ban.py',
'rpc_decodescript.py',
'rpc_blockchain.py',
@@ -111,11 +121,22 @@ BASE_SCRIPTS = [
'wallet_keypool.py',
'p2p_mempool.py',
'mining_prioritisetransaction.py',
+ 'p2p_invalid_locator.py',
'p2p_invalid_block.py',
'p2p_invalid_tx.py',
+ 'feature_assumevalid.py',
+ 'example_test.py',
+ 'wallet_txn_doublespend.py',
+ 'wallet_txn_clone.py --mineblock',
+ 'feature_notifications.py',
+ 'rpc_invalidateblock.py',
+ 'feature_rbf.py',
+ 'mempool_packages.py',
+ 'rpc_createmultisig.py',
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
'wallet_importprunedfunds.py',
+ 'rpc_zmq.py',
'rpc_signmessage.py',
'feature_nulldummy.py',
'mempool_accept.py',
@@ -140,10 +161,12 @@ BASE_SCRIPTS = [
'feature_uacomment.py',
'p2p_unrequested_blocks.py',
'feature_includeconf.py',
+ 'rpc_scantxoutset.py',
'feature_logging.py',
'p2p_node_network_limited.py',
'feature_blocksdir.py',
'feature_config_args.py',
+ 'rpc_help.py',
'feature_help.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
@@ -153,26 +176,7 @@ EXTENDED_SCRIPTS = [
# These tests are not run by the travis build process.
# Longest test should go first, to favor running tests in parallel
'feature_pruning.py',
- # vv Tests less than 20m vv
- 'feature_fee_estimation.py',
- # vv Tests less than 5m vv
- 'feature_maxuploadtarget.py',
- 'mempool_packages.py',
'feature_dbcrash.py',
- # vv Tests less than 2m vv
- 'feature_bip68_sequence.py',
- 'mining_getblocktemplate_longpoll.py',
- 'p2p_timeouts.py',
- # vv Tests less than 60s vv
- 'p2p_feefilter.py',
- # vv Tests less than 30s vv
- 'feature_assumevalid.py',
- 'example_test.py',
- 'wallet_txn_doublespend.py',
- 'wallet_txn_clone.py --mineblock',
- 'feature_notifications.py',
- 'rpc_invalidateblock.py',
- 'feature_rbf.py',
]
# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests
@@ -213,7 +217,7 @@ def main():
# Read config generated by configure.
config = configparser.ConfigParser()
configfile = os.path.abspath(os.path.dirname(__file__)) + "/../config.ini"
- config.read_file(open(configfile))
+ config.read_file(open(configfile, encoding="utf8"))
passon_args.append("--configfile=%s" % configfile)
@@ -222,13 +226,11 @@ def main():
logging.basicConfig(format='%(message)s', level=logging_level)
# Create base test directory
- tmpdir = "%s/bitcoin_test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
+ tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
os.makedirs(tmpdir)
logging.debug("Temporary test directory at %s" % tmpdir)
- enable_wallet = config["components"].getboolean("ENABLE_WALLET")
- enable_utils = config["components"].getboolean("ENABLE_UTILS")
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
if config["environment"]["EXEEXT"] == ".exe" and not args.force:
@@ -237,9 +239,9 @@ def main():
print("Tests currently disabled on Windows by default. Use --force option to enable")
sys.exit(0)
- if not (enable_wallet and enable_utils and enable_bitcoind):
- print("No functional tests to run. Wallet, utils, and bitcoind must all be enabled")
- print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
+ if not enable_bitcoind:
+ print("No functional tests to run.")
+ print("Rerun ./configure with --with-daemon and then make")
sys.exit(0)
# Build list of tests
@@ -419,10 +421,6 @@ class TestHandler:
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):
@@ -430,7 +428,7 @@ class TestHandler:
# Add tests
self.num_running += 1
test = self.test_list.pop(0)
- portseed = len(self.test_list) + self.portseed_offset
+ portseed = len(self.test_list)
portseed_arg = ["--portseed={}".format(portseed)]
log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
@@ -594,7 +592,7 @@ class RPCCoverage():
if not os.path.isfile(coverage_ref_filename):
raise RuntimeError("No coverage reference found")
- with open(coverage_ref_filename, 'r') as coverage_ref_file:
+ with open(coverage_ref_filename, 'r', encoding="utf8") as coverage_ref_file:
all_cmds.update([line.strip() for line in coverage_ref_file.readlines()])
for root, dirs, files in os.walk(self.dir):
@@ -603,7 +601,7 @@ class RPCCoverage():
coverage_filenames.add(os.path.join(root, filename))
for filename in coverage_filenames:
- with open(filename, 'r') as coverage_file:
+ with open(filename, 'r', encoding="utf8") as coverage_file:
covered_cmds.update([line.strip() for line in coverage_file.readlines()])
return all_cmds - covered_cmds
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index d5ef08d782..e5ac2c8bd4 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the abandontransaction RPC.
@@ -10,15 +10,19 @@
which are not included in a block and are not currently in the mempool. It has
no effect on transactions which are already abandoned.
"""
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from decimal import Decimal
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, disconnect_nodes, sync_blocks, sync_mempools
class AbandonConflictTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-minrelaytxfee=0.00001"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[1].generate(100)
sync_blocks(self.nodes)
@@ -70,9 +74,17 @@ class AbandonConflictTest(BitcoinTestFramework):
signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])
+ # Create a child tx spending ABC2
+ signed3_change = Decimal("24.999")
+ inputs = [ {"txid":txABC2, "vout":0} ]
+ outputs = { self.nodes[0].getnewaddress(): signed3_change }
+ signed3 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
+ # note tx is never directly referenced, only abandoned as a child of the above
+ self.nodes[0].sendrawtransaction(signed3["hex"])
+
# In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance()
- assert_equal(newbalance, balance - Decimal("30") + Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("30") + signed3_change)
balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
@@ -87,7 +99,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance()
- assert_equal(newbalance, balance - Decimal("24.9996"))
+ assert_equal(newbalance, balance - signed3_change)
# Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 7658d78383..0f75045c9d 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that the wallet can send and receive using all combinations of address types.
@@ -63,6 +63,7 @@ from test_framework.util import (
sync_mempools,
)
+
class AddressTypeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 6
@@ -72,9 +73,12 @@ class AddressTypeTest(BitcoinTestFramework):
["-addresstype=p2sh-segwit", "-changetype=bech32"],
["-addresstype=bech32"],
["-changetype=p2sh-segwit"],
- []
+ [],
]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
@@ -143,7 +147,7 @@ class AddressTypeTest(BitcoinTestFramework):
assert(False)
def test_change_output_type(self, node_sender, destinations, expected_type):
- txid = self.nodes[node_sender].sendmany(fromaccount="", amounts=dict.fromkeys(destinations, 0.001))
+ txid = self.nodes[node_sender].sendmany(dummy="", amounts=dict.fromkeys(destinations, 0.001))
raw_tx = self.nodes[node_sender].getrawtransaction(txid)
tx = self.nodes[node_sender].decoderawtransaction(raw_tx)
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index 46a72d7e28..32ec385fa1 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet backup features.
@@ -30,11 +30,13 @@ confirm 1/2/3/4 balances are same as before.
Shutdown again, restore using importwallet,
and confirm again balances are correct.
"""
+from decimal import Decimal
+import os
from random import randint
import shutil
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, sync_blocks, sync_mempools
class WalletBackupTest(BitcoinTestFramework):
def set_test_params(self):
@@ -43,6 +45,9 @@ class WalletBackupTest(BitcoinTestFramework):
# nodes 1, 2,3 are spenders, let's give them a keypool=100
self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
self.setup_nodes()
connect_nodes(self.nodes[0], 3)
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index add7b7629d..8bbff7f7ef 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet."""
@@ -23,6 +23,9 @@ class WalletTest(BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.add_nodes(4)
self.start_node(0)
@@ -64,6 +67,15 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), 50)
assert_equal(self.nodes[2].getbalance(), 0)
+ # Check getbalance with different arguments
+ assert_equal(self.nodes[0].getbalance("*"), 50)
+ assert_equal(self.nodes[0].getbalance("*", 1), 50)
+ assert_equal(self.nodes[0].getbalance("*", 1, True), 50)
+ assert_equal(self.nodes[0].getbalance(minconf=1), 50)
+
+ # first argument of getbalance must be excluded or set to "*"
+ assert_raises_rpc_error(-32, "dummy first argument must be excluded or set to \"*\"", self.nodes[0].getbalance, "")
+
# Check that only first and second nodes have UTXOs
utxos = self.nodes[0].listunspent()
assert_equal(len(utxos), 1)
@@ -135,6 +147,15 @@ class WalletTest(BitcoinTestFramework):
self.nodes[2].lockunspent, False,
[{"txid": unspent_0["txid"], "vout": 999}])
+ # An output should be unlocked when spent
+ unspent_0 = self.nodes[1].listunspent()[0]
+ self.nodes[1].lockunspent(False, [unspent_0])
+ tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 })
+ tx = self.nodes[1].fundrawtransaction(tx)['hex']
+ tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"]
+ self.nodes[1].sendrawtransaction(tx)
+ assert_equal(len(self.nodes[1].listlockunspent()), 0)
+
# Have node1 generate 100 blocks (so node0 can recover the fee)
self.nodes[1].generate(100)
self.sync_all([self.nodes[0:3]])
@@ -236,8 +257,8 @@ class WalletTest(BitcoinTestFramework):
# 2. hex-changed one output to 0.0
# 3. sign and send
# 4. check if recipient (node0) can list the zero value tx
- usp = self.nodes[1].listunspent()
- inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}]
+ usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0]
+ inputs = [{"txid": usp['txid'], "vout": usp['vout']}]
outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11}
raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32)
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index fcc11abce0..67ee00871d 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the bumpfee RPC.
@@ -14,12 +14,12 @@ added in the future, they should try to follow the same convention and not
make assumptions about execution order.
"""
-from test_framework.blocktools import send_to_witness
+from decimal import Decimal
+
+from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness
+from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction
from test_framework.test_framework import BitcoinTestFramework
-from test_framework import blocktools
-from test_framework.messages import BIP125_SEQUENCE_NUMBER
-from test_framework.mininode import CTransaction
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes, sync_mempools
import io
@@ -31,13 +31,18 @@ class BumpFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
- self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i)]
- for i in range(self.num_nodes)]
+ self.extra_args = [[
+ "-deprecatedrpc=addwitnessaddress",
+ "-walletrbf={}".format(i),
+ "-mintxfee=0.00002",
+ ] for i in range(self.num_nodes)]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
# Encrypt wallet for test_locked_wallet_fails test
- self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE)
- self.start_node(1)
+ self.nodes[1].encryptwallet(WALLET_PASSPHRASE)
self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
connect_nodes_bi(self.nodes, 0, 1)
@@ -190,6 +195,8 @@ def test_dust_to_fee(rbf_node, dest_address):
def test_settxfee(rbf_node, dest_address):
+ assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.000005'))
+ assert_raises_rpc_error(-8, "txfee cannot be less than wallet min fee", rbf_node.settxfee, Decimal('0.000015'))
# check that bumpfee reacts correctly to the use of settxfee (paytxfee)
rbfid = spend_one_input(rbf_node, dest_address)
requested_feerate = Decimal("0.00025000")
@@ -290,11 +297,11 @@ def submit_block_with_tx(node, tx):
tip = node.getbestblockhash()
height = node.getblockcount() + 1
block_time = node.getblockheader(tip)["mediantime"] + 1
- block = blocktools.create_block(int(tip, 16), blocktools.create_coinbase(height), block_time)
+ block = create_block(int(tip, 16), create_coinbase(height), block_time)
block.vtx.append(ctx)
block.rehash()
block.hashMerkleRoot = block.calc_merkle_root()
- blocktools.add_witness_commitment(block)
+ add_witness_commitment(block)
block.solve()
node.submitblock(bytes_to_hex_str(block.serialize(True)))
return block
diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py
index b0627d88ac..6530c58c78 100755
--- a/test/functional/wallet_disable.py
+++ b/test/functional/wallet_disable.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test a node with the -disablewallet option.
@@ -9,7 +9,7 @@
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_raises_rpc_error
class DisableWalletTest (BitcoinTestFramework):
def set_test_params(self):
diff --git a/test/functional/wallet_disableprivatekeys.py b/test/functional/wallet_disableprivatekeys.py
new file mode 100755
index 0000000000..34ff525255
--- /dev/null
+++ b/test/functional/wallet_disableprivatekeys.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test disable-privatekeys mode.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_raises_rpc_error,
+)
+
+
+class DisablePrivateKeysTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+ self.supports_cli = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ node = self.nodes[0]
+ self.log.info("Test disableprivatekeys creation.")
+ self.nodes[0].createwallet('w1', True)
+ self.nodes[0].createwallet('w2')
+ w1 = node.get_wallet_rpc('w1')
+ w2 = node.get_wallet_rpc('w2')
+ assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getnewaddress)
+ assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getrawchangeaddress)
+ w1.importpubkey(w2.getaddressinfo(w2.getnewaddress())['pubkey'])
+
+if __name__ == '__main__':
+ DisablePrivateKeysTest().main()
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index ba420ab2a6..b1db1e4ab9 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the dumpwallet RPC."""
@@ -29,50 +29,58 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old):
# only read non comment lines
if line[0] != "#" and len(line) > 10:
# split out some data
- key_label, comment = line.split("#")
- # key = key_label.split(" ")[0]
- keytype = key_label.split(" ")[2]
- if len(comment) > 1:
- addr_keypath = comment.split(" addr=")[1]
- addr = addr_keypath.split(" ")[0]
+ key_date_label, comment = line.split("#")
+ key_date_label = key_date_label.split(" ")
+ # key = key_date_label[0]
+ date = key_date_label[1]
+ keytype = key_date_label[2]
+
+ imported_key = date == '1970-01-01T00:00:01Z'
+ if imported_key:
+ # Imported keys have multiple addresses, no label (keypath) and timestamp
+ # Skip them
+ continue
+
+ addr_keypath = comment.split(" addr=")[1]
+ addr = addr_keypath.split(" ")[0]
+ keypath = None
+ if keytype == "inactivehdseed=1":
+ # ensure the old master is still available
+ assert (hd_master_addr_old == addr)
+ elif keytype == "hdseed=1":
+ # ensure we have generated a new hd master key
+ assert (hd_master_addr_old != addr)
+ hd_master_addr_ret = addr
+ elif keytype == "script=1":
+ # scripts don't have keypaths
keypath = None
- if keytype == "inactivehdseed=1":
- # ensure the old master is still available
- assert(hd_master_addr_old == addr)
- elif keytype == "hdseed=1":
- # ensure we have generated a new hd master key
- assert(hd_master_addr_old != addr)
- hd_master_addr_ret = addr
- elif keytype == "script=1":
- # scripts don't have keypaths
- keypath = None
- else:
- keypath = addr_keypath.rstrip().split("hdkeypath=")[1]
-
- # count key types
- for addrObj in addrs:
- if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=":
- # a labeled entry in the wallet should contain both a native address
- # and the p2sh-p2wpkh address that was added at wallet setup
- if len(addr.split(",")) == 2:
- addr_list = addr.split(",")
- # the entry should be of the first key in the wallet
- assert_equal(addrs[0]['address'], addr_list[0])
- witness_addr_ret = addr_list[1]
- found_addr += 1
- break
- elif keytype == "change=1":
- found_addr_chg += 1
- break
- elif keytype == "reserve=1":
- found_addr_rsv += 1
- break
-
- # count scripts
- for script_addr in script_addrs:
- if script_addr == addr.rstrip() and keytype == "script=1":
- found_script_addr += 1
- break
+ else:
+ keypath = addr_keypath.rstrip().split("hdkeypath=")[1]
+
+ # count key types
+ for addrObj in addrs:
+ if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=":
+ # a labeled entry in the wallet should contain both a native address
+ # and the p2sh-p2wpkh address that was added at wallet setup
+ if len(addr.split(",")) == 2:
+ addr_list = addr.split(",")
+ # the entry should be of the first key in the wallet
+ assert_equal(addrs[0]['address'], addr_list[0])
+ witness_addr_ret = addr_list[1]
+ found_addr += 1
+ break
+ elif keytype == "change=1":
+ found_addr_chg += 1
+ break
+ elif keytype == "reserve=1":
+ found_addr_rsv += 1
+ break
+
+ # count scripts
+ for script_addr in script_addrs:
+ if script_addr == addr.rstrip() and keytype == "script=1":
+ found_script_addr += 1
+ break
return found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret, witness_addr_ret
@@ -81,16 +89,16 @@ class WalletDumpTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [["-keypool=90", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
+ self.rpc_timeout = 120
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def setup_network(self, split=False):
- # Use 1 minute timeout because the initial getnewaddress RPC can take
- # longer than the default 30 seconds due to an expensive
- # CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in
- # the test often takes even longer.
- self.add_nodes(self.num_nodes, extra_args=self.extra_args, timewait=60)
+ self.add_nodes(self.num_nodes, extra_args=self.extra_args)
self.start_nodes()
- def run_test (self):
+ def run_test(self):
wallet_unenc_dump = os.path.join(self.nodes[0].datadir, "wallet.unencrypted.dump")
wallet_enc_dump = os.path.join(self.nodes[0].datadir, "wallet.encrypted.dump")
@@ -119,13 +127,12 @@ class WalletDumpTest(BitcoinTestFramework):
read_dump(wallet_unenc_dump, addrs, script_addrs, None)
assert_equal(found_addr, test_addr_count) # all keys must be in the dump
assert_equal(found_script_addr, 2) # all scripts must be in the dump
- assert_equal(found_addr_chg, 50) # 50 blocks where mined
- assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys
- assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key
+ assert_equal(found_addr_chg, 0) # 0 blocks where mined
+ assert_equal(found_addr_rsv, 90 * 2) # 90 keys plus 100% internal keys
+ assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key
#encrypt wallet, restart, unlock and dump
- self.nodes[0].node_encrypt_wallet('test')
- self.start_node(0)
+ self.nodes[0].encryptwallet('test')
self.nodes[0].walletpassphrase('test', 10)
# Should be a no-op:
self.nodes[0].keypoolrefill()
@@ -135,8 +142,8 @@ class WalletDumpTest(BitcoinTestFramework):
read_dump(wallet_enc_dump, addrs, script_addrs, hd_master_addr_unenc)
assert_equal(found_addr, test_addr_count)
assert_equal(found_script_addr, 2)
- assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now
- assert_equal(found_addr_rsv, 90*2)
+ assert_equal(found_addr_chg, 90 * 2) # old reserve keys are marked as change now
+ assert_equal(found_addr_rsv, 90 * 2)
assert_equal(witness_addr_ret, witness_addr)
# Overwriting should fail
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index 64ee678744..ab9ebed8d4 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test Wallet encryption"""
@@ -19,6 +19,9 @@ class WalletEncryptionTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
passphrase = "WalletPassphrase"
passphrase2 = "SecondWalletPassphrase"
@@ -30,8 +33,7 @@ class WalletEncryptionTest(BitcoinTestFramework):
assert_equal(len(privkey), 52)
# Encrypt the wallet
- self.nodes[0].node_encrypt_wallet(passphrase)
- self.start_node(0)
+ self.nodes[0].encryptwallet(passphrase)
# Test that the wallet is encrypted
assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address)
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index e9cd052344..0c67982bbe 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -1,16 +1,19 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_raises_rpc_error
class WalletRBFTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[0].generate(101)
@@ -21,7 +24,6 @@ class WalletRBFTest(BitcoinTestFramework):
self.restart_node(0, extra_args=["-fallbackfee=0"])
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].fundrawtransaction(self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})))
- assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendfrom("", self.nodes[0].getnewaddress(), 1))
assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1}))
if __name__ == '__main__':
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
new file mode 100755
index 0000000000..9d61483868
--- /dev/null
+++ b/test/functional/wallet_groups.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test wallet group functionality."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.messages import CTransaction, FromHex, ToHex
+from test_framework.util import (
+ assert_equal,
+)
+
+def assert_approx(v, vexp, vspan=0.00001):
+ if v < vexp - vspan:
+ raise AssertionError("%s < [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
+ if v > vexp + vspan:
+ raise AssertionError("%s > [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
+
+class WalletGroupTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+ self.extra_args = [[], [], ['-avoidpartialspends']]
+ self.rpc_timewait = 120
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ # Mine some coins
+ self.nodes[0].generate(110)
+
+ # Get some addresses from the two nodes
+ addr1 = [self.nodes[1].getnewaddress() for i in range(3)]
+ addr2 = [self.nodes[2].getnewaddress() for i in range(3)]
+ addrs = addr1 + addr2
+
+ # Send 1 + 0.5 coin to each address
+ [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]
+ [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]
+
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # For each node, send 0.2 coins back to 0;
+ # - node[1] should pick one 0.5 UTXO and leave the rest
+ # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a
+ # given address, and leave the rest
+ txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
+ tx1 = self.nodes[1].getrawtransaction(txid1, True)
+ # txid1 should have 1 input and 2 outputs
+ assert_equal(1, len(tx1["vin"]))
+ assert_equal(2, len(tx1["vout"]))
+ # one output should be 0.2, the other should be ~0.3
+ v = [vout["value"] for vout in tx1["vout"]]
+ v.sort()
+ assert_approx(v[0], 0.2)
+ assert_approx(v[1], 0.3, 0.0001)
+
+ txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
+ tx2 = self.nodes[2].getrawtransaction(txid2, True)
+ # txid2 should have 2 inputs and 2 outputs
+ assert_equal(2, len(tx2["vin"]))
+ assert_equal(2, len(tx2["vout"]))
+ # one output should be 0.2, the other should be ~1.3
+ v = [vout["value"] for vout in tx2["vout"]]
+ v.sort()
+ assert_approx(v[0], 0.2)
+ assert_approx(v[1], 1.3, 0.0001)
+
+ # Empty out node2's wallet
+ self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=self.nodes[2].getbalance(), subtractfeefromamount=True)
+ self.sync_all()
+ self.nodes[0].generate(1)
+
+ # Fill node2's wallet with 10000 outputs corresponding to the same
+ # scriptPubKey
+ for i in range(5):
+ raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}])
+ tx = FromHex(CTransaction(), raw_tx)
+ tx.vin = []
+ tx.vout = [tx.vout[0]] * 2000
+ funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
+ self.nodes[0].sendrawtransaction(signed_tx['hex'])
+ self.nodes[0].generate(1)
+
+ self.sync_all()
+
+ # Check that we can create a transaction that only requires ~100 of our
+ # utxos, without pulling in all outputs and creating a transaction that
+ # is way too big.
+ assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)
+
+if __name__ == '__main__':
+ WalletGroupTest().main ()
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 86abe0ca99..48e71f6c40 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test Hierarchical Deterministic wallet function."""
@@ -21,6 +21,9 @@ class WalletHDTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [[], ['-keypool=0']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Make sure can't switch off usehd after wallet creation
self.stop_node(1)
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 4c0ffb938b..f043a544fc 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet import RPCs.
@@ -26,7 +26,7 @@ import collections
import enum
import itertools
-Call = enum.Enum("Call", "single multi")
+Call = enum.Enum("Call", "single multiaddress multiscript")
Data = enum.Enum("Data", "address pub priv")
Rescan = enum.Enum("Rescan", "no yes late_timestamp")
@@ -53,11 +53,11 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
response = self.try_rpc(self.node.importprivkey, privkey=self.key, rescan=rescan)
assert_equal(response, None)
- elif self.call == Call.multi:
+ elif self.call in (Call.multiaddress, Call.multiscript):
response = self.node.importmulti([{
"scriptPubKey": {
"address": self.address["address"]
- },
+ } if self.call == Call.multiaddress else self.address["scriptPubKey"],
"timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
"keys": [self.key] if self.data == Data.priv else [],
@@ -109,6 +109,9 @@ class ImportRescanTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2 + len(IMPORT_NODES)
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
extra_args = [["-addresstype=legacy"] for _ in range(self.num_nodes)]
for i, import_node in enumerate(IMPORT_NODES, 2):
@@ -116,17 +119,26 @@ class ImportRescanTest(BitcoinTestFramework):
extra_args[i] += ["-prune=1"]
self.add_nodes(self.num_nodes, extra_args=extra_args)
+
+ # Import keys with pruning disabled
+ self.start_nodes(extra_args=[[]] * self.num_nodes)
+ super().import_deterministic_coinbase_privkeys()
+ self.stop_nodes()
+
self.start_nodes()
for i in range(1, self.num_nodes):
connect_nodes(self.nodes[i], 0)
+ def import_deterministic_coinbase_privkeys(self):
+ pass
+
def run_test(self):
# Create one transaction on node 0 with a unique amount for
# each possible type of wallet import RPC.
for i, variant in enumerate(IMPORT_VARIANTS):
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
- variant.initial_amount = 10 - (i + 1) / 4.0
+ variant.initial_amount = 1 - (i + 1) / 64
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
# Generate a block containing the initial transactions, then another
@@ -156,7 +168,7 @@ class ImportRescanTest(BitcoinTestFramework):
# Create new transactions sending to each address.
for i, variant in enumerate(IMPORT_VARIANTS):
- variant.sent_amount = 10 - (2 * i + 1) / 8.0
+ variant.sent_amount = 1 - (2 * i + 1) / 128
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
# Generate a block containing the new transactions.
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 91acdb01d0..f78ff19791 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -1,17 +1,28 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the importmulti RPC."""
+
+from test_framework import script
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_raises_rpc_error,
+ bytes_to_hex_str,
+)
+
-class ImportMultiTest (BitcoinTestFramework):
+class ImportMultiTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"]]
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
@@ -79,16 +90,17 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['ismine'], False)
assert_equal(address_assert['timestamp'], timestamp)
- # ScriptPubKey + !internal
- self.log.info("Should not import a scriptPubKey without internal flag")
+ # Nonstandard scriptPubKey + !internal
+ self.log.info("Should not import a nonstandard scriptPubKey without internal flag")
+ nonstandardScriptPubKey = address['scriptPubKey'] + bytes_to_hex_str(script.CScript([script.OP_NOP]))
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
- "scriptPubKey": address['scriptPubKey'],
+ "scriptPubKey": nonstandardScriptPubKey,
"timestamp": "now",
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -128,18 +140,18 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['ismine'], False)
assert_equal(address_assert['timestamp'], timestamp)
- # ScriptPubKey + Public key + !internal
- self.log.info("Should not import a scriptPubKey without internal and with public key")
+ # Nonstandard scriptPubKey + Public key + !internal
+ self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
request = [{
- "scriptPubKey": address['scriptPubKey'],
+ "scriptPubKey": nonstandardScriptPubKey,
"timestamp": "now",
"pubkeys": [ address['pubkey'] ]
}]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -207,17 +219,17 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['ismine'], True)
assert_equal(address_assert['timestamp'], timestamp)
- # ScriptPubKey + Private key + !internal
- self.log.info("Should not import a scriptPubKey without internal and with private key")
+ # Nonstandard scriptPubKey + Private key + !internal
+ self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
- "scriptPubKey": address['scriptPubKey'],
+ "scriptPubKey": nonstandardScriptPubKey,
"timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 9cee9aa49a..26b181db33 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the importprunedfunds and removeprunedfunds RPCs."""
@@ -15,7 +15,9 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.extra_args = [['-deprecatedrpc=accounts']] * 2
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
self.log.info("Mining blocks...")
@@ -74,22 +76,20 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
# Import with no affiliated address
assert_raises_rpc_error(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1)
- balance1 = self.nodes[1].getbalance("", 0, True)
+ balance1 = self.nodes[1].getbalance()
assert_equal(balance1, Decimal(0))
# Import with affiliated address with no rescan
- self.nodes[1].importaddress(address2, "add2", False)
+ self.nodes[1].importaddress(address=address2, rescan=False)
self.nodes[1].importprunedfunds(rawtxn2, proof2)
- balance2 = self.nodes[1].getbalance("add2", 0, True)
- assert_equal(balance2, Decimal('0.05'))
+ assert [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid2]
# Import with private key with no rescan
- self.nodes[1].importprivkey(privkey=address3_privkey, label="add3", rescan=False)
+ self.nodes[1].importprivkey(privkey=address3_privkey, rescan=False)
self.nodes[1].importprunedfunds(rawtxn3, proof3)
- balance3 = self.nodes[1].getbalance("add3", 0, False)
+ assert [tx for tx in self.nodes[1].listtransactions() if tx['txid'] == txnid3]
+ balance3 = self.nodes[1].getbalance()
assert_equal(balance3, Decimal('0.025'))
- balance3 = self.nodes[1].getbalance("*", 0, True)
- assert_equal(balance3, Decimal('0.075'))
# Addresses Test - after import
address_info = self.nodes[1].getaddressinfo(address1)
@@ -104,17 +104,13 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
# Remove transactions
assert_raises_rpc_error(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1)
-
- balance1 = self.nodes[1].getbalance("*", 0, True)
- assert_equal(balance1, Decimal('0.075'))
+ assert not [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid1]
self.nodes[1].removeprunedfunds(txnid2)
- balance2 = self.nodes[1].getbalance("*", 0, True)
- assert_equal(balance2, Decimal('0.025'))
+ assert not [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid2]
self.nodes[1].removeprunedfunds(txnid3)
- balance3 = self.nodes[1].getbalance("*", 0, True)
- assert_equal(balance3, Decimal('0.0'))
+ assert not [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid3]
if __name__ == '__main__':
ImportPrunedFundsTest().main()
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 1285515dfc..51afa0cb1a 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -1,16 +1,21 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet keypool and interaction with wallet encryption/locking."""
+import time
+
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import assert_equal, assert_raises_rpc_error
class KeyPoolTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
nodes = self.nodes
addr_before_encrypting = nodes[0].getnewaddress()
@@ -20,9 +25,7 @@ class KeyPoolTest(BitcoinTestFramework):
assert(addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid'])
# Encrypt wallet and wait to terminate
- nodes[0].node_encrypt_wallet('test')
- # Restart node 0
- self.start_node(0)
+ nodes[0].encryptwallet('test')
# Keep creating keys
addr = nodes[0].getnewaddress()
addr_data = nodes[0].getaddressinfo(addr)
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index d657dc30c4..f1a441c399 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test HD Wallet keypool restore function.
@@ -27,6 +27,9 @@ class KeypoolRestoreTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [[], ['-keypool=100']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
wallet_path = os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat")
wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak")
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index 705dd8985e..8d7c77bb96 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -1,19 +1,13 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2017 The Bitcoin Core developers
+# Copyright (c) 2016-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test label RPCs.
RPCs tested are:
- - getlabeladdress
- - getaddressesbyaccount/getaddressesbylabel
+ - getaddressesbylabel
- listaddressgroupings
- setlabel
- - sendfrom (with account arguments)
- - move (with account arguments)
-
-Run the test twice - once using the accounts API and once using the labels API.
-The accounts API test can be removed in V0.18.
"""
from collections import defaultdict
@@ -23,22 +17,14 @@ from test_framework.util import assert_equal, assert_raises_rpc_error
class WalletLabelsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 2
- self.extra_args = [['-deprecatedrpc=accounts'], []]
+ self.num_nodes = 1
- def setup_network(self):
- """Don't connect nodes."""
- self.setup_nodes()
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
- """Run the test twice - once using the accounts API and once using the labels API."""
- self.log.info("Test accounts API")
- self._run_subtest(True, self.nodes[0])
- self.log.info("Test labels API")
- self._run_subtest(False, self.nodes[1])
-
- def _run_subtest(self, accounts_api, node):
- # Check that there's no UTXO on any of the nodes
+ # Check that there's no UTXO on the node
+ node = self.nodes[0]
assert_equal(len(node.listunspent()), 0)
# Note each time we call generate, all generated coins go into
@@ -61,17 +47,12 @@ class WalletLabelsTest(BitcoinTestFramework):
linked_addresses.add(address_group[0][0])
# send 50 from each address to a third address not in this wallet
- # There's some fee that will come back to us when the miner reward
- # matures.
common_address = "msf4WtN1YQKXvNtvdFYt9JBnUD2FB41kjr"
- txid = node.sendmany(
- fromaccount="",
+ node.sendmany(
amounts={common_address: 100},
subtractfeefrom=[common_address],
minconf=1,
)
- tx_details = node.gettransaction(txid)
- fee = -tx_details['details'][0]['fee']
# there should be 1 address group, with the previously
# unlinked addresses now linked (they both have 0 balance)
address_groups = node.listaddressgroupings()
@@ -85,24 +66,22 @@ class WalletLabelsTest(BitcoinTestFramework):
# we want to reset so that the "" label has what's expected.
# otherwise we're off by exactly the fee amount as that's mined
# and matures in the next 100 blocks
- node.sendfrom("", common_address, fee)
amount_to_send = 1.0
# Create labels and make sure subsequent label API calls
# recognize the label/address associations.
- labels = [Label(name, accounts_api) for name in ("a", "b", "c", "d", "e")]
+ labels = [Label(name) for name in ("a", "b", "c", "d", "e")]
for label in labels:
- label.add_receive_address(node.getlabeladdress(label=label.name, force=True))
+ address = node.getnewaddress(label.name)
+ label.add_receive_address(address)
label.verify(node)
# Check all labels are returned by listlabels.
assert_equal(node.listlabels(), [label.name for label in labels])
- # Send a transaction to each label, and make sure this forces
- # getlabeladdress to generate a new receiving address.
+ # Send a transaction to each label.
for label in labels:
- node.sendtoaddress(label.receive_address, amount_to_send)
- label.add_receive_address(node.getlabeladdress(label.name))
+ node.sendtoaddress(label.addresses[0], amount_to_send)
label.verify(node)
# Check the amounts received.
@@ -112,36 +91,25 @@ class WalletLabelsTest(BitcoinTestFramework):
node.getreceivedbyaddress(label.addresses[0]), amount_to_send)
assert_equal(node.getreceivedbylabel(label.name), amount_to_send)
- # Check that sendfrom label reduces listaccounts balances.
for i, label in enumerate(labels):
to_label = labels[(i + 1) % len(labels)]
- node.sendfrom(label.name, to_label.receive_address, amount_to_send)
+ node.sendtoaddress(to_label.addresses[0], amount_to_send)
node.generate(1)
for label in labels:
- label.add_receive_address(node.getlabeladdress(label.name))
+ address = node.getnewaddress(label.name)
+ label.add_receive_address(address)
label.verify(node)
assert_equal(node.getreceivedbylabel(label.name), 2)
- if accounts_api:
- node.move(label.name, "", node.getbalance(label.name))
label.verify(node)
node.generate(101)
- expected_account_balances = {"": 5200}
- for label in labels:
- expected_account_balances[label.name] = 0
- if accounts_api:
- assert_equal(node.listaccounts(), expected_account_balances)
- assert_equal(node.getbalance(""), 5200)
# Check that setlabel can assign a label to a new unused address.
for label in labels:
- address = node.getlabeladdress(label="", force=True)
+ address = node.getnewaddress()
node.setlabel(address, label.name)
label.add_address(address)
label.verify(node)
- if accounts_api:
- assert(address not in node.getaddressesbyaccount(""))
- else:
- assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
+ assert_raises_rpc_error(-11, "No addresses with label", node.getaddressesbylabel, "")
# Check that addmultisigaddress can assign labels.
for label in labels:
@@ -152,33 +120,20 @@ class WalletLabelsTest(BitcoinTestFramework):
label.add_address(multisig_address)
label.purpose[multisig_address] = "send"
label.verify(node)
- node.sendfrom("", multisig_address, 50)
node.generate(101)
- if accounts_api:
- for label in labels:
- assert_equal(node.getbalance(label.name), 50)
# Check that setlabel can change the label of an address from a
# different label.
change_label(node, labels[0].addresses[0], labels[0], labels[1])
- # Check that setlabel can change the label of an address which
- # is the receiving address of a different label.
- change_label(node, labels[0].receive_address, labels[0], labels[1])
-
# Check that setlabel can set the label of an address already
# in the label. This is a no-op.
change_label(node, labels[2].addresses[0], labels[2], labels[2])
- # Check that setlabel can set the label of an address which is
- # already the receiving address of the label. This is a no-op.
- change_label(node, labels[2].receive_address, labels[2], labels[2])
-
class Label:
- def __init__(self, name, accounts_api):
+ def __init__(self, name):
# Label name
self.name = name
- self.accounts_api = accounts_api
# Current receiving address associated with this label.
self.receive_address = None
# List of all addresses assigned with this label
@@ -192,29 +147,21 @@ class Label:
def add_receive_address(self, address):
self.add_address(address)
- self.receive_address = address
def verify(self, node):
if self.receive_address is not None:
assert self.receive_address in self.addresses
- assert_equal(node.getlabeladdress(self.name), self.receive_address)
for address in self.addresses:
assert_equal(
node.getaddressinfo(address)['labels'][0],
{"name": self.name,
"purpose": self.purpose[address]})
- if self.accounts_api:
- assert_equal(node.getaccount(address), self.name)
- else:
- assert_equal(node.getaddressinfo(address)['label'], self.name)
+ assert_equal(node.getaddressinfo(address)['label'], self.name)
assert_equal(
node.getaddressesbylabel(self.name),
{address: {"purpose": self.purpose[address]} for address in self.addresses})
- if self.accounts_api:
- assert_equal(set(node.getaddressesbyaccount(self.name)), set(self.addresses))
-
def change_label(node, address, old_label, new_label):
assert_equal(address in old_label.addresses, True)
@@ -223,19 +170,8 @@ def change_label(node, address, old_label, new_label):
old_label.addresses.remove(address)
new_label.add_address(address)
- # Calling setlabel on an address which was previously the receiving
- # address of a different label should reset the receiving address of
- # the old label, causing getlabeladdress to return a brand new
- # address.
- if old_label.name != new_label.name and address == old_label.receive_address:
- new_address = node.getlabeladdress(old_label.name)
- assert_equal(new_address not in old_label.addresses, True)
- assert_equal(new_address not in new_label.addresses, True)
- old_label.add_receive_address(new_address)
-
old_label.verify(node)
new_label.verify(node)
-
if __name__ == '__main__':
WalletLabelsTest().main()
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
index e9912f994e..3485c4470f 100755
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listreceivedbyaddress RPC."""
@@ -18,6 +18,14 @@ class ReceivedByTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def import_deterministic_coinbase_privkeys(self):
+ assert_equal(0, len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True)))
+ super().import_deterministic_coinbase_privkeys()
+ self.num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Generate block to get out of IBD
self.nodes[0].generate(1)
@@ -64,7 +72,7 @@ class ReceivedByTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling")
# Another address receive money
res = self.nodes[1].listreceivedbyaddress(0, True, True)
- assert_equal(len(res), 2) # Right now 2 entries
+ assert_equal(len(res), 2 + self.num_cb_reward_addresses) # Right now 2 entries
other_addr = self.nodes[1].getnewaddress()
txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1)
self.nodes[0].generate(1)
@@ -81,7 +89,7 @@ class ReceivedByTest(BitcoinTestFramework):
assert_equal(len(res), 1)
# Should be two entries though without filter
res = self.nodes[1].listreceivedbyaddress(0, True, True)
- assert_equal(len(res), 3) # Became 3 entries
+ assert_equal(len(res), 3 + self.num_cb_reward_addresses) # Became 3 entries
# Not on random addr
other_addr = self.nodes[0].getnewaddress() # note on node[0]! just a random addr
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index a49be78f2b..25ab222375 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listsincelast RPC."""
@@ -12,6 +12,9 @@ class ListSinceBlockTest (BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[2].generate(101)
self.sync_all()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 7cf2e456cf..5a17395abd 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listtransactions API."""
from decimal import Decimal
from io import BytesIO
-from test_framework.mininode import CTransaction, COIN
+from test_framework.messages import COIN, CTransaction
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
@@ -27,6 +27,9 @@ class ListTransactionsTest(BitcoinTestFramework):
self.num_nodes = 2
self.enable_mocktime()
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Simple send, 0 to 1:
txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 53638615f6..435821ec48 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test multiwallet.
@@ -23,6 +23,9 @@ class MultiWalletTest(BitcoinTestFramework):
self.num_nodes = 2
self.supports_cli = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
node = self.nodes[0]
@@ -30,6 +33,11 @@ class MultiWalletTest(BitcoinTestFramework):
wallet_dir = lambda *p: data_dir('wallets', *p)
wallet = lambda name: node.get_wallet_rpc(name)
+ def wallet_file(name):
+ if os.path.isdir(wallet_dir(name)):
+ return wallet_dir(name, "wallet.dat")
+ return wallet_dir(name)
+
# check wallet.dat is created
self.stop_nodes()
assert_equal(os.path.isfile(wallet_dir('wallet.dat')), True)
@@ -43,6 +51,12 @@ class MultiWalletTest(BitcoinTestFramework):
# directory paths) can be loaded
os.rename(wallet_dir("wallet.dat"), wallet_dir("w8"))
+ # create another dummy wallet for use in testing backups later
+ self.start_node(0, [])
+ self.stop_nodes()
+ empty_wallet = os.path.join(self.options.tmpdir, 'empty.dat')
+ os.rename(wallet_dir("wallet.dat"), empty_wallet)
+
# restart node with a mix of wallet names:
# w1, w2, w3 - to verify new wallets created when non-existing paths specified
# w - to verify wallet name matching works when one wallet path is prefix of another
@@ -59,10 +73,7 @@ class MultiWalletTest(BitcoinTestFramework):
# check that all requested wallets were created
self.stop_node(0)
for wallet_name in wallet_names:
- if os.path.isdir(wallet_dir(wallet_name)):
- assert_equal(os.path.isfile(wallet_dir(wallet_name, "wallet.dat")), True)
- else:
- assert_equal(os.path.isfile(wallet_dir(wallet_name)), True)
+ assert_equal(os.path.isfile(wallet_file(wallet_name)), True)
# should not initialize if wallet path can't be created
exp_stderr = "boost::filesystem::create_directory: (The system cannot find the path specified|Not a directory):"
@@ -88,7 +99,7 @@ class MultiWalletTest(BitcoinTestFramework):
self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist')
# should not initialize if the specified walletdir is not a directory
not_a_dir = wallet_dir('notadir')
- open(not_a_dir, 'a').close()
+ open(not_a_dir, 'a', encoding="utf8").close()
self.nodes[0].assert_start_raises_init_error(['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory')
self.log.info("Do not allow -zapwallettxes with multiwallet")
@@ -211,6 +222,10 @@ class MultiWalletTest(BitcoinTestFramework):
# Fail to load if wallet file is a symlink
assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
+ # Fail to load if a directory is specified that doesn't contain a wallet
+ os.mkdir(wallet_dir('empty_wallet_dir'))
+ assert_raises_rpc_error(-18, "Directory empty_wallet_dir does not contain a wallet.dat file", self.nodes[0].loadwallet, 'empty_wallet_dir')
+
self.log.info("Test dynamic wallet creation.")
# Fail to create a wallet if it already exists.
@@ -234,5 +249,52 @@ class MultiWalletTest(BitcoinTestFramework):
assert new_wallet_name in self.nodes[0].listwallets()
+ self.log.info("Test dynamic wallet unloading")
+
+ # Test `unloadwallet` errors
+ assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].unloadwallet)
+ assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", self.nodes[0].unloadwallet, "dummy")
+ assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", node.get_wallet_rpc("dummy").unloadwallet)
+ assert_raises_rpc_error(-8, "Cannot unload the requested wallet", w1.unloadwallet, "w2"),
+
+ # Successfully unload the specified wallet name
+ self.nodes[0].unloadwallet("w1")
+ assert 'w1' not in self.nodes[0].listwallets()
+
+ # Successfully unload the wallet referenced by the request endpoint
+ w2.unloadwallet()
+ assert 'w2' not in self.nodes[0].listwallets()
+
+ # Successfully unload all wallets
+ for wallet_name in self.nodes[0].listwallets():
+ self.nodes[0].unloadwallet(wallet_name)
+ assert_equal(self.nodes[0].listwallets(), [])
+ assert_raises_rpc_error(-32601, "Method not found (wallet method is disabled because no wallet is loaded)", self.nodes[0].getwalletinfo)
+
+ # Successfully load a previously unloaded wallet
+ self.nodes[0].loadwallet('w1')
+ assert_equal(self.nodes[0].listwallets(), ['w1'])
+ assert_equal(w1.getwalletinfo()['walletname'], 'w1')
+
+ # Test backing up and restoring wallets
+ self.log.info("Test wallet backup")
+ self.restart_node(0, ['-nowallet'])
+ for wallet_name in wallet_names:
+ self.nodes[0].loadwallet(wallet_name)
+ for wallet_name in wallet_names:
+ rpc = self.nodes[0].get_wallet_rpc(wallet_name)
+ addr = rpc.getnewaddress()
+ backup = os.path.join(self.options.tmpdir, 'backup.dat')
+ rpc.backupwallet(backup)
+ self.nodes[0].unloadwallet(wallet_name)
+ shutil.copyfile(empty_wallet, wallet_file(wallet_name))
+ self.nodes[0].loadwallet(wallet_name)
+ assert_equal(rpc.getaddressinfo(addr)['ismine'], False)
+ self.nodes[0].unloadwallet(wallet_name)
+ shutil.copyfile(backup, wallet_file(wallet_name))
+ self.nodes[0].loadwallet(wallet_name)
+ assert_equal(rpc.getaddressinfo(addr)['ismine'], True)
+
+
if __name__ == '__main__':
MultiWalletTest().main()
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index d959bb4c38..00bf58d709 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test resendwallettransactions RPC."""
@@ -12,6 +12,9 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [['--walletbroadcast=false']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled.
assert_raises_rpc_error(-4, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast", self.nodes[0].resendwallettransactions)
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 72ae2d5db7..d78c105c17 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs."""
@@ -16,11 +16,14 @@ class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def add_options(self, parser):
- parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
- help="Test double-spend of 1-confirmed transaction")
- parser.add_option("--segwit", dest="segwit", default=False, action="store_true",
- help="Test behaviour with SegWit txn (which should fail")
+ parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true",
+ help="Test double-spend of 1-confirmed transaction")
+ parser.add_argument("--segwit", dest="segwit", default=False, action="store_true",
+ help="Test behaviour with SegWit txn (which should fail")
def setup_network(self):
# Start with split network:
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index 7ee60d5611..f114d5ab68 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet accounts properly when there is a double-spend conflict."""
@@ -18,9 +18,12 @@ class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def add_options(self, parser):
- parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
- help="Test double-spend of 1-confirmed transaction")
+ parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true",
+ help="Test double-spend of 1-confirmed transaction")
def setup_network(self):
# Start with split network:
diff --git a/test/functional/wallet_zapwallettxes.py b/test/functional/wallet_zapwallettxes.py
index 87f44b2737..adebff360a 100755
--- a/test/functional/wallet_zapwallettxes.py
+++ b/test/functional/wallet_zapwallettxes.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the zapwallettxes functionality.
@@ -26,6 +26,9 @@ class ZapWalletTXesTest (BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.log.info("Mining blocks...")
self.nodes[0].generate(1)
diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py
index de5719eb29..7b056dab32 100755
--- a/test/lint/check-doc.py
+++ b/test/lint/check-doc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
+# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,12 +22,12 @@ CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_GREP)
CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
# list unsupported, deprecated and duplicate args as they need no documentation
-SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb', '-usehd'])
+SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb', '-usehd'])
def main():
- used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True)
- docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True)
+ used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True, encoding='utf8')
+ docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True, encoding='utf8')
args_used = set(re.findall(re.compile(REGEX_ARG), used))
args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL)
diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py
index 7e96852c5c..137cc82b5d 100755
--- a/test/lint/check-rpc-mappings.py
+++ b/test/lint/check-rpc-mappings.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
+# Copyright (c) 2017-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Check RPC argument consistency."""
@@ -44,7 +44,7 @@ def process_commands(fname):
"""Find and parse dispatch table in implementation file `fname`."""
cmds = []
in_rpcs = False
- with open(fname, "r") as f:
+ with open(fname, "r", encoding="utf8") as f:
for line in f:
line = line.rstrip()
if not in_rpcs:
@@ -70,7 +70,7 @@ def process_mapping(fname):
"""Find and parse conversion table in implementation file `fname`."""
cmds = []
in_rpcs = False
- with open(fname, "r") as f:
+ with open(fname, "r", encoding="utf8") as f:
for line in f:
line = line.rstrip()
if not in_rpcs:
@@ -90,6 +90,10 @@ def process_mapping(fname):
return cmds
def main():
+ if len(sys.argv) != 2:
+ print('Usage: {} ROOT-DIR'.format(sys.argv[0]), file=sys.stderr)
+ sys.exit(1)
+
root = sys.argv[1]
# Get all commands from dispatch tables
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 1c9dbc7f68..f1327469f3 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -11,6 +11,7 @@
# The resulting script should exactly transform the previous commit into the current
# one. Any remaining diff signals an error.
+export LC_ALL=C
if test "x$1" = "x"; then
echo "Usage: $0 <commit>..."
exit 1
diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh
index 184951715e..85e8b841b6 100755
--- a/test/lint/git-subtree-check.sh
+++ b/test/lint/git-subtree-check.sh
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+export LC_ALL=C
DIR="$1"
COMMIT="$2"
if [ -z "$COMMIT" ]; then
diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh
index b6d86959c6..7c4f96cb3b 100755
--- a/test/lint/lint-all.sh
+++ b/test/lint/lint-all.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -7,6 +7,10 @@
# This script runs all contrib/devtools/lint-*.sh files, and fails if any exit
# with a non-zero status code.
+# This script is intentionally locale dependent by not setting "export LC_ALL=C"
+# in order to allow for the executed lint scripts to opt in or opt out of locale
+# dependence themselves.
+
set -u
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
diff --git a/test/lint/lint-assertions.sh b/test/lint/lint-assertions.sh
new file mode 100755
index 0000000000..5bbcae79eb
--- /dev/null
+++ b/test/lint/lint-assertions.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Check for assertions with obvious side effects.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+
+# PRE31-C (SEI CERT C Coding Standard):
+# "Assertions should not contain assignments, increment, or decrement operators."
+OUTPUT=$(git grep -E '[^_]assert\(.*(\+\+|\-\-|[^=!<>]=[^=!<>]).*\);' -- "*.cpp" "*.h")
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Assertions should not have side effects:"
+ echo
+ echo "${OUTPUT}"
+ EXIT_CODE=1
+fi
+
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
new file mode 100755
index 0000000000..3972baed1d
--- /dev/null
+++ b/test/lint/lint-circular-dependencies.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Check for circular dependencies
+
+export LC_ALL=C
+
+EXPECTED_CIRCULAR_DEPENDENCIES=(
+ "chainparamsbase -> util -> chainparamsbase"
+ "checkpoints -> validation -> checkpoints"
+ "index/txindex -> validation -> index/txindex"
+ "policy/fees -> txmempool -> policy/fees"
+ "policy/policy -> validation -> policy/policy"
+ "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel"
+ "qt/bantablemodel -> qt/clientmodel -> qt/bantablemodel"
+ "qt/bitcoingui -> qt/utilitydialog -> qt/bitcoingui"
+ "qt/bitcoingui -> qt/walletframe -> qt/bitcoingui"
+ "qt/bitcoingui -> qt/walletview -> qt/bitcoingui"
+ "qt/clientmodel -> qt/peertablemodel -> qt/clientmodel"
+ "qt/paymentserver -> qt/walletmodel -> qt/paymentserver"
+ "qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel"
+ "qt/sendcoinsdialog -> qt/walletmodel -> qt/sendcoinsdialog"
+ "qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel"
+ "qt/walletmodel -> qt/walletmodeltransaction -> qt/walletmodel"
+ "txmempool -> validation -> txmempool"
+ "validation -> validationinterface -> validation"
+ "wallet/coincontrol -> wallet/wallet -> wallet/coincontrol"
+ "wallet/fees -> wallet/wallet -> wallet/fees"
+ "wallet/rpcwallet -> wallet/wallet -> wallet/rpcwallet"
+ "wallet/wallet -> wallet/walletdb -> wallet/wallet"
+ "policy/fees -> policy/policy -> validation -> policy/fees"
+ "policy/rbf -> txmempool -> validation -> policy/rbf"
+ "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/addressbookpage"
+ "qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil"
+ "txmempool -> validation -> validationinterface -> txmempool"
+ "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/receivecoinsdialog -> qt/addressbookpage"
+ "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/signverifymessagedialog -> qt/addressbookpage"
+ "qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/intro -> qt/guiutil"
+ "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/sendcoinsdialog -> qt/sendcoinsentry -> qt/addressbookpage"
+)
+
+EXIT_CODE=0
+
+CIRCULAR_DEPENDENCIES=()
+
+IFS=$'\n'
+for CIRC in $(cd src && ../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp} | sed -e 's/^Circular dependency: //'); do
+ CIRCULAR_DEPENDENCIES+=($CIRC)
+ IS_EXPECTED_CIRC=0
+ for EXPECTED_CIRC in "${EXPECTED_CIRCULAR_DEPENDENCIES[@]}"; do
+ if [[ "${CIRC}" == "${EXPECTED_CIRC}" ]]; then
+ IS_EXPECTED_CIRC=1
+ break
+ fi
+ done
+ if [[ ${IS_EXPECTED_CIRC} == 0 ]]; then
+ echo "A new circular dependency in the form of \"${CIRC}\" appears to have been introduced."
+ echo
+ EXIT_CODE=1
+ fi
+done
+
+for EXPECTED_CIRC in "${EXPECTED_CIRCULAR_DEPENDENCIES[@]}"; do
+ IS_PRESENT_EXPECTED_CIRC=0
+ for CIRC in "${CIRCULAR_DEPENDENCIES[@]}"; do
+ if [[ "${CIRC}" == "${EXPECTED_CIRC}" ]]; then
+ IS_PRESENT_EXPECTED_CIRC=1
+ break
+ fi
+ done
+ if [[ ${IS_PRESENT_EXPECTED_CIRC} == 0 ]]; then
+ echo "Good job! The circular dependency \"${EXPECTED_CIRC}\" is no longer present."
+ echo "Please remove it from EXPECTED_CIRCULAR_DEPENDENCIES in $0"
+ echo "to make sure this circular dependency is not accidentally reintroduced."
+ echo
+ EXIT_CODE=1
+ fi
+done
+
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-filenames.sh b/test/lint/lint-filenames.sh
new file mode 100755
index 0000000000..5391e43d91
--- /dev/null
+++ b/test/lint/lint-filenames.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Make sure only lowercase alphanumerics (a-z0-9), underscores (_),
+# hyphens (-) and dots (.) are used in source code filenames.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+OUTPUT=$(git ls-files --full-name -- "*.[cC][pP][pP]" "*.[hH]" "*.[pP][yY]" "*.[sS][hH]" | \
+ grep -vE '^[a-z0-9_./-]+$' | \
+ grep -vE '^src/(secp256k1|univalue)/')
+
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Use only lowercase alphanumerics (a-z0-9), underscores (_), hyphens (-) and dots (.)"
+ echo "in source code filenames:"
+ echo
+ echo "${OUTPUT}"
+ EXIT_CODE=1
+fi
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py
new file mode 100755
index 0000000000..2fb35fd8ca
--- /dev/null
+++ b/test/lint/lint-format-strings.py
@@ -0,0 +1,291 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Lint format strings: This program checks that the number of arguments passed
+# to a variadic format string function matches the number of format specifiers
+# in the format string.
+
+import argparse
+import re
+import sys
+
+FALSE_POSITIVES = [
+ ("src/dbwrapper.cpp", "vsnprintf(p, limit - p, format, backup_ap)"),
+ ("src/index/base.cpp", "FatalError(const char* fmt, const Args&... args)"),
+ ("src/netbase.cpp", "LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args)"),
+ ("src/util.cpp", "strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION))"),
+ ("src/util.cpp", "strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION)"),
+ ("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"),
+ ("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"),
+ ("src/logging.h", "LogPrintf(const char* fmt, const Args&... args)"),
+]
+
+
+def parse_function_calls(function_name, source_code):
+ """Return an array with all calls to function function_name in string source_code.
+ Preprocessor directives and C++ style comments ("//") in source_code are removed.
+
+ >>> len(parse_function_calls("foo", "foo();bar();foo();bar();"))
+ 2
+ >>> parse_function_calls("foo", "foo(1);bar(1);foo(2);bar(2);")[0].startswith("foo(1);")
+ True
+ >>> parse_function_calls("foo", "foo(1);bar(1);foo(2);bar(2);")[1].startswith("foo(2);")
+ True
+ >>> len(parse_function_calls("foo", "foo();bar();// foo();bar();"))
+ 1
+ >>> len(parse_function_calls("foo", "#define FOO foo();"))
+ 0
+ """
+ assert(type(function_name) is str and type(source_code) is str and function_name)
+ lines = [re.sub("// .*", " ", line).strip()
+ for line in source_code.split("\n")
+ if not line.strip().startswith("#")]
+ return re.findall(r"[^a-zA-Z_](?=({}\(.*).*)".format(function_name), " " + " ".join(lines))
+
+
+def normalize(s):
+ """Return a normalized version of string s with newlines, tabs and C style comments ("/* ... */")
+ replaced with spaces. Multiple spaces are replaced with a single space.
+
+ >>> normalize(" /* nothing */ foo\tfoo /* bar */ foo ")
+ 'foo foo foo'
+ """
+ assert(type(s) is str)
+ s = s.replace("\n", " ")
+ s = s.replace("\t", " ")
+ s = re.sub("/\*.*?\*/", " ", s)
+ s = re.sub(" {2,}", " ", s)
+ return s.strip()
+
+
+ESCAPE_MAP = {
+ r"\n": "[escaped-newline]",
+ r"\t": "[escaped-tab]",
+ r'\"': "[escaped-quote]",
+}
+
+
+def escape(s):
+ """Return the escaped version of string s with "\\\"", "\\n" and "\\t" escaped as
+ "[escaped-backslash]", "[escaped-newline]" and "[escaped-tab]".
+
+ >>> unescape(escape("foo")) == "foo"
+ True
+ >>> escape(r'foo \\t foo \\n foo \\\\ foo \\ foo \\"bar\\"')
+ 'foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\ foo \\\\ foo [escaped-quote]bar[escaped-quote]'
+ """
+ assert(type(s) is str)
+ for raw_value, escaped_value in ESCAPE_MAP.items():
+ s = s.replace(raw_value, escaped_value)
+ return s
+
+
+def unescape(s):
+ """Return the unescaped version of escaped string s.
+ Reverses the replacements made in function escape(s).
+
+ >>> unescape(escape("bar"))
+ 'bar'
+ >>> unescape("foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\ foo \\\\ foo [escaped-quote]bar[escaped-quote]")
+ 'foo \\\\t foo \\\\n foo \\\\\\\\ foo \\\\ foo \\\\"bar\\\\"'
+ """
+ assert(type(s) is str)
+ for raw_value, escaped_value in ESCAPE_MAP.items():
+ s = s.replace(escaped_value, raw_value)
+ return s
+
+
+def parse_function_call_and_arguments(function_name, function_call):
+ """Split string function_call into an array of strings consisting of:
+ * the string function_call followed by "("
+ * the function call argument #1
+ * ...
+ * the function call argument #n
+ * a trailing ");"
+
+ The strings returned are in escaped form. See escape(...).
+
+ >>> parse_function_call_and_arguments("foo", 'foo("%s", "foo");')
+ ['foo(', '"%s",', ' "foo"', ')']
+ >>> parse_function_call_and_arguments("foo", 'foo("%s", "foo");')
+ ['foo(', '"%s",', ' "foo"', ')']
+ >>> parse_function_call_and_arguments("foo", 'foo("%s %s", "foo", "bar");')
+ ['foo(', '"%s %s",', ' "foo",', ' "bar"', ')']
+ >>> parse_function_call_and_arguments("fooprintf", 'fooprintf("%050d", i);')
+ ['fooprintf(', '"%050d",', ' i', ')']
+ >>> parse_function_call_and_arguments("foo", 'foo(bar(foobar(barfoo("foo"))), foobar); barfoo')
+ ['foo(', 'bar(foobar(barfoo("foo"))),', ' foobar', ')']
+ >>> parse_function_call_and_arguments("foo", "foo()")
+ ['foo(', '', ')']
+ >>> parse_function_call_and_arguments("foo", "foo(123)")
+ ['foo(', '123', ')']
+ >>> parse_function_call_and_arguments("foo", 'foo("foo")')
+ ['foo(', '"foo"', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);')
+ ['strprintf(', '"%s (%d)",', ' std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf),', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo<wchar_t>().to_bytes(buf), err);')
+ ['strprintf(', '"%s (%d)",', ' foo<wchar_t>().to_bytes(buf),', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo().to_bytes(buf), err);')
+ ['strprintf(', '"%s (%d)",', ' foo().to_bytes(buf),', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo << 1, err);')
+ ['strprintf(', '"%s (%d)",', ' foo << 1,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo<bar>() >> 1, err);')
+ ['strprintf(', '"%s (%d)",', ' foo<bar>() >> 1,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo < 1 ? bar : foobar, err);')
+ ['strprintf(', '"%s (%d)",', ' foo < 1 ? bar : foobar,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo < 1, err);')
+ ['strprintf(', '"%s (%d)",', ' foo < 1,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo > 1 ? bar : foobar, err);')
+ ['strprintf(', '"%s (%d)",', ' foo > 1 ? bar : foobar,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo > 1, err);')
+ ['strprintf(', '"%s (%d)",', ' foo > 1,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo <= 1, err);')
+ ['strprintf(', '"%s (%d)",', ' foo <= 1,', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo <= bar<1, 2>(1, 2), err);')
+ ['strprintf(', '"%s (%d)",', ' foo <= bar<1, 2>(1, 2),', ' err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2)?bar:foobar,err)');
+ ['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2)?bar:foobar,', 'err', ')']
+ >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2),err)');
+ ['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2),', 'err', ')']
+ """
+ assert(type(function_name) is str and type(function_call) is str and function_name)
+ remaining = normalize(escape(function_call))
+ expected_function_call = "{}(".format(function_name)
+ assert(remaining.startswith(expected_function_call))
+ parts = [expected_function_call]
+ remaining = remaining[len(expected_function_call):]
+ open_parentheses = 1
+ open_template_arguments = 0
+ in_string = False
+ parts.append("")
+ for i, char in enumerate(remaining):
+ parts.append(parts.pop() + char)
+ if char == "\"":
+ in_string = not in_string
+ continue
+ if in_string:
+ continue
+ if char == "(":
+ open_parentheses += 1
+ continue
+ if char == ")":
+ open_parentheses -= 1
+ if open_parentheses > 1:
+ continue
+ if open_parentheses == 0:
+ parts.append(parts.pop()[:-1])
+ parts.append(char)
+ break
+ prev_char = remaining[i - 1] if i - 1 >= 0 else None
+ next_char = remaining[i + 1] if i + 1 <= len(remaining) - 1 else None
+ if char == "<" and next_char not in [" ", "<", "="] and prev_char not in [" ", "<"]:
+ open_template_arguments += 1
+ continue
+ if char == ">" and next_char not in [" ", ">", "="] and prev_char not in [" ", ">"] and open_template_arguments > 0:
+ open_template_arguments -= 1
+ if open_template_arguments > 0:
+ continue
+ if char == ",":
+ parts.append("")
+ return parts
+
+
+def parse_string_content(argument):
+ """Return the text within quotes in string argument.
+
+ >>> parse_string_content('1 "foo %d bar" 2')
+ 'foo %d bar'
+ >>> parse_string_content('1 foobar 2')
+ ''
+ >>> parse_string_content('1 "bar" 2')
+ 'bar'
+ >>> parse_string_content('1 "foo" 2 "bar" 3')
+ 'foobar'
+ >>> parse_string_content('1 "foo" 2 " " "bar" 3')
+ 'foo bar'
+ >>> parse_string_content('""')
+ ''
+ >>> parse_string_content('')
+ ''
+ >>> parse_string_content('1 2 3')
+ ''
+ """
+ assert(type(argument) is str)
+ string_content = ""
+ in_string = False
+ for char in normalize(escape(argument)):
+ if char == "\"":
+ in_string = not in_string
+ elif in_string:
+ string_content += char
+ return string_content
+
+
+def count_format_specifiers(format_string):
+ """Return the number of format specifiers in string format_string.
+
+ >>> count_format_specifiers("foo bar foo")
+ 0
+ >>> count_format_specifiers("foo %d bar foo")
+ 1
+ >>> count_format_specifiers("foo %d bar %i foo")
+ 2
+ >>> count_format_specifiers("foo %d bar %i foo %% foo")
+ 2
+ >>> count_format_specifiers("foo %d bar %i foo %% foo %d foo")
+ 3
+ >>> count_format_specifiers("foo %d bar %i foo %% foo %*d foo")
+ 4
+ """
+ assert(type(format_string) is str)
+ n = 0
+ in_specifier = False
+ for i, char in enumerate(format_string):
+ if format_string[i - 1:i + 1] == "%%" or format_string[i:i + 2] == "%%":
+ pass
+ elif char == "%":
+ in_specifier = True
+ n += 1
+ elif char in "aAcdeEfFgGinopsuxX":
+ in_specifier = False
+ elif in_specifier and char == "*":
+ n += 1
+ return n
+
+
+def main():
+ parser = argparse.ArgumentParser(description="This program checks that the number of arguments passed "
+ "to a variadic format string function matches the number of format "
+ "specifiers in the format string.")
+ parser.add_argument("--skip-arguments", type=int, help="number of arguments before the format string "
+ "argument (e.g. 1 in the case of fprintf)", default=0)
+ parser.add_argument("function_name", help="function name (e.g. fprintf)", default=None)
+ parser.add_argument("file", type=argparse.FileType("r", encoding="utf-8"), nargs="*", help="C++ source code file (e.g. foo.cpp)")
+ args = parser.parse_args()
+
+ exit_code = 0
+ for f in args.file:
+ for function_call_str in parse_function_calls(args.function_name, f.read()):
+ parts = parse_function_call_and_arguments(args.function_name, function_call_str)
+ relevant_function_call_str = unescape("".join(parts))[:512]
+ if (f.name, relevant_function_call_str) in FALSE_POSITIVES:
+ continue
+ if len(parts) < 3 + args.skip_arguments:
+ exit_code = 1
+ print("{}: Could not parse function call string \"{}(...)\": {}".format(f.name, args.function_name, relevant_function_call_str))
+ continue
+ argument_count = len(parts) - 3 - args.skip_arguments
+ format_str = parse_string_content(parts[1 + args.skip_arguments])
+ format_specifier_count = count_format_specifiers(format_str)
+ if format_specifier_count != argument_count:
+ exit_code = 1
+ print("{}: Expected {} argument(s) after format string but found {} argument(s): {}".format(f.name, format_specifier_count, argument_count, relevant_function_call_str))
+ continue
+ sys.exit(exit_code)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh
new file mode 100755
index 0000000000..2c443abf6b
--- /dev/null
+++ b/test/lint/lint-format-strings.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Lint format strings: This program checks that the number of arguments passed
+# to a variadic format string function matches the number of format specifiers
+# in the format string.
+
+export LC_ALL=C
+
+FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=(
+ FatalError,0
+ fprintf,1
+ LogConnectFailure,1
+ LogPrint,1
+ LogPrintf,0
+ printf,0
+ snprintf,2
+ sprintf,1
+ strprintf,0
+ vfprintf,1
+ vprintf,1
+ vsnprintf,1
+ vsprintf,1
+ WalletLogPrintf,0
+)
+
+EXIT_CODE=0
+if ! python3 -m doctest test/lint/lint-format-strings.py; then
+ EXIT_CODE=1
+fi
+for S in "${FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS[@]}"; do
+ IFS="," read -r FUNCTION_NAME SKIP_ARGUMENTS <<< "${S}"
+ for MATCHING_FILE in $(git grep --full-name -l "${FUNCTION_NAME}" -- "*.c" "*.cpp" "*.h" | sort | grep -vE "^src/(leveldb|secp256k1|tinyformat|univalue)"); do
+ MATCHING_FILES+=("${MATCHING_FILE}")
+ done
+ if ! test/lint/lint-format-strings.py --skip-arguments "${SKIP_ARGUMENTS}" "${FUNCTION_NAME}" "${MATCHING_FILES[@]}"; then
+ EXIT_CODE=1
+ fi
+done
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh
index 6a0dd556bb..464969794b 100755
--- a/test/lint/lint-include-guards.sh
+++ b/test/lint/lint-include-guards.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,6 +6,7 @@
#
# Check include guards.
+export LC_ALL=C
HEADER_ID_PREFIX="BITCOIN_"
HEADER_ID_SUFFIX="_H"
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 2c3456b644..a3e7681d45 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,9 +6,13 @@
#
# Check for duplicate includes.
# Guard against accidental introduction of new Boost dependencies.
+# Check includes: Check for duplicate includes. Enforce bracket syntax includes.
+
+export LC_ALL=C
+IGNORE_REGEXP="/(leveldb|secp256k1|univalue)/"
filter_suffix() {
- git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "/(leveldb|secp256k1|univalue)/"
+ git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "${IGNORE_REGEXP}"
}
EXIT_CODE=0
@@ -43,20 +47,15 @@ fi
EXPECTED_BOOST_INCLUDES=(
boost/algorithm/string.hpp
- boost/algorithm/string/case_conv.hpp
boost/algorithm/string/classification.hpp
- boost/algorithm/string/join.hpp
- boost/algorithm/string/predicate.hpp
boost/algorithm/string/replace.hpp
boost/algorithm/string/split.hpp
- boost/assign/std/vector.hpp
boost/bind.hpp
boost/chrono/chrono.hpp
boost/date_time/posix_time/posix_time.hpp
boost/filesystem.hpp
boost/filesystem/detail/utf8_codecvt_facet.hpp
boost/filesystem/fstream.hpp
- boost/interprocess/sync/file_lock.hpp
boost/multi_index/hashed_index.hpp
boost/multi_index/ordered_index.hpp
boost/multi_index/sequenced_index.hpp
@@ -64,8 +63,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/optional.hpp
boost/preprocessor/cat.hpp
boost/preprocessor/stringize.hpp
- boost/program_options/detail/config_file.hpp
- boost/scoped_array.hpp
boost/signals2/connection.hpp
boost/signals2/last_value.hpp
boost/signals2/signal.hpp
@@ -105,4 +102,12 @@ for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do
fi
done
+QUOTE_SYNTAX_INCLUDES=$(git grep '^#include "' -- "*.cpp" "*.h" | grep -Ev "${IGNORE_REGEXP}")
+if [[ ${QUOTE_SYNTAX_INCLUDES} != "" ]]; then
+ echo "Please use bracket syntax includes (\"#include <foo.h>\") instead of quote syntax includes:"
+ echo "${QUOTE_SYNTAX_INCLUDES}"
+ echo
+ EXIT_CODE=1
+fi
+
exit ${EXIT_CODE}
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index 3144f2c841..cbee437c91 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -1,5 +1,6 @@
-#!/bin/bash
+#!/usr/bin/env bash
+export LC_ALL=C
KNOWN_VIOLATIONS=(
"src/base58.cpp:.*isspace"
"src/bitcoin-tx.cpp.*stoul"
@@ -10,11 +11,9 @@ KNOWN_VIOLATIONS=(
"src/dbwrapper.cpp:.*vsnprintf"
"src/httprpc.cpp.*trim"
"src/init.cpp:.*atoi"
- "src/netbase.cpp.*to_lower"
"src/qt/rpcconsole.cpp:.*atoi"
"src/qt/rpcconsole.cpp:.*isdigit"
"src/rest.cpp:.*strtol"
- "src/rpc/server.cpp.*to_upper"
"src/test/dbwrapper_tests.cpp:.*snprintf"
"src/test/getarg_tests.cpp.*split"
"src/torcontrol.cpp:.*atoi"
@@ -198,11 +197,11 @@ REGEXP_IGNORE_KNOWN_VIOLATIONS=$(join_array "|" "${KNOWN_VIOLATIONS[@]}")
# Invoke "git grep" only once in order to minimize run-time
REGEXP_LOCALE_DEPENDENT_FUNCTIONS=$(join_array "|" "${LOCALE_DEPENDENT_FUNCTIONS[@]}")
-GIT_GREP_OUTPUT=$(git grep -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(|_r|_s))[^a-zA-Z0-9_\`'\"<>]" -- "*.cpp" "*.h")
+GIT_GREP_OUTPUT=$(git grep -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(_r|_s)?)[^a-zA-Z0-9_\`'\"<>]" -- "*.cpp" "*.h")
EXIT_CODE=0
for LOCALE_DEPENDENT_FUNCTION in "${LOCALE_DEPENDENT_FUNCTIONS[@]}"; do
- MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(|_r|_s)[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \
+ MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \
grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}" | \
grep -vE 'fprintf\(.*(stdout|stderr)')
if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != "" ]]; then
diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh
index 35be13ec19..1afd4cfc1a 100755
--- a/test/lint/lint-logs.sh
+++ b/test/lint/lint-logs.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -12,7 +12,7 @@
# There are some instances of LogPrintf() in comments. Those can be
# ignored
-
+export LC_ALL=C
UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \
grep -v '\\n"' | \
grep -v "/\* Continued \*/" | \
diff --git a/test/lint/lint-python-shebang.sh b/test/lint/lint-python-shebang.sh
index f5c5971c03..4ff87f0bf7 100755
--- a/test/lint/lint-python-shebang.sh
+++ b/test/lint/lint-python-shebang.sh
@@ -1,5 +1,7 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Shebang must use python3 (not python or python2)
+
+export LC_ALL=C
EXIT_CODE=0
for PYTHON_FILE in $(git ls-files -- "*.py"); do
if [[ $(head -c 2 "${PYTHON_FILE}") == "#!" &&
diff --git a/test/lint/lint-python-utf8-encoding.sh b/test/lint/lint-python-utf8-encoding.sh
new file mode 100755
index 0000000000..d03c20205d
--- /dev/null
+++ b/test/lint/lint-python-utf8-encoding.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Make sure we explicitly open all text files using UTF-8 (or ASCII) encoding to
+# avoid potential issues on the BSDs where the locale is not always set.
+
+export LC_ALL=C
+EXIT_CODE=0
+OUTPUT=$(git grep " open(" -- "*.py" | grep -vE "encoding=.(ascii|utf8|utf-8)." | grep -vE "open\([^,]*, ['\"][^'\"]*b[^'\"]*['\"]")
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Python's open(...) seems to be used to open text files without explicitly"
+ echo "specifying encoding=\"utf8\":"
+ echo
+ echo "${OUTPUT}"
+ EXIT_CODE=1
+fi
+OUTPUT=$(git grep "check_output(" -- "*.py" | grep "universal_newlines=True" | grep -vE "encoding=.(ascii|utf8|utf-8).")
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Python's check_output(...) seems to be used to get program outputs without explicitly"
+ echo "specifying encoding=\"utf8\":"
+ echo
+ echo "${OUTPUT}"
+ EXIT_CODE=1
+fi
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index 7d3555b6d4..4f4542ff0c 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -6,6 +6,8 @@
#
# Check for specified flake8 warnings in python files.
+export LC_ALL=C
+
# E101 indentation contains mixed spaces and tabs
# E112 expected an indented block
# E113 unexpected indentation
@@ -28,6 +30,8 @@
# E306 expected 1 blank line before a nested definition
# E401 multiple imports on one line
# E402 module level import not at top of file
+# F403 'from foo_module import *' used; unable to detect undefined names
+# F405 foo_function may be undefined, or defined from star imports: bar_module
# E502 the backslash is redundant between brackets
# E701 multiple statements on one line (colon)
# E702 multiple statements on one line (semicolon)
@@ -75,4 +79,12 @@
# W605 invalid escape sequence "x"
# W606 'async' and 'await' are reserved keywords starting with Python 3.7
-flake8 --ignore=B,C,E,F,I,N,W --select=E101,E112,E113,E115,E116,E125,E129,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,F401,E901,E902,F402,F404,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W191,W291,W292,W293,W504,W601,W602,W603,W604,W605,W606 .
+if ! command -v flake8 > /dev/null; then
+ echo "Skipping Python linting since flake8 is not installed. Install by running \"pip3 install flake8\""
+ exit 0
+elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then
+ echo "Skipping Python linting since flake8 is running under Python 2. Install the Python 3 version of flake8 by running \"pip3 install flake8\""
+ exit 0
+fi
+
+PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=E101,E112,E113,E115,E116,E125,E129,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,E901,E902,F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W191,W291,W292,W293,W504,W601,W602,W603,W604,W605,W606 .
diff --git a/test/lint/lint-qt.sh b/test/lint/lint-qt.sh
new file mode 100755
index 0000000000..2e77682aa2
--- /dev/null
+++ b/test/lint/lint-qt.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Check for SIGNAL/SLOT connect style, removed since Qt4 support drop.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+
+OUTPUT=$(git grep -E '(SIGNAL|, ?SLOT)\(' -- src/qt)
+if [[ ${OUTPUT} != "" ]]; then
+ echo "Use Qt5 connect style in:"
+ echo "$OUTPUT"
+ EXIT_CODE=1
+fi
+
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-shell-locale.sh b/test/lint/lint-shell-locale.sh
new file mode 100755
index 0000000000..084dc93f76
--- /dev/null
+++ b/test/lint/lint-shell-locale.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Make sure all shell scripts:
+# a.) explicitly opt out of locale dependence using
+# "export LC_ALL=C" or "export LC_ALL=C.UTF-8", or
+# b.) explicitly opt in to locale dependence using the annotation below.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+for SHELL_SCRIPT in $(git ls-files -- "*.sh" | grep -vE "src/(secp256k1|univalue)/"); do
+ if grep -q "# This script is intentionally locale dependent by not setting \"export LC_ALL=C\"" "${SHELL_SCRIPT}"; then
+ continue
+ fi
+ FIRST_NON_COMMENT_LINE=$(grep -vE '^(#.*)?$' "${SHELL_SCRIPT}" | head -1)
+ if [[ ${FIRST_NON_COMMENT_LINE} != "export LC_ALL=C" && ${FIRST_NON_COMMENT_LINE} != "export LC_ALL=C.UTF-8" ]]; then
+ echo "Missing \"export LC_ALL=C\" (to avoid locale dependence) as first non-comment non-empty line in ${SHELL_SCRIPT}"
+ EXIT_CODE=1
+ fi
+done
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 5f5fa9a925..9af3c10ed6 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,7 +6,24 @@
#
# Check for shellcheck warnings in shell scripts.
+export LC_ALL=C
+
+# The shellcheck binary segfault/coredumps in Travis with LC_ALL=C
+# It does not do so in Ubuntu 14.04, 16.04, 18.04 in versions 0.3.3, 0.3.7, 0.4.6
+# respectively. So export LC_ALL=C is set as required by lint-shell-locale.sh
+# but unset here in case of running in Travis.
+if [ "$TRAVIS" = "true" ]; then
+ unset LC_ALL
+fi
+
+if ! command -v shellcheck > /dev/null; then
+ echo "Skipping shell linting since shellcheck is not installed."
+ exit 0
+fi
+
# Disabled warnings:
+# SC1087: Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet).
+# SC1117: Backslash is literal in "\.". Prefer explicit escaping: "\\.".
# SC2001: See if you can use ${variable//search/replace} instead.
# SC2004: $/${} is unnecessary on arithmetic variables.
# SC2005: Useless echo? Instead of 'echo $(cmd)', just use 'cmd'.
@@ -23,5 +40,8 @@
# SC2166: Prefer [ p ] && [ q ] as [ p -a q ] is not well defined.
# SC2166: Prefer [ p ] || [ q ] as [ p -o q ] is not well defined.
# SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
-shellcheck -e SC2001,SC2004,SC2005,SC2006,SC2016,SC2028,SC2046,SC2048,SC2066,SC2086,SC2116,SC2148,SC2162,SC2166,SC2181 \
+# SC2206: Quote to prevent word splitting, or split robustly with mapfile or read -a.
+# SC2207: Prefer mapfile or read -a to split command output (or quote to avoid splitting).
+# SC2230: which is non-standard. Use builtin 'command -v' instead.
+shellcheck -e SC1087,SC1117,SC2001,SC2004,SC2005,SC2006,SC2016,SC2028,SC2046,SC2048,SC2066,SC2086,SC2116,SC2148,SC2162,SC2166,SC2181,SC2206,SC2207,SC2230 \
$(git ls-files -- "*.sh" | grep -vE 'src/(secp256k1|univalue)/')
diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt
new file mode 100644
index 0000000000..9a49f32271
--- /dev/null
+++ b/test/lint/lint-spelling.ignore-words.txt
@@ -0,0 +1,6 @@
+cas
+hights
+mor
+objext
+unselect
+useable
diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh
new file mode 100755
index 0000000000..ebeafd7d58
--- /dev/null
+++ b/test/lint/lint-spelling.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+# Warn in case of spelling errors.
+# Note: Will exit successfully regardless of spelling errors.
+
+export LC_ALL=C
+
+EXIT_CODE=0
+IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt
+if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/qt/locale/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then
+ echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}"
+ EXIT_CODE=1
+fi
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-tests.sh b/test/lint/lint-tests.sh
index ffc0660551..35d11023eb 100755
--- a/test/lint/lint-tests.sh
+++ b/test/lint/lint-tests.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -6,6 +6,7 @@
#
# Check the test suite naming conventions
+export LC_ALL=C
EXIT_CODE=0
NAMING_INCONSISTENCIES=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index c5d43043d5..beb7ec42f4 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -8,6 +8,7 @@
# We can't run this check unless we know the commit range for the PR.
+export LC_ALL=C
while getopts "?" opt; do
case $opt in
?)
diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py
index 30bd13d0dc..92fef30e13 100755
--- a/test/util/bitcoin-util-test.py
+++ b/test/util/bitcoin-util-test.py
@@ -28,7 +28,7 @@ import sys
def main():
config = configparser.ConfigParser()
config.optionxform = str
- config.readfp(open(os.path.join(os.path.dirname(__file__), "../config.ini")))
+ config.read_file(open(os.path.join(os.path.dirname(__file__), "../config.ini"), encoding="utf8"))
env_conf = dict(config.items('environment'))
parser = argparse.ArgumentParser(description=__doc__)
@@ -49,7 +49,7 @@ def main():
def bctester(testDir, input_basename, buildenv):
""" Loads and parses the input file, runs all tests and reports results"""
input_filename = os.path.join(testDir, input_basename)
- raw_data = open(input_filename).read()
+ raw_data = open(input_filename, encoding="utf8").read()
input_data = json.loads(raw_data)
failed_testcases = []
@@ -86,7 +86,7 @@ def bctest(testDir, testObj, buildenv):
inputData = None
if "input" in testObj:
filename = os.path.join(testDir, testObj["input"])
- inputData = open(filename).read()
+ inputData = open(filename, encoding="utf8").read()
stdinCfg = subprocess.PIPE
# Read the expected output data (if there is any)
@@ -97,7 +97,7 @@ def bctest(testDir, testObj, buildenv):
outputFn = testObj['output_cmp']
outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
try:
- outputData = open(os.path.join(testDir, outputFn)).read()
+ outputData = open(os.path.join(testDir, outputFn), encoding="utf8").read()
except:
logging.error("Output file " + outputFn + " can not be opened")
raise
diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json
index a115aa30d9..f2213f4f2e 100644
--- a/test/util/data/bitcoin-util-test.json
+++ b/test/util/data/bitcoin-util-test.json
@@ -27,6 +27,12 @@
"description": "Creates a blank transaction when nothing is piped into bitcoin-tx (output in json)"
},
{ "exec": "./bitcoin-tx",
+ "args": ["-create", "nversion=1foo"],
+ "return_code": 1,
+ "error_txt": "error: Invalid TX version requested",
+ "description": "Tests the check for invalid nversion value"
+ },
+ { "exec": "./bitcoin-tx",
"args": ["-", "delin=1"],
"input": "tx394b54bb.hex",
"output_cmp": "tt-delin1-out.hex",
@@ -46,6 +52,13 @@
"description": "Attempts to delete an input with a bad index from a transaction. Expected to fail."
},
{ "exec": "./bitcoin-tx",
+ "args": ["-", "delin=1foo"],
+ "input": "tx394b54bb.hex",
+ "return_code": 1,
+ "error_txt": "error: Invalid TX input index",
+ "description": "Tests the check for an invalid input index with delin"
+ },
+ { "exec": "./bitcoin-tx",
"args": ["-", "delout=1"],
"input": "tx394b54bb.hex",
"output_cmp": "tt-delout1-out.hex",
@@ -65,6 +78,13 @@
"description": "Attempts to delete an output with a bad index from a transaction. Expected to fail."
},
{ "exec": "./bitcoin-tx",
+ "args": ["-", "delout=1foo"],
+ "input": "tx394b54bb.hex",
+ "return_code": 1,
+ "error_txt": "error: Invalid TX output index",
+ "description": "Tests the check for an invalid output index with delout"
+ },
+ { "exec": "./bitcoin-tx",
"args": ["-", "locktime=317000"],
"input": "tx394b54bb.hex",
"output_cmp": "tt-locktime317000-out.hex",
@@ -77,6 +97,29 @@
"description": "Adds an nlocktime to a transaction (output in json)"
},
{ "exec": "./bitcoin-tx",
+ "args": ["-create", "locktime=317000foo"],
+ "return_code": 1,
+ "error_txt": "error: Invalid TX locktime requested",
+ "description": "Tests the check for invalid locktime value"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "replaceable=0foo"],
+ "return_code": 1,
+ "error_txt": "error: Invalid TX input index",
+ "description": "Tests the check for an invalid input index with replaceable"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0x"],
+ "return_code": 1,
+ "error_txt": "error: invalid TX input vout",
+ "description": "Tests the check for an invalid vout value when adding an input"
+ },
+ { "exec": "./bitcoin-tx",
"args":
["-create",
"outaddr=1"],
@@ -227,6 +270,18 @@
},
{ "exec": "./bitcoin-tx",
"args":
+ ["-create",
+ "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
+ "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
+ "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":\"0foo\",\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
+ "sign=ALL",
+ "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
+ "return_code": 1,
+ "error_txt": "error: prevtxs internal object typecheck fail",
+ "description": "Tests the check for invalid vout index in prevtxs for sign"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"],
"output_cmp": "txcreateoutpubkey1.hex",
"description": "Creates a new transaction with a single pay-to-pubkey output"
diff --git a/test/util/data/txcreatesignv1.hex b/test/util/data/txcreatesignv1.hex
index a46fcc88cb..40039319bd 100644
--- a/test/util/data/txcreatesignv1.hex
+++ b/test/util/data/txcreatesignv1.hex
@@ -1 +1 @@
-01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
+01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a4730440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
diff --git a/test/util/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json
index 64e5137f4b..7a06aa9ffe 100644
--- a/test/util/data/txcreatesignv1.json
+++ b/test/util/data/txcreatesignv1.json
@@ -1,18 +1,18 @@
{
- "txid": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
- "hash": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
+ "txid": "ffc7e509ec3fd60a182eb712621d41a47dc7d4ff310a70826c2fb0e9afb3fa02",
+ "hash": "ffc7e509ec3fd60a182eb712621d41a47dc7d4ff310a70826c2fb0e9afb3fa02",
"version": 1,
- "size": 224,
- "vsize": 224,
- "weight": 896,
+ "size": 223,
+ "vsize": 223,
+ "weight": 892,
"locktime": 0,
"vin": [
{
"txid": "4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485",
"vout": 0,
"scriptSig": {
- "asm": "304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e2[ALL] 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
- "hex": "48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
+ "asm": "30440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e[ALL] 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ "hex": "4730440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
},
"sequence": 4294967295
}
@@ -32,5 +32,5 @@
}
}
],
- "hex": "01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000"
+ "hex": "01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a4730440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000"
}
diff --git a/test/util/rpcauth-test.py b/test/util/rpcauth-test.py
index 2456feb102..46e9fbc739 100755
--- a/test/util/rpcauth-test.py
+++ b/test/util/rpcauth-test.py
@@ -18,7 +18,7 @@ class TestRPCAuth(unittest.TestCase):
config_path = os.path.abspath(
os.path.join(os.sep, os.path.abspath(os.path.dirname(__file__)),
"../config.ini"))
- with open(config_path) as config_file:
+ with open(config_path, encoding="utf8") as config_file:
config.read_file(config_file)
sys.path.insert(0, os.path.dirname(config['environment']['RPCAUTH']))
self.rpcauth = importlib.import_module('rpcauth')