diff options
52 files changed, 464 insertions, 634 deletions
diff --git a/.gitignore b/.gitignore index edc683e48b..809e851ff1 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ libtool src/config/bitcoin-config.h src/config/bitcoin-config.h.in src/config/stamp-h1 +src/obj share/setup.nsi share/qt/Info.plist @@ -132,3 +133,7 @@ db4/ # clang-check *.plist + +osx_volname +dist/ +*.background.tiff diff --git a/.travis.yml b/.travis.yml index 4d83042994..f515ab2b87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,101 +91,49 @@ jobs: - stage: test name: 'ARM [GOAL: install] [no unit or functional tests]' env: >- - HOST=arm-linux-gnueabihf - PACKAGES="python3 g++-arm-linux-gnueabihf" - RUN_UNIT_TESTS=false - RUN_FUNCTIONAL_TESTS=false - GOAL="install" - # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" - # This could be removed once the ABI change warning does not show up by default - BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" + FILE_ENV="./ci/test/00_setup_env_arm.sh" - stage: test name: 'Win64 [GOAL: deploy] [no gui or functional tests]' env: >- - HOST=x86_64-w64-mingw32 - PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" - RUN_FUNCTIONAL_TESTS=false - GOAL="deploy" - BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" + FILE_ENV="./ci/test/00_setup_env_win64.sh" - stage: test name: '32-bit + dash [GOAL: install] [GUI: no BIP70]' env: >- - HOST=i686-pc-linux-gnu - PACKAGES="g++-multilib python3-zmq" - GOAL="install" - BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --disable-bip70 --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" - CONFIG_SHELL="/bin/dash" + FILE_ENV="./ci/test/00_setup_env_i686.sh" - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package instead of depends Qt to speed up build and avoid timeout] [unsigned char]' env: >- - HOST=x86_64-unknown-linux-gnu - PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" - DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" - TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash - GOAL="install" - BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\"" + FILE_ENV="./ci/test/00_setup_env_amd64_qt5.sh" - stage: test name: 'x86_64 Linux [GOAL: install] [trusty] [no functional tests, no depends, only system libs]' env: >- - HOST=x86_64-unknown-linux-gnu - DOCKER_NAME_TAG=ubuntu:14.04 - PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" - NO_DEPENDS=1 - RUN_FUNCTIONAL_TESTS=false - GOAL="install" - BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no" + FILE_ENV="./ci/test/00_setup_env_amd64_trusty.sh" - stage: test name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs, sanitizers: thread (TSan), no wallet]' env: >- - HOST=x86_64-unknown-linux-gnu - DOCKER_NAME_TAG=ubuntu:16.04 - PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" - NO_DEPENDS=1 - GOAL="install" - BITCOIN_CONFIG="--enable-zmq --disable-wallet --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=thread --disable-hardening --disable-asm CC=clang CXX=clang++" + FILE_ENV="./ci/test/00_setup_env_amd64_tsan.sh" - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer]' env: >- - HOST=x86_64-unknown-linux-gnu - PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" - NO_DEPENDS=1 - GOAL="install" - BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" + FILE_ENV="./ci/test/00_setup_env_amd64_asan.sh" - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: fuzzer,address]' env: >- - HOST=x86_64-unknown-linux-gnu - PACKAGES="clang llvm python3 libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev" - NO_DEPENDS=1 - RUN_UNIT_TESTS=false - RUN_FUNCTIONAL_TESTS=false - RUN_FUZZ_TESTS=true - GOAL="install" - BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++" + FILE_ENV="./ci/test/00_setup_env_amd64_fuzz.sh" - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]' env: >- - HOST=x86_64-unknown-linux-gnu - PACKAGES="python3-zmq" - DEP_OPTS="NO_WALLET=1" - GOAL="install" - BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + FILE_ENV="./ci/test/00_setup_env_amd64_nowallet.sh" - stage: test name: 'macOS 10.10 [GOAL: deploy] [no functional tests]' env: >- - HOST=x86_64-apple-darwin14 - PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools" - OSX_SDK=10.11 - RUN_UNIT_TESTS=false - RUN_FUNCTIONAL_TESTS=false - GOAL="deploy" - BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror" + FILE_ENV="./ci/test/00_setup_env_mac.sh" diff --git a/Makefile.am b/Makefile.am index 712f2a454d..8b1e2a6b5b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -310,4 +310,5 @@ clean-docs: clean-local: clean-docs rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP) rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache share/rpcauth/__pycache__ + rm -rf osx_volname dist/ dpi36.background.tiff dpi72.background.tiff diff --git a/ci/README.md b/ci/README.md index 754cbc7c95..16c481158f 100644 --- a/ci/README.md +++ b/ci/README.md @@ -15,11 +15,17 @@ requires `docker` to be installed. To install all requirements on Ubuntu, run sudo apt install docker.io ccache bash git ``` -To run the test stage, +To run the default test stage, ``` ./ci/test_run_all.sh ``` +To run the test stage with a specific configuration, + +``` +FILE_ENV="./ci/test/00_setup_env_arm.sh" ./ci/test_run_all.sh +``` + Be aware that the tests will be build and run in-place, so please run at your own risk. If the repository is not a fresh git clone, you might have to clean files from previous builds or test runs first. diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh index fae48ba176..09b37f8240 100755 --- a/ci/test/00_setup_env.sh +++ b/ci/test/00_setup_env.sh @@ -31,3 +31,10 @@ export GOAL=${GOAL:-install} export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_BUILD_DIR}/qa-assets} export PATH=${BASE_ROOT_DIR}/ci/retry:$PATH export CI_RETRY_EXE=${CI_RETRY_EXE:retry} + +echo "Setting specific values in env" +if [ -n "${FILE_ENV}" ]; then + set -o errexit; + # shellcheck disable=SC1090 + source "${FILE_ENV}" +fi diff --git a/ci/test/00_setup_env_amd64_asan.sh b/ci/test/00_setup_env_amd64_asan.sh new file mode 100644 index 0000000000..9d20b6a72b --- /dev/null +++ b/ci/test/00_setup_env_amd64_asan.sh @@ -0,0 +1,13 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-unknown-linux-gnu +export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" +export NO_DEPENDS=1 +export GOAL="install" +export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_amd64_fuzz.sh b/ci/test/00_setup_env_amd64_fuzz.sh new file mode 100644 index 0000000000..edcb65af28 --- /dev/null +++ b/ci/test/00_setup_env_amd64_fuzz.sh @@ -0,0 +1,16 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-unknown-linux-gnu +export PACKAGES="clang llvm python3 libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev" +export NO_DEPENDS=1 +export RUN_UNIT_TESTS=false +export RUN_FUNCTIONAL_TESTS=false +export RUN_FUZZ_TESTS=true +export GOAL="install" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_amd64_nowallet.sh b/ci/test/00_setup_env_amd64_nowallet.sh new file mode 100644 index 0000000000..d5a2ba3111 --- /dev/null +++ b/ci/test/00_setup_env_amd64_nowallet.sh @@ -0,0 +1,13 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-unknown-linux-gnu +export PACKAGES="python3-zmq" +export DEP_OPTS="NO_WALLET=1" +export GOAL="install" +export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" diff --git a/ci/test/00_setup_env_amd64_qt5.sh b/ci/test/00_setup_env_amd64_qt5.sh new file mode 100644 index 0000000000..77b1531be4 --- /dev/null +++ b/ci/test/00_setup_env_amd64_qt5.sh @@ -0,0 +1,14 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-unknown-linux-gnu +export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" +export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" +export TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash +export GOAL="install" +export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\"" diff --git a/ci/test/00_setup_env_amd64_trusty.sh b/ci/test/00_setup_env_amd64_trusty.sh new file mode 100644 index 0000000000..cc0f1196e7 --- /dev/null +++ b/ci/test/00_setup_env_amd64_trusty.sh @@ -0,0 +1,15 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-unknown-linux-gnu +export DOCKER_NAME_TAG=ubuntu:14.04 +export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" +export NO_DEPENDS=1 +export RUN_FUNCTIONAL_TESTS=false +export GOAL="install" +export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no" diff --git a/ci/test/00_setup_env_amd64_tsan.sh b/ci/test/00_setup_env_amd64_tsan.sh new file mode 100644 index 0000000000..c127e284bd --- /dev/null +++ b/ci/test/00_setup_env_amd64_tsan.sh @@ -0,0 +1,14 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-unknown-linux-gnu +export DOCKER_NAME_TAG=ubuntu:16.04 +export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" +export NO_DEPENDS=1 +export GOAL="install" +export BITCOIN_CONFIG="--enable-zmq --disable-wallet --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=thread --disable-hardening --disable-asm CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh new file mode 100644 index 0000000000..ac7ace8c3b --- /dev/null +++ b/ci/test/00_setup_env_arm.sh @@ -0,0 +1,16 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=arm-linux-gnueabihf +export PACKAGES="python3 g++-arm-linux-gnueabihf" +export RUN_UNIT_TESTS=false +export RUN_FUNCTIONAL_TESTS=false +export GOAL="install" +# -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" +# This could be removed once the ABI change warning does not show up by default +export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" diff --git a/ci/test/00_setup_env_i686.sh b/ci/test/00_setup_env_i686.sh new file mode 100644 index 0000000000..768e2ac558 --- /dev/null +++ b/ci/test/00_setup_env_i686.sh @@ -0,0 +1,13 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=i686-pc-linux-gnu +export PACKAGES="g++-multilib python3-zmq" +export GOAL="install" +export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --disable-bip70 --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" +export CONFIG_SHELL="/bin/dash" diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh new file mode 100644 index 0000000000..f384ba9263 --- /dev/null +++ b/ci/test/00_setup_env_mac.sh @@ -0,0 +1,15 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-apple-darwin14 +export PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools" +export OSX_SDK=10.11 +export RUN_UNIT_TESTS=false +export RUN_FUNCTIONAL_TESTS=false +export GOAL="deploy" +export BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror" diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh new file mode 100644 index 0000000000..1e04c4287a --- /dev/null +++ b/ci/test/00_setup_env_win64.sh @@ -0,0 +1,13 @@ +#!/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. + +export LC_ALL=C.UTF-8 + +export HOST=x86_64-w64-mingw32 +export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" +export RUN_FUNCTIONAL_TESTS=false +export GOAL="deploy" +export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh index a39f1f9f09..a1d4bd1952 100755 --- a/ci/test_run_all.sh +++ b/ci/test_run_all.sh @@ -6,8 +6,6 @@ export LC_ALL=C.UTF-8 -echo "Setting default values in env" - set -o errexit; source ./ci/test/00_setup_env.sh set -o errexit; source ./ci/test/03_before_install.sh set -o errexit; source ./ci/test/04_install.sh diff --git a/contrib/README.md b/contrib/README.md index 8915919766..e9e72f6686 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -3,10 +3,10 @@ Repository Tools ### [Developer tools](/contrib/devtools) ### Specific tools for developers working on this repository. -Contains the script `github-merge.py` for merging GitHub pull requests securely and signing them using GPG. +Additional tools, including the `github-merge.py` script, are available in the [maintainer-tools](https://github.com/bitcoin-core/bitcoin-maintainer-tools) repository. ### [Verify-Commits](/contrib/verify-commits) ### -Tool to verify that every merge commit was signed by a developer using the above `github-merge.py` script. +Tool to verify that every merge commit was signed by a developer using the `github-merge.py` script. ### [Linearize](/contrib/linearize) ### Construct a linear, no-fork, best version of the blockchain. diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index 4994d7f0a5..3d1024c7a5 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -89,66 +89,6 @@ example: BUILDDIR=$PWD/build contrib/devtools/gen-manpages.sh ``` -github-merge.py -=============== - -A small script to automate merging pull-requests securely and sign them with GPG. - -For example: - - ./github-merge.py 3077 - -(in any git repository) will help you merge pull request #3077 for the -bitcoin/bitcoin repository. - -What it does: -* Fetch master and the pull request. -* Locally construct a merge commit. -* Show the diff that merge results in. -* Ask you to verify the resulting source tree (so you can do a make -check or whatever). -* Ask you whether to GPG sign the merge commit. -* Ask you whether to push the result upstream. - -This means that there are no potential race conditions (where a -pullreq gets updated while you're reviewing it, but before you click -merge), and when using GPG signatures, that even a compromised GitHub -couldn't mess with the sources. - -Setup ---------- -Configuring the github-merge tool for the bitcoin repository is done in the following way: - - git config githubmerge.repository bitcoin/bitcoin - git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing) - git config --global user.signingkey mykeyid - -Authentication (optional) --------------------------- - -The API request limit for unauthenticated requests is quite low, but the -limit for authenticated requests is much higher. If you start running -into rate limiting errors it can be useful to set an authentication token -so that the script can authenticate requests. - -- First, go to [Personal access tokens](https://github.com/settings/tokens). -- Click 'Generate new token'. -- Fill in an arbitrary token description. No further privileges are needed. -- Click the `Generate token` button at the bottom of the form. -- Copy the generated token (should be a hexadecimal string) - -Then do: - - git config --global user.ghtoken "pasted token" - -Create and verify timestamps of merge commits ---------------------------------------------- -To create or verify timestamps on the merge commits, install the OpenTimestamps -client via `pip3 install opentimestamps-client`. Then, download the gpg wrapper -`ots-git-gpg-wrapper.sh` and set it as git's `gpg.program`. See -[the ots git integration documentation](https://github.com/opentimestamps/opentimestamps-client/blob/master/doc/git-integration.md#usage) -for further details. - optimize-pngs.py ================ diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py deleted file mode 100755 index 78ac671bfe..0000000000 --- a/contrib/devtools/github-merge.py +++ /dev/null @@ -1,413 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2016-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. - -# This script will locally construct a merge commit for a pull request on a -# github repository, inspect it, sign it and optionally push it. - -# The following temporary branches are created/overwritten and deleted: -# * pull/$PULL/base (the current master we're merging onto) -# * pull/$PULL/head (the current state of the remote pull request) -# * pull/$PULL/merge (github's merge) -# * pull/$PULL/local-merge (our merge) - -# In case of a clean merge that is accepted by the user, the local branch with -# name $BRANCH is overwritten with the merged result, and optionally pushed. -import os -from sys import stdin,stdout,stderr -import argparse -import hashlib -import subprocess -import sys -import json -import codecs -from urllib.request import Request, urlopen -from urllib.error import HTTPError - -# External tools (can be overridden using environment) -GIT = os.getenv('GIT','git') -BASH = os.getenv('BASH','bash') - -# OS specific configuration for terminal attributes -ATTR_RESET = '' -ATTR_PR = '' -ATTR_NAME = '' -ATTR_WARN = '' -COMMIT_FORMAT = '%H %s (%an)%d' -if os.name == 'posix': # if posix, assume we can use basic terminal escapes - ATTR_RESET = '\033[0m' - ATTR_PR = '\033[1;36m' - ATTR_NAME = '\033[0;36m' - ATTR_WARN = '\033[1;31m' - COMMIT_FORMAT = '%C(bold blue)%H%Creset %s %C(cyan)(%an)%Creset%C(green)%d%Creset' - -def git_config_get(option, default=None): - ''' - Get named configuration option from git repository. - ''' - try: - return subprocess.check_output([GIT,'config','--get',option]).rstrip().decode('utf-8') - except subprocess.CalledProcessError: - return default - -def get_response(req_url, ghtoken): - req = Request(req_url) - if ghtoken is not None: - req.add_header('Authorization', 'token ' + ghtoken) - return urlopen(req) - -def retrieve_json(req_url, ghtoken, use_pagination=False): - ''' - Retrieve json from github. - Return None if an error happens. - ''' - try: - reader = codecs.getreader('utf-8') - if not use_pagination: - return json.load(reader(get_response(req_url, ghtoken))) - - obj = [] - page_num = 1 - while True: - req_url_page = '{}?page={}'.format(req_url, page_num) - result = get_response(req_url_page, ghtoken) - obj.extend(json.load(reader(result))) - - link = result.headers.get('link', None) - if link is not None: - link_next = [l for l in link.split(',') if 'rel="next"' in l] - if len(link_next) > 0: - page_num = int(link_next[0][link_next[0].find("page=")+5:link_next[0].find(">")]) - continue - break - return obj - except HTTPError as e: - error_message = e.read() - print('Warning: unable to retrieve pull information from github: %s' % e) - print('Detailed error: %s' % error_message) - return None - except Exception as e: - print('Warning: unable to retrieve pull information from github: %s' % e) - return None - -def retrieve_pr_info(repo,pull,ghtoken): - req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull - return retrieve_json(req_url,ghtoken) - -def retrieve_pr_comments(repo,pull,ghtoken): - req_url = "https://api.github.com/repos/"+repo+"/issues/"+pull+"/comments" - return retrieve_json(req_url,ghtoken,use_pagination=True) - -def retrieve_pr_reviews(repo,pull,ghtoken): - req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull+"/reviews" - return retrieve_json(req_url,ghtoken,use_pagination=True) - -def ask_prompt(text): - print(text,end=" ",file=stderr) - stderr.flush() - reply = stdin.readline().rstrip() - print("",file=stderr) - return reply - -def get_symlink_files(): - files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', 'HEAD']).splitlines()) - ret = [] - for f in files: - if (int(f.decode('utf-8').split(" ")[0], 8) & 0o170000) == 0o120000: - ret.append(f.decode('utf-8').split("\t")[1]) - return ret - -def tree_sha512sum(commit='HEAD'): - # request metadata for entire tree, recursively - files = [] - blob_by_name = {} - for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines(): - name_sep = line.index(b'\t') - metadata = line[:name_sep].split() # perms, 'blob', blobid - assert(metadata[1] == b'blob') - name = line[name_sep+1:] - files.append(name) - blob_by_name[name] = metadata[2] - - files.sort() - # open connection to git-cat-file in batch mode to request data for all blobs - # this is much faster than launching it per file - p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE) - overall = hashlib.sha512() - for f in files: - blob = blob_by_name[f] - # request blob - p.stdin.write(blob + b'\n') - p.stdin.flush() - # read header: blob, "blob", size - reply = p.stdout.readline().split() - assert(reply[0] == blob and reply[1] == b'blob') - size = int(reply[2]) - # hash the blob data - intern = hashlib.sha512() - ptr = 0 - while ptr < size: - bs = min(65536, size - ptr) - piece = p.stdout.read(bs) - if len(piece) == bs: - intern.update(piece) - else: - raise IOError('Premature EOF reading git cat-file output') - ptr += bs - dig = intern.hexdigest() - assert(p.stdout.read(1) == b'\n') # ignore LF that follows blob data - # update overall hash with file hash - overall.update(dig.encode("utf-8")) - overall.update(" ".encode("utf-8")) - overall.update(f) - overall.update("\n".encode("utf-8")) - p.stdin.close() - if p.wait(): - raise IOError('Non-zero return value executing git cat-file') - return overall.hexdigest() - -def get_acks_from_comments(head_commit, comments): - # Look for abbreviated commit id, because not everyone wants to type/paste - # the whole thing and the chance of collisions within a PR is small enough - head_abbrev = head_commit[0:6] - acks = [] - for c in comments: - review = [l for l in c['body'].split('\r\n') if 'ACK' in l and head_abbrev in l] - if review: - acks.append((c['user']['login'], review[0])) - return acks - -def make_acks_message(head_commit, acks): - if acks: - ack_str ='\n\nACKs for top commit:\n'.format(head_commit) - for name, msg in acks: - ack_str += ' {}:\n'.format(name) - ack_str += ' {}\n'.format(msg) - else: - ack_str ='\n\nTop commit has no ACKs.\n' - return ack_str - -def print_merge_details(pull, title, branch, base_branch, head_branch, acks): - print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET)) - subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch]) - if acks is not None: - if acks: - print('{}ACKs:{}'.format(ATTR_PR, ATTR_RESET)) - for (name, message) in acks: - print('* {} {}({}){}'.format(message, ATTR_NAME, name, ATTR_RESET)) - else: - print('{}Top commit has no ACKs!{}'.format(ATTR_WARN, ATTR_RESET)) - -def parse_arguments(): - epilog = ''' - In addition, you can set the following git configuration variables: - githubmerge.repository (mandatory), - user.signingkey (mandatory), - user.ghtoken (default: none). - githubmerge.host (default: git@github.com), - githubmerge.branch (no default), - githubmerge.testcmd (default: none). - ''' - parser = argparse.ArgumentParser(description='Utility to merge, sign and push github pull requests', - epilog=epilog) - parser.add_argument('pull', metavar='PULL', type=int, nargs=1, - help='Pull request ID to merge') - parser.add_argument('branch', metavar='BRANCH', type=str, nargs='?', - default=None, help='Branch to merge against (default: githubmerge.branch setting, or base branch for pull, or \'master\')') - return parser.parse_args() - -def main(): - # Extract settings from git repo - repo = git_config_get('githubmerge.repository') - host = git_config_get('githubmerge.host','git@github.com') - opt_branch = git_config_get('githubmerge.branch',None) - testcmd = git_config_get('githubmerge.testcmd') - ghtoken = git_config_get('user.ghtoken') - signingkey = git_config_get('user.signingkey') - if repo is None: - print("ERROR: No repository configured. Use this command to set:", file=stderr) - print("git config githubmerge.repository <owner>/<repo>", file=stderr) - sys.exit(1) - if signingkey is None: - print("ERROR: No GPG signing key set. Set one using:",file=stderr) - print("git config --global user.signingkey <key>",file=stderr) - sys.exit(1) - - if host.startswith(('https:','http:')): - host_repo = host+"/"+repo+".git" - else: - host_repo = host+":"+repo - - # Extract settings from command line - args = parse_arguments() - pull = str(args.pull[0]) - - # Receive pull information from github - info = retrieve_pr_info(repo,pull,ghtoken) - if info is None: - sys.exit(1) - title = info['title'].strip() - body = info['body'].strip() - # precedence order for destination branch argument: - # - command line argument - # - githubmerge.branch setting - # - base branch for pull (as retrieved from github) - # - 'master' - branch = args.branch or opt_branch or info['base']['ref'] or 'master' - - # Initialize source branches - head_branch = 'pull/'+pull+'/head' - base_branch = 'pull/'+pull+'/base' - merge_branch = 'pull/'+pull+'/merge' - local_merge_branch = 'pull/'+pull+'/local-merge' - - devnull = open(os.devnull, 'w', encoding="utf8") - try: - subprocess.check_call([GIT,'checkout','-q',branch]) - except subprocess.CalledProcessError: - print("ERROR: Cannot check out branch %s." % (branch), file=stderr) - sys.exit(3) - try: - subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*', - '+refs/heads/'+branch+':refs/heads/'+base_branch]) - except subprocess.CalledProcessError: - print("ERROR: Cannot find pull request #%s or branch %s on %s." % (pull,branch,host_repo), file=stderr) - sys.exit(3) - try: - subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+head_branch], stdout=devnull, stderr=stdout) - head_commit = subprocess.check_output([GIT,'log','-1','--pretty=format:%H',head_branch]).decode('utf-8') - assert len(head_commit) == 40 - except subprocess.CalledProcessError: - print("ERROR: Cannot find head of pull request #%s on %s." % (pull,host_repo), file=stderr) - sys.exit(3) - try: - subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+merge_branch], stdout=devnull, stderr=stdout) - except subprocess.CalledProcessError: - print("ERROR: Cannot find merge of pull request #%s on %s." % (pull,host_repo), file=stderr) - sys.exit(3) - subprocess.check_call([GIT,'checkout','-q',base_branch]) - subprocess.call([GIT,'branch','-q','-D',local_merge_branch], stderr=devnull) - subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch]) - - try: - # Go up to the repository's root. - toplevel = subprocess.check_output([GIT,'rev-parse','--show-toplevel']).strip() - os.chdir(toplevel) - # Create unsigned merge commit. - if title: - firstline = 'Merge #%s: %s' % (pull,title) - else: - firstline = 'Merge #%s' % (pull,) - message = firstline + '\n\n' - message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%H %s (%an)',base_branch+'..'+head_branch]).decode('utf-8') - message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n' - try: - subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','--no-gpg-sign','-m',message.encode('utf-8'),head_branch]) - except subprocess.CalledProcessError: - print("ERROR: Cannot be merged cleanly.",file=stderr) - subprocess.check_call([GIT,'merge','--abort']) - sys.exit(4) - logmsg = subprocess.check_output([GIT,'log','--pretty=format:%s','-n','1']).decode('utf-8') - if logmsg.rstrip() != firstline.rstrip(): - print("ERROR: Creating merge failed (already merged?).",file=stderr) - sys.exit(4) - - symlink_files = get_symlink_files() - for f in symlink_files: - print("ERROR: File %s was a symlink" % f) - if len(symlink_files) > 0: - sys.exit(4) - - # Compute SHA512 of git tree (to be able to detect changes before sign-off) - try: - first_sha512 = tree_sha512sum() - except subprocess.CalledProcessError: - print("ERROR: Unable to compute tree hash") - sys.exit(4) - - print_merge_details(pull, title, branch, base_branch, head_branch, None) - print() - - # Run test command if configured. - if testcmd: - if subprocess.call(testcmd,shell=True): - print("ERROR: Running %s failed." % testcmd,file=stderr) - sys.exit(5) - - # Show the created merge. - diff = subprocess.check_output([GIT,'diff',merge_branch+'..'+local_merge_branch]) - subprocess.check_call([GIT,'diff',base_branch+'..'+local_merge_branch]) - if diff: - print("WARNING: merge differs from github!",file=stderr) - reply = ask_prompt("Type 'ignore' to continue.") - if reply.lower() == 'ignore': - print("Difference with github ignored.",file=stderr) - else: - sys.exit(6) - else: - # Verify the result manually. - print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr) - print("Run 'git diff HEAD~' to show the changes being merged.",file=stderr) - print("Type 'exit' when done.",file=stderr) - if os.path.isfile('/etc/debian_version'): # Show pull number on Debian default prompt - os.putenv('debian_chroot',pull) - subprocess.call([BASH,'-i']) - - second_sha512 = tree_sha512sum() - if first_sha512 != second_sha512: - print("ERROR: Tree hash changed unexpectedly",file=stderr) - sys.exit(8) - - # Retrieve PR comments and ACKs and add to commit message, store ACKs to print them with commit - # description - comments = retrieve_pr_comments(repo,pull,ghtoken) + retrieve_pr_reviews(repo,pull,ghtoken) - if comments is None: - print("ERROR: Could not fetch PR comments and reviews",file=stderr) - sys.exit(1) - acks = get_acks_from_comments(head_commit=head_commit, comments=comments) - message += make_acks_message(head_commit=head_commit, acks=acks) - # end message with SHA512 tree hash, then update message - message += '\n\nTree-SHA512: ' + first_sha512 - try: - subprocess.check_call([GIT,'commit','--amend','--no-gpg-sign','-m',message.encode('utf-8')]) - except subprocess.CalledProcessError: - print("ERROR: Cannot update message.", file=stderr) - sys.exit(4) - - # Sign the merge commit. - print_merge_details(pull, title, branch, base_branch, head_branch, acks) - while True: - reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower() - if reply == 's': - try: - subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit']) - break - except subprocess.CalledProcessError: - print("Error while signing, asking again.",file=stderr) - elif reply == 'x': - print("Not signing off on merge, exiting.",file=stderr) - sys.exit(1) - - # Put the result in branch. - subprocess.check_call([GIT,'checkout','-q',branch]) - subprocess.check_call([GIT,'reset','-q','--hard',local_merge_branch]) - finally: - # Clean up temporary branches. - subprocess.call([GIT,'checkout','-q',branch]) - subprocess.call([GIT,'branch','-q','-D',head_branch],stderr=devnull) - subprocess.call([GIT,'branch','-q','-D',base_branch],stderr=devnull) - subprocess.call([GIT,'branch','-q','-D',merge_branch],stderr=devnull) - subprocess.call([GIT,'branch','-q','-D',local_merge_branch],stderr=devnull) - - # Push the result. - while True: - reply = ask_prompt("Type 'push' to push the result to %s, branch %s, or 'x' to exit without pushing." % (host_repo,branch)).lower() - if reply == 'push': - subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch]) - break - elif reply == 'x': - sys.exit(1) - -if __name__ == '__main__': - main() diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py index 255ce75092..9ec8663fba 100755 --- a/contrib/verify-commits/verify-commits.py +++ b/contrib/verify-commits/verify-commits.py @@ -16,7 +16,7 @@ GIT = os.getenv('GIT', 'git') def tree_sha512sum(commit='HEAD'): """Calculate the Tree-sha512 for the commit. - This is copied from github-merge.py.""" + This is copied from github-merge.py. See https://github.com/bitcoin-core/bitcoin-maintainer-tools.""" # request metadata for entire tree, recursively files = [] diff --git a/doc/rapidcheck.md b/doc/rapidcheck.md new file mode 100644 index 0000000000..397a907f17 --- /dev/null +++ b/doc/rapidcheck.md @@ -0,0 +1,84 @@ +# RapidCheck property-based testing for Bitcoin Core + +## Concept + +Property-based testing is experimentally being added to Bitcoin Core with +[RapidCheck](https://github.com/emil-e/rapidcheck), a C++ framework for +property-based testing inspired by the Haskell library +[QuickCheck](https://hackage.haskell.org/package/QuickCheck). + +RapidCheck performs random testing of program properties. A specification of the +program is given in the form of properties which functions should satisfy, and +RapidCheck tests that the properties hold in a large number of randomly +generated cases. + +If an exception is found, RapidCheck tries to find the smallest case, for some +definition of smallest, for which the property is still false and displays it as +a counter-example. For example, if the input is an integer, RapidCheck tries to +find the smallest integer for which the property is false. + +## Running + +If RapidCheck is installed, Bitcoin Core will automatically run the +property-based tests with the unit tests during `make check`, unless the +`--without-rapidcheck` flag is passed when configuring. + +For more information, run `./configure --help` and see `--with-rapidcheck` under +Optional Packages. + +## Setup + +The following instructions have been tested with Linux Debian and macOS. + +1. Clone the RapidCheck source code and cd into the repository. + + ```shell + git clone https://github.com/emil-e/rapidcheck.git + cd rapidcheck + ``` + +2. Build RapidCheck (requires CMake to be installed). + + ```shell + cmake -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true -DRC_ENABLE_BOOST_TEST=ON $(pwd) + make && make install + ``` + +3. Configure Bitcoin Core with RapidCheck. + + `cd` to the directory of your local bitcoin repository and run + `./configure`. In the output you should see: + + ```shell + checking rapidcheck.h usability... yes + checking rapidcheck.h presence... yes + checking for rapidcheck.h... yes + [...] + Options used to compile and link: + [...] + with test = yes + with prop = yes + ``` + +4. Build Bitcoin Core with RapidCheck. + + Now you can run `make` and should see the property-based tests compiled with + the unit tests: + + ```shell + Making all in src + [...] + CXX test/gen/test_bitcoin-crypto_gen.o + CXX test/test_bitcoin-key_properties.o + ``` + +5. Run the unit tests with `make check`. The property-based tests will be run + with the unit tests. + + ```shell + Running tests: crypto_tests from test/crypto_tests.cpp + [...] + Running tests: key_properties from test/key_properties.cpp + ``` + +That's it! You are now running property-based tests in Bitcoin Core. diff --git a/doc/release-notes-16647.md b/doc/release-notes-16647.md new file mode 100644 index 0000000000..7e5539cb0d --- /dev/null +++ b/doc/release-notes-16647.md @@ -0,0 +1,3 @@ +RPC changes +----------- +`getmempoolentry` now provides a `weight` field containing the transaction weight as defined in BIP 141. diff --git a/share/examples/bitcoin.conf b/share/examples/bitcoin.conf index b5475dc1c6..709d8b002b 100644 --- a/share/examples/bitcoin.conf +++ b/share/examples/bitcoin.conf @@ -70,8 +70,8 @@ # server=1 tells Bitcoin-Qt and bitcoind to accept JSON-RPC commands #server=0 -# Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. -# This option can be specified multiple times (default: bind to all interfaces) +# Bind to given address to listen for JSON-RPC connections. +# Refer to the manpage or bitcoind -help for further details. #rpcbind=<addr> # If no rpcpassword is set, rpc cookie auth is sought. The default `-rpccookiefile` name diff --git a/src/Makefile.am b/src/Makefile.am index 141d8e68ea..477b1300bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -211,6 +211,7 @@ BITCOIN_CORE_H = \ util/memory.h \ util/moneystr.h \ util/rbf.h \ + util/string.h \ util/threadnames.h \ util/time.h \ util/translation.h \ @@ -501,6 +502,7 @@ libbitcoin_util_a_SOURCES = \ util/rbf.cpp \ util/threadnames.cpp \ util/strencodings.cpp \ + util/string.cpp \ util/time.cpp \ util/url.cpp \ util/validation.cpp \ diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 5f6d69a4f3..cde624ce74 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -125,7 +125,7 @@ static int AppInitRPC(int argc, char* argv[]) } return EXIT_SUCCESS; } - if (!fs::is_directory(GetDataDir(false))) { + if (!CheckDataDirOption()) { tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str()); return EXIT_FAILURE; } diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 203f909cc4..361fedf35a 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -57,7 +57,7 @@ static bool WalletAppInit(int argc, char* argv[]) // check for printtoconsole, allow -debug LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false)); - if (!fs::is_directory(GetDataDir(false))) { + if (!CheckDataDirOption()) { tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str()); return false; } diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 8e31f6e32b..cb3c4f70b4 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -95,8 +95,7 @@ static bool AppInit(int argc, char* argv[]) try { - if (!fs::is_directory(GetDataDir(false))) - { + if (!CheckDataDirOption()) { return InitError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))); } if (!gArgs.ReadConfigFiles(error, true)) { diff --git a/src/init.cpp b/src/init.cpp index dce601a554..dd43ef71c9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -366,7 +366,7 @@ void SetupServerArgs() gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet, RPC and relay whitelisted inbound peers are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); @@ -510,8 +510,8 @@ void SetupServerArgs() gArgs.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); gArgs.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if the transactions were already in the mempool or violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted inbound peers even if the transactions were already in the mempool or violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted inbound peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); gArgs.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); diff --git a/src/net.cpp b/src/net.cpp index 0391edadaa..337d1f6a46 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -909,8 +909,8 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { bool legacyWhitelisted = false; if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_ISIMPLICIT)) { NetPermissions::ClearFlag(permissionFlags, PF_ISIMPLICIT); - if (gArgs.GetBoolArg("-whitelistforcerelay", false)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY); - if (gArgs.GetBoolArg("-whitelistrelay", false)) NetPermissions::AddFlag(permissionFlags, PF_RELAY); + if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY); + if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permissionFlags, PF_RELAY); NetPermissions::AddFlag(permissionFlags, PF_MEMPOOL); NetPermissions::AddFlag(permissionFlags, PF_NOBAN); legacyWhitelisted = true; @@ -40,6 +40,11 @@ class CScheduler; class CNode; class BanMan; +/** Default for -whitelistrelay. */ +static const bool DEFAULT_WHITELISTRELAY = true; +/** Default for -whitelistforcerelay. */ +static const bool DEFAULT_WHITELISTFORCERELAY = false; + /** Time between pings automatically sent out for latency probing and keepalive (in seconds). */ static const int PING_INTERVAL = 2 * 60; /** Time after which to disconnect, after waiting for a ping response (or inactivity). */ diff --git a/src/obj/.gitignore b/src/obj/.gitignore deleted file mode 100644 index d6b7ef32c8..0000000000 --- a/src/obj/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 29423db3d0..131cceccbe 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -10,6 +10,8 @@ #include <key_io.h> #include <wallet/wallet.h> +#include <algorithm> + #include <QFont> #include <QDebug> @@ -86,18 +88,18 @@ public: QString::fromStdString(EncodeDestination(address.dest)))); } } - // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order + // std::lower_bound() and std::upper_bound() require our cachedAddressTable list to be sorted in asc order // Even though the map is already sorted this re-sorting step is needed because the originating map // is sorted by binary address, not by base58() address. - qSort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); + std::sort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); } void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status) { // Find address / label in model - QList<AddressTableEntry>::iterator lower = qLowerBound( + QList<AddressTableEntry>::iterator lower = std::lower_bound( cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan()); - QList<AddressTableEntry>::iterator upper = qUpperBound( + QList<AddressTableEntry>::iterator upper = std::upper_bound( cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan()); int lowerIndex = (lower - cachedAddressTable.begin()); int upperIndex = (upper - cachedAddressTable.begin()); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 8a6b205cd8..efc726e09e 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -10,6 +10,8 @@ #include <sync.h> #include <util/time.h> +#include <algorithm> + #include <QDebug> #include <QList> @@ -61,7 +63,7 @@ public: if (sortColumn >= 0) // sort cachedBanlist (use stable sort to prevent rows jumping around unnecessarily) - qStableSort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder)); + std::stable_sort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder)); } int size() const diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 5ce4f3c191..adc19df935 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -490,10 +490,9 @@ int GuiMain(int argc, char* argv[]) if (!Intro::pickDataDirectory(*node)) return EXIT_SUCCESS; - /// 6. Determine availability of data and blocks directory and parse bitcoin.conf + /// 6. Determine availability of data directory and parse bitcoin.conf /// - Do not call GetDataDir(true) before this step finishes - if (!fs::is_directory(GetDataDir(false))) - { + if (!CheckDataDirOption()) { node->initError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 85b691c470..99a9a12fe2 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -11,6 +11,8 @@ #include <interfaces/node.h> #include <sync.h> +#include <algorithm> + #include <QDebug> #include <QList> #include <QTimer> @@ -76,7 +78,7 @@ public: if (sortColumn >= 0) // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily) - qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); + std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); // build index map mapNodeRows.clear(); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index aa746017f3..1611ec823c 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -11,6 +11,8 @@ #include <clientversion.h> #include <streams.h> +#include <algorithm> + RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) @@ -202,7 +204,7 @@ void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient) void RecentRequestsTableModel::sort(int column, Qt::SortOrder order) { - qSort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order)); + std::sort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order)); Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex())); } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 1064c60dfd..8d0cb54151 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -17,6 +17,8 @@ #include <interfaces/handler.h> #include <uint256.h> +#include <algorithm> + #include <QColor> #include <QDateTime> #include <QDebug> @@ -93,9 +95,9 @@ public: qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); // Find bounds of this transaction in model - QList<TransactionRecord>::iterator lower = qLowerBound( + QList<TransactionRecord>::iterator lower = std::lower_bound( cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); - QList<TransactionRecord>::iterator upper = qUpperBound( + QList<TransactionRecord>::iterator upper = std::upper_bound( cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); int lowerIndex = (lower - cachedWallet.begin()); int upperIndex = (upper - cachedWallet.begin()); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index bfb6ab6a21..a74003149d 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -374,6 +374,7 @@ static std::string EntryDescriptionString() return " \"vsize\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n" " \"size\" : n, (numeric) (DEPRECATED) same as vsize. Only returned if bitcoind is started with -deprecatedrpc=size\n" " size will be completely removed in v0.20.\n" + " \"weight\" : n, (numeric) transaction weight as defined in BIP 141.\n" " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)\n" " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED)\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" @@ -413,6 +414,7 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool info.pushKV("vsize", (int)e.GetTxSize()); if (IsDeprecatedRPCEnabled("size")) info.pushKV("size", (int)e.GetTxSize()); + info.pushKV("weight", (int)e.GetTxWeight()); info.pushKV("fee", ValueFromAmount(e.GetFee())); info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee())); info.pushKV("time", e.GetTime()); diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 464537a5b0..22d67c34da 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -4,11 +4,12 @@ #include <key_io.h> #include <outputtype.h> -#include <script/signingprovider.h> #include <rpc/util.h> #include <script/descriptor.h> +#include <script/signingprovider.h> #include <tinyformat.h> #include <util/strencodings.h> +#include <util/string.h> #include <tuple> @@ -645,11 +646,7 @@ std::string RPCArg::ToString(const bool oneline) const } case Type::OBJ: case Type::OBJ_USER_KEYS: { - std::string res; - for (size_t i = 0; i < m_inner.size();) { - res += m_inner[i].ToStringObj(oneline); - if (++i < m_inner.size()) res += ","; - } + const std::string res = Join(m_inner, ",", [&](const RPCArg& i) { return i.ToStringObj(oneline); }); if (m_type == Type::OBJ) { return "{" + res + "}"; } else { diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 7119f56fc3..65cb956fbe 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -6,11 +6,12 @@ #include <clientversion.h> #include <sync.h> +#include <test/setup_common.h> #include <test/util.h> -#include <util/strencodings.h> #include <util/moneystr.h> +#include <util/strencodings.h> +#include <util/string.h> #include <util/time.h> -#include <test/setup_common.h> #include <stdint.h> #include <thread> @@ -123,6 +124,19 @@ BOOST_AUTO_TEST_CASE(util_HexStr) ); } +BOOST_AUTO_TEST_CASE(util_Join) +{ + // Normal version + BOOST_CHECK_EQUAL(Join({}, ", "), ""); + BOOST_CHECK_EQUAL(Join({"foo"}, ", "), "foo"); + BOOST_CHECK_EQUAL(Join({"foo", "bar"}, ", "), "foo, bar"); + + // Version with unary operator + const auto op_upper = [](const std::string& s) { return ToUpper(s); }; + BOOST_CHECK_EQUAL(Join<std::string>({}, ", ", op_upper), ""); + BOOST_CHECK_EQUAL(Join<std::string>({"foo"}, ", ", op_upper), "FOO"); + BOOST_CHECK_EQUAL(Join<std::string>({"foo", "bar"}, ", ", op_upper), "FOO, BAR"); +} BOOST_AUTO_TEST_CASE(util_FormatISO8601DateTime) { diff --git a/src/util/string.cpp b/src/util/string.cpp new file mode 100644 index 0000000000..8ea3a1afc6 --- /dev/null +++ b/src/util/string.cpp @@ -0,0 +1,5 @@ +// 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. + +#include <util/string.h> diff --git a/src/util/string.h b/src/util/string.h new file mode 100644 index 0000000000..dec0c19b08 --- /dev/null +++ b/src/util/string.h @@ -0,0 +1,35 @@ +// 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. + +#ifndef BITCOIN_UTIL_STRING_H +#define BITCOIN_UTIL_STRING_H + +#include <functional> +#include <string> +#include <vector> + +/** + * Join a list of items + * + * @param list The list to join + * @param separator The separator + * @param unary_op Apply this operator to each item in the list + */ +template <typename T, typename UnaryOp> +std::string Join(const std::vector<T>& list, const std::string& separator, UnaryOp unary_op) +{ + std::string ret; + for (size_t i = 0; i < list.size(); ++i) { + if (i > 0) ret += separator; + ret += unary_op(list.at(i)); + } + return ret; +} + +inline std::string Join(const std::vector<std::string>& list, const std::string& separator) +{ + return Join(list, separator, [](const std::string& i) { return i; }); +} + +#endif // BITCOIN_UTIL_STRENCODINGS_H diff --git a/src/util/system.cpp b/src/util/system.cpp index f8bcc45a6a..c925dec253 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -748,8 +748,9 @@ const fs::path &GetDataDir(bool fNetSpecific) // this function if (!path.empty()) return path; - if (gArgs.IsArgSet("-datadir")) { - path = fs::system_complete(gArgs.GetArg("-datadir", "")); + std::string datadir = gArgs.GetArg("-datadir", ""); + if (!datadir.empty()) { + path = fs::system_complete(datadir); if (!fs::is_directory(path)) { path = ""; return path; @@ -768,6 +769,12 @@ const fs::path &GetDataDir(bool fNetSpecific) return path; } +bool CheckDataDirOption() +{ + std::string datadir = gArgs.GetArg("-datadir", ""); + return datadir.empty() || fs::is_directory(fs::system_complete(datadir)); +} + void ClearDatadirCache() { LOCK(csPathCached); @@ -937,7 +944,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) // If datadir is changed in .conf file: ClearDatadirCache(); - if (!fs::is_directory(GetDataDir(false))) { + if (!CheckDataDirOption()) { error = strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()); return false; } @@ -1205,6 +1212,9 @@ int64_t GetStartupTime() fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific) { + if (path.is_absolute()) { + return path; + } return fs::absolute(path, GetDataDir(net_specific)); } diff --git a/src/util/system.h b/src/util/system.h index 75e8096826..908a3c407d 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -71,6 +71,8 @@ fs::path GetDefaultDataDir(); // The blocks directory is always net specific. const fs::path &GetBlocksDir(); const fs::path &GetDataDir(bool fNetSpecific = true); +// Return true if -datadir option points to a valid directory or is not specified. +bool CheckDataDirOption(); /** Tests only */ void ClearDatadirCache(); fs::path GetConfigFile(const std::string& confPath); diff --git a/src/validation.h b/src/validation.h index 7cf3311f22..99850f71d9 100644 --- a/src/validation.h +++ b/src/validation.h @@ -50,10 +50,6 @@ struct DisconnectedBlockTransactions; struct PrecomputedTransactionData; struct LockPoints; -/** Default for -whitelistrelay. */ -static const bool DEFAULT_WHITELISTRELAY = true; -/** Default for -whitelistforcerelay. */ -static const bool DEFAULT_WHITELISTFORCERELAY = false; /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; /** Default for -limitancestorcount, max number of in-mempool ancestors */ diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index cf388ad827..984be3e301 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -444,7 +444,7 @@ public: * on this bitcoin node, and set to 0 for transactions that were created * externally and came in through the network or sendrawtransaction RPC. */ - char fFromMe; + bool fFromMe; int64_t nOrderPos; //!< position in ordered transaction list std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered; @@ -501,8 +501,8 @@ public: std::vector<char> dummy_vector1; //!< Used to be vMerkleBranch std::vector<char> dummy_vector2; //!< Used to be vtxPrev - char dummy_char = false; //!< Used to be fSpent - s << tx << hashBlock << dummy_vector1 << nIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_char; + bool dummy_bool = false; //!< Used to be fSpent + s << tx << hashBlock << dummy_vector1 << nIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool; } template<typename Stream> @@ -512,8 +512,8 @@ public: std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev - char dummy_char; //! Used to be fSpent - s >> tx >> hashBlock >> dummy_vector1 >> nIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_char; + bool dummy_bool; //! Used to be fSpent + s >> tx >> hashBlock >> dummy_vector1 >> nIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_bool; ReadOrderPos(nOrderPos, mapValue); nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0; diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 70a824b863..b997c76025 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -109,17 +109,15 @@ class ConfArgsTest(BitcoinTestFramework): f.write("datadir=" + new_data_dir + "\n") f.write(conf_file_contents) - # 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.') + self.nodes[0].assert_start_raises_init_error(['-conf=' + conf_file], 'Error: 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) - # Temporarily disabled, because this test would access the user's home dir (~/.bitcoin) - #self.start_node(0, ['-conf='+conf_file, '-wallet=w1']) - #self.stop_node(0) - #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'blocks')) - #if self.is_wallet_compiled(): - #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1')) + self.start_node(0, ['-conf='+conf_file, '-wallet=w1']) + self.stop_node(0) + assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'blocks')) + if self.is_wallet_compiled(): + assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1')) # Ensure command line argument overrides datadir in conf os.mkdir(new_data_dir_2) diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index d47065d1cb..b9db618575 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -226,6 +226,16 @@ class SegWitTest(BitcoinTestFramework): assert tx.wit.is_null() # This should not be a segwit input assert txid1 in self.nodes[0].getrawmempool() + tx1_hex = self.nodes[0].gettransaction(txid1)['hex'] + tx1 = FromHex(CTransaction(), tx1_hex) + + # Check that wtxid is properly reported in mempool entry (txid1) + assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16), tx1.calc_sha256(True)) + + # Check that weight and vsize are properly reported in mempool entry (txid1) + assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"], (self.nodes[0].getmempoolentry(txid1)["weight"] + 3) // 4) + assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"], len(tx1.serialize_without_witness())*3 + len(tx1.serialize_with_witness())) + # Now create tx2, which will spend from txid1. tx = CTransaction() tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b'')) @@ -235,6 +245,13 @@ class SegWitTest(BitcoinTestFramework): tx = FromHex(CTransaction(), tx2_hex) assert not tx.wit.is_null() + # Check that wtxid is properly reported in mempool entry (txid2) + assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16), tx.calc_sha256(True)) + + # Check that weight and vsize are properly reported in mempool entry (txid2) + assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"], (self.nodes[0].getmempoolentry(txid2)["weight"] + 3) // 4) + assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"], len(tx.serialize_without_witness())*3 + len(tx.serialize_with_witness())) + # Now create tx3, which will spend from txid2 tx = CTransaction() tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b"")) @@ -251,9 +268,13 @@ class SegWitTest(BitcoinTestFramework): assert txid2 in template_txids assert txid3 in template_txids - # Check that wtxid is properly reported in mempool entry + # Check that wtxid is properly reported in mempool entry (txid3) assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True)) + # Check that weight and vsize are properly reported in mempool entry (txid3) + assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"], (self.nodes[0].getmempoolentry(txid3)["weight"] + 3) // 4) + assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"], len(tx.serialize_without_witness())*3 + len(tx.serialize_with_witness())) + # Mine a block to clear the gbt cache again. self.nodes[0].generate(1) diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index 1013055420..40b28d7533 100644..100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -23,18 +23,24 @@ class P2PPermissionsTests(BitcoinTestFramework): def run_test(self): self.checkpermission( - # relay permission added - ["-whitelist=127.0.0.1", "-whitelistrelay"], - ["relay", "noban", "mempool"], - True) + # default permissions (no specific permissions) + ["-whitelist=127.0.0.1"], + ["relay", "noban", "mempool"], + True) self.checkpermission( - # forcerelay and relay permission added - # Legacy parameter interaction which set whitelistrelay to true - # if whitelistforcerelay is true - ["-whitelist=127.0.0.1", "-whitelistforcerelay"], - ["forcerelay", "relay", "noban", "mempool"], - True) + # relay permission removed (no specific permissions) + ["-whitelist=127.0.0.1", "-whitelistrelay=0"], + ["noban", "mempool"], + True) + + self.checkpermission( + # forcerelay and relay permission added + # Legacy parameter interaction which set whitelistrelay to true + # if whitelistforcerelay is true + ["-whitelist=127.0.0.1", "-whitelistforcerelay"], + ["forcerelay", "relay", "noban", "mempool"], + True) # Let's make sure permissions are merged correctly # For this, we need to use whitebind instead of bind @@ -42,35 +48,35 @@ class P2PPermissionsTests(BitcoinTestFramework): ip_port = "127.0.0.1:{}".format(p2p_port(1)) self.replaceinconfig(1, "bind=127.0.0.1", "whitebind=bloomfilter,forcerelay@" + ip_port) self.checkpermission( - ["-whitelist=noban@127.0.0.1" ], - # Check parameter interaction forcerelay should activate relay - ["noban", "bloomfilter", "forcerelay", "relay" ], - False) + ["-whitelist=noban@127.0.0.1" ], + # Check parameter interaction forcerelay should activate relay + ["noban", "bloomfilter", "forcerelay", "relay" ], + False) self.replaceinconfig(1, "whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1") self.checkpermission( - # legacy whitelistrelay should be ignored - ["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"], - ["noban", "mempool"], - False) + # legacy whitelistrelay should be ignored + ["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"], + ["noban", "mempool"], + False) self.checkpermission( - # legacy whitelistforcerelay should be ignored - ["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"], - ["noban", "mempool"], - False) + # legacy whitelistforcerelay should be ignored + ["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"], + ["noban", "mempool"], + False) self.checkpermission( - # missing mempool permission to be considered legacy whitelisted - ["-whitelist=noban@127.0.0.1"], - ["noban"], - False) + # missing mempool permission to be considered legacy whitelisted + ["-whitelist=noban@127.0.0.1"], + ["noban"], + False) self.checkpermission( - # all permission added - ["-whitelist=all@127.0.0.1"], - ["forcerelay", "noban", "mempool", "bloomfilter", "relay"], - False) + # all permission added + ["-whitelist=all@127.0.0.1"], + ["forcerelay", "noban", "mempool", "bloomfilter", "relay"], + False) self.stop_node(1) self.nodes[1].assert_start_raises_init_error(["-whitelist=oopsie@127.0.0.1"], "Invalid P2P permission", match=ErrorMatch.PARTIAL_REGEX) diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py index a1a8196557..423741fd27 100644..100755 --- a/test/functional/rpc_setban.py +++ b/test/functional/rpc_setban.py @@ -26,7 +26,7 @@ class SetBanTests(BitcoinTestFramework): self.nodes[1].setban("127.0.0.1", "add") # Node 0 should not be able to reconnect - with self.nodes[1].assert_debug_log(expected_msgs=['dropped (banned)\n']): + with self.nodes[1].assert_debug_log(expected_msgs=['dropped (banned)\n'],timeout=5): self.restart_node(1, []) self.nodes[0].addnode("127.0.0.1:" + str(p2p_port(1)), "onetry") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index df027397d2..9667cf4ea4 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -307,7 +307,8 @@ class TestNode(): wait_until(self.is_node_stopped, timeout=timeout) @contextlib.contextmanager - def assert_debug_log(self, expected_msgs): + def assert_debug_log(self, expected_msgs, timeout=2): + time_end = time.time() + timeout debug_log = os.path.join(self.datadir, self.chain, 'debug.log') with open(debug_log, encoding='utf-8') as dl: dl.seek(0, 2) @@ -315,13 +316,21 @@ class TestNode(): 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)) + while True: + found = True + 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: + found = False + if found: + return + if time.time() >= time_end: + break + time.sleep(0.05) + self._raise_assertion_error('Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(str(expected_msgs), print_log)) @contextlib.contextmanager def assert_memory_usage_stable(self, *, increase_allowed=0.03): diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 3d9be0d0a6..821e1cd3c5 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -293,6 +293,7 @@ def initialize_datadir(dirname, n, chain): f.write("discover=0\n") f.write("listenonion=0\n") f.write("printtoconsole=0\n") + f.write("upnp=0\n") os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True) os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True) return datadir |