aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/devtools/README.md2
-rwxr-xr-xcontrib/devtools/circular-dependencies.py9
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/devtools/test_deterministic_coverage.sh151
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml6
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml2
-rw-r--r--contrib/linearize/README.md3
-rwxr-xr-xcontrib/linearize/linearize-data.py6
-rw-r--r--contrib/zmq/zmq_sub3.4.py90
10 files changed, 171 insertions, 102 deletions
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index 6ee65f40be..d66eff66be 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -167,7 +167,7 @@ still compatible with the minimum supported Linux distribution versions.
Example usage after a gitian build:
- find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
+ find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
If only supported symbols are used the return value will be 0 and the output will be empty.
diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py
index abfa5ed5ae..2e4657f1dd 100755
--- a/contrib/devtools/circular-dependencies.py
+++ b/contrib/devtools/circular-dependencies.py
@@ -8,9 +8,18 @@ MAPPING = {
'core_write.cpp': 'core_io.cpp',
}
+# Directories with header-based modules, where the assumption that .cpp files
+# define functions and variables declared in corresponding .h files is
+# incorrect.
+HEADER_MODULE_PATHS = [
+ 'interfaces/'
+]
+
def module_name(path):
if path in MAPPING:
path = MAPPING[path]
+ if any(path.startswith(dirpath) for dirpath in HEADER_MODULE_PATHS):
+ return path
if path.endswith(".h"):
return path[:-2]
if path.endswith(".c"):
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index c6158c9422..7729dd7257 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -9,7 +9,7 @@ still compatible with the minimum supported Linux distribution versions.
Example usage:
- find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
+ find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
'''
import subprocess
import re
diff --git a/contrib/devtools/test_deterministic_coverage.sh b/contrib/devtools/test_deterministic_coverage.sh
new file mode 100755
index 0000000000..16d03e1fff
--- /dev/null
+++ b/contrib/devtools/test_deterministic_coverage.sh
@@ -0,0 +1,151 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019 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 deterministic coverage across unit test runs.
+
+export LC_ALL=C
+
+# Use GCOV_EXECUTABLE="gcov" if compiling with gcc.
+# Use GCOV_EXECUTABLE="llvm-cov gcov" if compiling with clang.
+GCOV_EXECUTABLE="gcov"
+
+# Disable tests known to cause non-deterministic behaviour and document the source or point of non-determinism.
+NON_DETERMINISTIC_TESTS=(
+ "coinselector_tests/knapsack_solver_test" # coinselector_tests.cpp: if (equal_sets(setCoinsRet, setCoinsRet2))
+ "denialofservice_tests/DoS_mapOrphans" # denialofservice_tests.cpp: it = mapOrphanTransactions.lower_bound(InsecureRand256());
+ "fs_tests/fsbridge_fstream" # deterministic test failure?
+ "miner_tests/CreateNewBlock_validity" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "scheduler_tests/manythreads" # scheduler.cpp: CScheduler::serviceQueue()
+ "scheduler_tests/singlethreadedscheduler_ordered" # scheduler.cpp: CScheduler::serviceQueue()
+ "tx_validationcache_tests/checkinputs_test" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "tx_validationcache_tests/tx_mempool_block_doublespend" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "txindex_tests/txindex_initial_sync" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "txvalidation_tests/tx_mempool_reject_coinbase" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "validation_block_tests/processnewblock_signals_ordering" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/coin_mark_dirty_immature_credit" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/dummy_input_size_test" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/importmulti_rescan" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/importwallet_rescan" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/ListCoins" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/scan_for_wallet_transactions" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+ "wallet_tests/wallet_disableprivkeys" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10)
+)
+
+TEST_BITCOIN_BINARY="src/test/test_bitcoin"
+
+print_usage() {
+ echo "Usage: $0 [custom test filter (default: all but known non-deterministic tests)] [number of test runs (default: 2)]"
+}
+
+N_TEST_RUNS=2
+BOOST_TEST_RUN_FILTERS=""
+if [[ $# != 0 ]]; then
+ if [[ $1 == "--help" ]]; then
+ print_usage
+ exit
+ fi
+ PARSED_ARGUMENTS=0
+ if [[ $1 =~ [a-z] ]]; then
+ BOOST_TEST_RUN_FILTERS=$1
+ PARSED_ARGUMENTS=$((PARSED_ARGUMENTS + 1))
+ shift
+ fi
+ if [[ $1 =~ ^[0-9]+$ ]]; then
+ N_TEST_RUNS=$1
+ PARSED_ARGUMENTS=$((PARSED_ARGUMENTS + 1))
+ shift
+ fi
+ if [[ ${PARSED_ARGUMENTS} == 0 || $# -gt 2 || ${N_TEST_RUNS} -lt 2 ]]; then
+ print_usage
+ exit
+ fi
+fi
+if [[ ${BOOST_TEST_RUN_FILTERS} == "" ]]; then
+ BOOST_TEST_RUN_FILTERS="$(IFS=":"; echo "!${NON_DETERMINISTIC_TESTS[*]}" | sed 's/:/:!/g')"
+else
+ echo "Using Boost test filter: ${BOOST_TEST_RUN_FILTERS}"
+ echo
+fi
+
+if ! command -v gcov > /dev/null; then
+ echo "Error: gcov not installed. Exiting."
+ exit 1
+fi
+
+if ! command -v gcovr > /dev/null; then
+ echo "Error: gcovr not installed. Exiting."
+ exit 1
+fi
+
+if [[ ! -e ${TEST_BITCOIN_BINARY} ]]; then
+ echo "Error: Executable ${TEST_BITCOIN_BINARY} not found. Run \"./configure --enable-lcov\" and compile."
+ exit 1
+fi
+
+get_file_suffix_count() {
+ find src/ -type f -name "*.$1" | wc -l
+}
+
+if [[ $(get_file_suffix_count gcno) == 0 ]]; then
+ echo "Error: Could not find any *.gcno files. The *.gcno files are generated by the compiler. Run \"./configure --enable-lcov\" and re-compile."
+ exit 1
+fi
+
+get_covr_filename() {
+ echo "gcovr.run-$1.txt"
+}
+
+TEST_RUN_ID=0
+while [[ ${TEST_RUN_ID} -lt ${N_TEST_RUNS} ]]; do
+ TEST_RUN_ID=$((TEST_RUN_ID + 1))
+ echo "[$(date +"%Y-%m-%d %H:%M:%S")] Measuring coverage, run #${TEST_RUN_ID} of ${N_TEST_RUNS}"
+ find src/ -type f -name "*.gcda" -exec rm {} \;
+ if [[ $(get_file_suffix_count gcda) != 0 ]]; then
+ echo "Error: Stale *.gcda files found. Exiting."
+ exit 1
+ fi
+ TEST_OUTPUT_TEMPFILE=$(mktemp)
+ if ! BOOST_TEST_RUN_FILTERS="${BOOST_TEST_RUN_FILTERS}" ${TEST_BITCOIN_BINARY} > "${TEST_OUTPUT_TEMPFILE}" 2>&1; then
+ cat "${TEST_OUTPUT_TEMPFILE}"
+ rm "${TEST_OUTPUT_TEMPFILE}"
+ exit 1
+ fi
+ rm "${TEST_OUTPUT_TEMPFILE}"
+ if [[ $(get_file_suffix_count gcda) == 0 ]]; then
+ echo "Error: Running the test suite did not create any *.gcda files. The gcda files are generated when the instrumented test programs are executed. Run \"./configure --enable-lcov\" and re-compile."
+ exit 1
+ fi
+ GCOVR_TEMPFILE=$(mktemp)
+ if ! gcovr --gcov-executable "${GCOV_EXECUTABLE}" -r src/ > "${GCOVR_TEMPFILE}"; then
+ echo "Error: gcovr failed. Output written to ${GCOVR_TEMPFILE}. Exiting."
+ exit 1
+ fi
+ GCOVR_FILENAME=$(get_covr_filename ${TEST_RUN_ID})
+ mv "${GCOVR_TEMPFILE}" "${GCOVR_FILENAME}"
+ if grep -E "^TOTAL *0 *0 " "${GCOVR_FILENAME}"; then
+ echo "Error: Spurious gcovr output. Make sure the correct GCOV_EXECUTABLE variable is set in $0 (\"gcov\" for gcc, \"llvm-cov gcov\" for clang)."
+ exit 1
+ fi
+ if [[ ${TEST_RUN_ID} != 1 ]]; then
+ COVERAGE_DIFF=$(diff -u "$(get_covr_filename 1)" "${GCOVR_FILENAME}")
+ if [[ ${COVERAGE_DIFF} != "" ]]; then
+ echo
+ echo "The line coverage is non-deterministic between runs. Exiting."
+ echo
+ echo "The test suite must be deterministic in the sense that the set of lines executed at least"
+ echo "once must be identical between runs. This is a necessary condition for meaningful"
+ echo "coverage measuring."
+ echo
+ echo "${COVERAGE_DIFF}"
+ exit 1
+ fi
+ rm "${GCOVR_FILENAME}"
+ fi
+done
+
+echo
+echo "Coverage test passed: Deterministic coverage across ${N_TEST_RUNS} runs."
+exit
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index e97072c80a..1fc1ce98a9 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -30,7 +30,7 @@ packages:
- "faketime"
- "bsdmainutils"
- "ca-certificates"
-- "python"
+- "python3"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 87d8007ccb..1d9c31f9e7 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -23,9 +23,9 @@ packages:
- "libcap-dev"
- "libz-dev"
- "libbz2-dev"
-- "python"
-- "python-dev"
-- "python-setuptools"
+- "python3"
+- "python3-dev"
+- "python3-setuptools"
- "fonts-tuffy"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 31b9c309c7..2f1fb14c10 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -20,7 +20,7 @@ packages:
- "nsis"
- "zip"
- "ca-certificates"
-- "python"
+- "python3"
- "rename"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md
index 2985106982..25a1c7351a 100644
--- a/contrib/linearize/README.md
+++ b/contrib/linearize/README.md
@@ -1,6 +1,5 @@
# Linearize
-Construct a linear, no-fork, best version of the Bitcoin blockchain. The scripts
-run using Python 3 but are compatible with Python 2.
+Construct a linear, no-fork, best version of the Bitcoin blockchain.
## Step 1: Download hash list
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 56c1fbfc92..468aec04b5 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -16,7 +16,7 @@ import hashlib
import datetime
import time
from collections import namedtuple
-from binascii import hexlify, unhexlify
+from binascii import unhexlify
settings = {}
@@ -61,7 +61,7 @@ def calc_hash_str(blk_hdr):
hash = calc_hdr_hash(blk_hdr)
hash = bufreverse(hash)
hash = wordreverse(hash)
- hash_str = hexlify(hash).decode('utf-8')
+ hash_str = hash.hex()
return hash_str
def get_blk_dt(blk_hdr):
@@ -213,7 +213,7 @@ class BlockDataCopier:
inMagic = inhdr[:4]
if (inMagic != self.settings['netmagic']):
- print("Invalid magic: " + hexlify(inMagic).decode('utf-8'))
+ print("Invalid magic: " + inMagic.hex())
return
inLenLE = inhdr[4:]
su = struct.unpack("<I", inLenLE)
diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py
deleted file mode 100644
index 66fdf7887f..0000000000
--- a/contrib/zmq/zmq_sub3.4.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env python3
-# 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.
-
-"""
- ZMQ example using python3's asyncio
-
- Bitcoin should be started with the command line arguments:
- bitcoind -testnet -daemon \
- -zmqpubrawtx=tcp://127.0.0.1:28332 \
- -zmqpubrawblock=tcp://127.0.0.1:28332 \
- -zmqpubhashtx=tcp://127.0.0.1:28332 \
- -zmqpubhashblock=tcp://127.0.0.1:28332
-
- We use the asyncio library here. `self.handle()` installs itself as a
- future at the end of the function. Since it never returns with the event
- loop having an empty stack of futures, this creates an infinite loop. An
- alternative is to wrap the contents of `handle` inside `while True`.
-
- The `@asyncio.coroutine` decorator and the `yield from` syntax found here
- was introduced in python 3.4 and has been deprecated in favor of the `async`
- and `await` keywords respectively.
-
- A blocking example using python 2.7 can be obtained from the git history:
- https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
-"""
-
-import binascii
-import asyncio
-import zmq
-import zmq.asyncio
-import signal
-import struct
-import sys
-
-if (sys.version_info.major, sys.version_info.minor) < (3, 4):
- print("This example only works with Python 3.4 and greater")
- sys.exit(1)
-
-port = 28332
-
-class ZMQHandler():
- def __init__(self):
- self.loop = asyncio.get_event_loop()
- self.zmqContext = zmq.asyncio.Context()
-
- self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
- self.zmqSubSocket.setsockopt(zmq.RCVHWM, 0)
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
- self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
-
- @asyncio.coroutine
- def handle(self) :
- msg = yield from self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- body = msg[1]
- sequence = "Unknown"
- if len(msg[-1]) == 4:
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- sequence = str(msgSequence)
- if topic == b"hashblock":
- print('- HASH BLOCK ('+sequence+') -')
- print(binascii.hexlify(body))
- elif topic == b"hashtx":
- print('- HASH TX ('+sequence+') -')
- print(binascii.hexlify(body))
- elif topic == b"rawblock":
- print('- RAW BLOCK HEADER ('+sequence+') -')
- print(binascii.hexlify(body[:80]))
- elif topic == b"rawtx":
- print('- RAW TX ('+sequence+') -')
- print(binascii.hexlify(body))
- # schedule ourselves to receive the next message
- asyncio.ensure_future(self.handle())
-
- def start(self):
- self.loop.add_signal_handler(signal.SIGINT, self.stop)
- self.loop.create_task(self.handle())
- self.loop.run_forever()
-
- def stop(self):
- self.loop.stop()
- self.zmqContext.destroy()
-
-daemon = ZMQHandler()
-daemon.start()