diff options
1016 files changed, 10133 insertions, 6227 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index b3ac6d06cb..97fe9866ae 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -29,6 +29,7 @@ base_template: &BASE_TEMPLATE - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - git fetch $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts + # Also, the merge commit is used to lint COMMIT_RANGE="HEAD~..HEAD" main_template: &MAIN_TEMPLATE timeout_in: 120m # https://cirrus-ci.org/faq/#instance-timed-out @@ -64,14 +65,17 @@ compute_credits_template: &CREDITS_TEMPLATE use_compute_credits: $CIRRUS_REPO_FULL_NAME == 'bitcoin/bitcoin' && $CIRRUS_PR != "" task: - name: 'lint [bionic]' + name: 'lint [jammy]' << : *BASE_TEMPLATE container: - image: ubuntu:bionic # For python 3.6, oldest supported version according to doc/dependencies.md + image: ubuntu:jammy cpu: 1 memory: 1G # For faster CI feedback, immediately schedule the linters << : *CREDITS_TEMPLATE + python_cache: + folder: "/tmp/python" + fingerprint_script: cat .python-version /etc/os-release lint_script: - ./ci/lint_run_all.sh env: @@ -101,7 +105,7 @@ task: env: PATH: 'C:\jom;C:\Python39;C:\Python39\Scripts;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin;%PATH%' PYTHONUTF8: 1 - CI_VCPKG_TAG: '2022.09.27' + CI_VCPKG_TAG: '2023.01.09' VCPKG_DOWNLOADS: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\downloads' VCPKG_DEFAULT_BINARY_CACHE: 'C:\Users\ContainerAdministrator\AppData\Local\vcpkg\archives' CCACHE_DIR: 'C:\Users\ContainerAdministrator\AppData\Local\ccache' @@ -152,7 +156,7 @@ task: ccache_cache: folder: '%CCACHE_DIR%' install_tools_script: - - choco install --yes --no-progress ccache --version=4.6.1 + - choco install --yes --no-progress ccache --version=4.7.4 - choco install --yes --no-progress python3 --version=3.9.6 - pip install zmq - ccache --version @@ -175,16 +179,16 @@ task: - ccache --show-stats check_script: - src\test_bitcoin.exe -l test_suite - - src\bench_bitcoin.exe --sanity-check > NUL + - src\bench_bitcoin.exe --sanity-check - python test\util\test_runner.py - python test\util\rpcauth-test.py functional_tests_script: # Increase the dynamic port range to the maximum allowed value to mitigate "OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted". - # See: https://docs.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance + # See: https://learn.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance - netsh int ipv4 set dynamicport tcp start=1025 num=64511 - netsh int ipv6 set dynamicport tcp start=1025 num=64511 # Exclude feature_dbcrash for now due to timeout - - python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=4000 --jobs=6 --timeout-factor=8 --extended --exclude feature_dbcrash + - python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=99999999 --jobs=6 --timeout-factor=8 --extended --exclude feature_dbcrash task: name: 'ARM [unit tests, no functional tests] [bullseye]' @@ -212,6 +216,8 @@ task: << : *GLOBAL_TASK_TEMPLATE container: image: quay.io/centos/centos:stream8 + # For faster CI feedback, immediately schedule one task that runs all tests + << : *CREDITS_TEMPLATE env: << : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV PACKAGE_MANAGER_INSTALL: "yum install -y" @@ -289,10 +295,10 @@ task: FILE_ENV: "./ci/test/00_setup_env_i686_multiprocess.sh" task: - name: '[no wallet, libbitcoinkernel] [bionic]' + name: '[no wallet, libbitcoinkernel] [buster]' << : *GLOBAL_TASK_TEMPLATE container: - image: ubuntu:bionic + image: debian:buster env: << : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV FILE_ENV: "./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh" diff --git a/.github/ISSUE_TEMPLATE/good_first_issue.md b/.github/ISSUE_TEMPLATE/good_first_issue.md index d32e22d360..ff943032ba 100644 --- a/.github/ISSUE_TEMPLATE/good_first_issue.md +++ b/.github/ISSUE_TEMPLATE/good_first_issue.md @@ -15,7 +15,7 @@ assignees: '' #### Useful skills: -<!-- (For example, “C++11 std::thread”, “Qt5 GUI and async GUI design” or “basic understanding of Bitcoin mining and the Bitcoin Core RPC interface”.) --> +<!-- (For example, “std::thread”, “Qt5 GUI and async GUI design” or “basic understanding of Bitcoin mining and the Bitcoin Core RPC interface”.) --> #### Want to work on this issue? diff --git a/.python-version b/.python-version index cd337510be..36f601f10e 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.6.15 +3.7.16 @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2009-2022 The Bitcoin Core developers -Copyright (c) 2009-2022 Bitcoin Developers +Copyright (c) 2009-2023 The Bitcoin Core developers +Copyright (c) 2009-2023 Bitcoin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/build_msvc/README.md b/build_msvc/README.md index b9bebd369c..ba6171fee7 100644 --- a/build_msvc/README.md +++ b/build_msvc/README.md @@ -7,7 +7,9 @@ Visual Studio 2022 is minimum required to build Bitcoin Core. Solution and project files to build with `msbuild` or Visual Studio can be found in the `build_msvc` directory. -To build Bitcoin Core from the command-line, it is sufficient to only install the Visual Studio Build Tools component. +To build Bitcoin Core from the command-line, it is sufficient to only install the [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/) component. + +The "Desktop development with C++" workload must be installed as well. Building with Visual Studio is an alternative to the Linux based [cross-compiler build](../doc/build-windows.md). @@ -15,7 +17,7 @@ Building with Visual Studio is an alternative to the Linux based [cross-compiler Prerequisites --------------------- To build [dependencies](../doc/dependencies.md) (except for [Qt](#qt)), -the default approach is to use the [vcpkg](https://docs.microsoft.com/en-us/cpp/vcpkg) package manager from Microsoft: +the default approach is to use the [vcpkg](https://vcpkg.io) package manager from Microsoft: 1. [Install](https://vcpkg.io/en/getting-started.html) vcpkg. @@ -67,7 +69,7 @@ Alternatively, open the `build_msvc/bitcoin.sln` file in Visual Studio. Security --------------------- -[Base address randomization](https://docs.microsoft.com/en-us/cpp/build/reference/dynamicbase-use-address-space-layout-randomization?view=msvc-160) is used to make Bitcoin Core more secure. When building Bitcoin using the `build_msvc` process base address randomization can be disabled by editing `common.init.vcproj` to change `RandomizedBaseAddress` from `true` to `false` and then rebuilding the project. +[Base address randomization](https://learn.microsoft.com/en-us/cpp/build/reference/dynamicbase-use-address-space-layout-randomization) is used to make Bitcoin Core more secure. When building Bitcoin using the `build_msvc` process base address randomization can be disabled by editing `common.init.vcproj` to change `RandomizedBaseAddress` from `true` to `false` and then rebuilding the project. To check if `bitcoind` has `RandomizedBaseAddress` enabled or disabled run diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj index 16ee32d87e..0b90f341a7 100644 --- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj +++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj @@ -14,7 +14,7 @@ </ItemGroup> <ItemDefinitionGroup> <ClCompile> - <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <DisableSpecificWarnings>4146;4244;4267;4334</DisableSpecificWarnings> </ClCompile> diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py index ae48a52a2f..e02e3abdfa 100755 --- a/build_msvc/msvc-autogen.py +++ b/build_msvc/msvc-autogen.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh index 6f9a4709dd..f7147582dc 100755 --- a/ci/lint/04_install.sh +++ b/ci/lint/04_install.sh @@ -1,27 +1,45 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 ${CI_RETRY_EXE} apt-get update -${CI_RETRY_EXE} apt-get install -y python3-pip curl git gawk jq -( - # Temporary workaround for https://github.com/bitcoin/bitcoin/pull/26130#issuecomment-1260499544 - # Can be removed once the underlying image is bumped to something that includes git2.34 or later - sed -i -e 's/bionic/jammy/g' /etc/apt/sources.list - ${CI_RETRY_EXE} apt-get update - ${CI_RETRY_EXE} apt-get install -y --reinstall git -) +# Lint dependencies: +# - curl/xz-utils (to install shellcheck) +# - git (used in many lint scripts) +# - gpg (used by verify-commits) +${CI_RETRY_EXE} apt-get install -y curl xz-utils git gpg + +if [ -z "${SKIP_PYTHON_INSTALL}" ]; then + PYTHON_PATH=/tmp/python + if [ ! -d "${PYTHON_PATH}/bin" ]; then + ( + git clone https://github.com/pyenv/pyenv.git + cd pyenv/plugins/python-build || exit 1 + ./install.sh + ) + # For dependencies see https://github.com/pyenv/pyenv/wiki#suggested-build-environment + ${CI_RETRY_EXE} apt-get install -y build-essential libssl-dev zlib1g-dev \ + libbz2-dev libreadline-dev libsqlite3-dev curl llvm \ + libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \ + clang + env CC=clang python-build "$(cat "${BASE_ROOT_DIR}/.python-version")" "${PYTHON_PATH}" + fi + export PATH="${PYTHON_PATH}/bin:${PATH}" + command -v python3 + python3 --version +fi ${CI_RETRY_EXE} pip3 install codespell==2.2.1 -${CI_RETRY_EXE} pip3 install flake8==4.0.1 -${CI_RETRY_EXE} pip3 install mypy==0.942 -${CI_RETRY_EXE} pip3 install pyzmq==22.3.0 -${CI_RETRY_EXE} pip3 install vulture==2.3 +${CI_RETRY_EXE} pip3 install flake8==5.0.4 +${CI_RETRY_EXE} pip3 install mypy==0.971 +${CI_RETRY_EXE} pip3 install pyzmq==24.0.1 +${CI_RETRY_EXE} pip3 install vulture==2.6 SHELLCHECK_VERSION=v0.8.0 -curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/ -export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}" +curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \ + tar --xz -xf - --directory /tmp/ +mv "/tmp/shellcheck-${SHELLCHECK_VERSION}/shellcheck" /usr/bin/ diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh index 4506848740..fa28f6126c 100755 --- a/ci/lint/06_script.sh +++ b/ci/lint/06_script.sh @@ -1,15 +1,23 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 -GIT_HEAD=$(git rev-parse HEAD) -if [ -n "$CIRRUS_PR" ]; then - COMMIT_RANGE="${CIRRUS_BASE_SHA}..$GIT_HEAD" +if [ -n "$LOCAL_BRANCH" ]; then + # To faithfully recreate CI linting locally, specify all commits on the current + # branch. + COMMIT_RANGE="$(git merge-base HEAD master)..HEAD" +elif [ -n "$CIRRUS_PR" ]; then + COMMIT_RANGE="HEAD~..HEAD" + echo + git log --no-merges --oneline "$COMMIT_RANGE" + echo test/lint/commit-script-check.sh "$COMMIT_RANGE" +else + COMMIT_RANGE="SKIP_EMPTY_NOT_A_PR" fi export COMMIT_RANGE @@ -36,8 +44,3 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "bitcoin/bitcoin" ] && [ "$CIRRUS_PR" = "" ] ; t ${CI_RETRY_EXE} gpg --keyserver hkps://keys.openpgp.org --recv-keys "${KEYS[@]}" && ./contrib/verify-commits/verify-commits.py; fi - -if [ -n "$COMMIT_RANGE" ]; then - echo - git log --no-merges --oneline "$COMMIT_RANGE" -fi diff --git a/ci/lint/Dockerfile b/ci/lint/Dockerfile new file mode 100644 index 0000000000..03c20c7286 --- /dev/null +++ b/ci/lint/Dockerfile @@ -0,0 +1,29 @@ +# See test/lint/README.md for usage. +# +# This container basically has to live in this directory in order to pull in the CI +# install scripts. If it lived in the root directory, it would have to pull in the +# entire repo as docker context during build; if it lived elsewhere, it wouldn't be +# able to make back-references to pull in the install scripts. So here it lives. + +FROM python:3.7-buster + +ENV DEBIAN_FRONTEND=noninteractive +ENV LC_ALL=C.UTF-8 + +# This is used by the 04_install.sh script; we can't read the Python version from +# .python-version for the same reasons as above, and it's more efficient to pull a +# preexisting Python image than it is to build from source. +ENV SKIP_PYTHON_INSTALL=1 + +# Must be built from ./ci/lint/ for these paths to work. +COPY ./docker-entrypoint.sh /entrypoint.sh +COPY ./04_install.sh /install.sh + +RUN /install.sh && \ + echo 'alias lint="./ci/lint/06_script.sh"' >> ~/.bashrc && \ + chmod 755 /entrypoint.sh && \ + rm -rf /var/lib/apt/lists/* + + +WORKDIR /bitcoin +ENTRYPOINT ["/entrypoint.sh"] diff --git a/ci/lint/docker-entrypoint.sh b/ci/lint/docker-entrypoint.sh new file mode 100755 index 0000000000..3fdbbb0761 --- /dev/null +++ b/ci/lint/docker-entrypoint.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +export LC_ALL=C + +# Fixes permission issues when there is a container UID/GID mismatch with the owner +# of the mounted bitcoin src dir. +git config --global --add safe.directory /bitcoin + +if [ -z "$1" ]; then + LOCAL_BRANCH=1 bash -ic "./ci/lint/06_script.sh" +else + exec "$@" +fi diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh index 5a150d5f80..07c20f632d 100755 --- a/ci/test/00_setup_env.sh +++ b/ci/test/00_setup_env.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -48,7 +48,7 @@ export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false} export EXPECTED_TESTS_DURATION_IN_SECONDS=${EXPECTED_TESTS_DURATION_IN_SECONDS:-1000} export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed} -export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:20.04} +export CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG:-ubuntu:20.04} # Randomize test order. # See https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/random.html export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1} @@ -66,7 +66,7 @@ export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out/$HOST} export BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build} export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/releases/$HOST} export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks} -export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps bison} +export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps bison} export GOAL=${GOAL:-install} export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets} export PATH=${BASE_ROOT_DIR}/ci/retry:$PATH diff --git a/ci/test/00_setup_env_android.sh b/ci/test/00_setup_env_android.sh index 6732db36ad..e1830b4f49 100755 --- a/ci/test/00_setup_env_android.sh +++ b/ci/test/00_setup_env_android.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8 export HOST=aarch64-linux-android export PACKAGES="unzip openjdk-8-jdk gradle" export CONTAINER_NAME=ci_android -export DOCKER_NAME_TAG="ubuntu:focal" +export CI_IMAGE_NAME_TAG="ubuntu:focal" export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh index 932be4b43d..ac0c0be96a 100755 --- a/ci/test/00_setup_env_arm.sh +++ b/ci/test/00_setup_env_arm.sh @@ -18,7 +18,7 @@ if [ -n "$QEMU_USER_CMD" ]; then fi export CONTAINER_NAME=ci_arm_linux # Use debian to avoid 404 apt errors when cross compiling -export DOCKER_NAME_TAG="debian:bullseye" +export CI_IMAGE_NAME_TAG="debian:bullseye" export USE_BUSY_BOX=true export RUN_UNIT_TESTS=true export RUN_FUNCTIONAL_TESTS=false diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh index 1ce3261f44..e8f963c8a9 100755 --- a/ci/test/00_setup_env_i686_centos.sh +++ b/ci/test/00_setup_env_i686_centos.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,8 +8,8 @@ export LC_ALL=C.UTF-8 export HOST=i686-pc-linux-gnu export CONTAINER_NAME=ci_i686_centos -export DOCKER_NAME_TAG=quay.io/centos/centos:stream8 -export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison" +export CI_IMAGE_NAME_TAG=quay.io/centos/centos:stream8 +export CI_BASE_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python38 python38-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison" export PIP_PACKAGES="pyzmq" export GOAL="install" export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports" diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh index 76de87d955..9e3ea0d383 100755 --- a/ci/test/00_setup_env_i686_multiprocess.sh +++ b/ci/test/00_setup_env_i686_multiprocess.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8 export HOST=i686-pc-linux-gnu export CONTAINER_NAME=ci_i686_multiprocess -export DOCKER_NAME_TAG=ubuntu:20.04 +export CI_IMAGE_NAME_TAG=ubuntu:20.04 export PACKAGES="cmake python3 llvm clang g++-multilib" export DEP_OPTS="DEBUG=1 MULTIPROCESS=1" export GOAL="install" diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh index c4f22c8f9e..fe42871c31 100755 --- a/ci/test/00_setup_env_mac.sh +++ b/ci/test/00_setup_env_mac.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_macos_cross -export DOCKER_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to macos +export CI_IMAGE_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to macos export HOST=x86_64-apple-darwin export PACKAGES="cmake libz-dev libtinfo5 python3-setuptools xorriso" export XCODE_VERSION=12.2 diff --git a/ci/test/00_setup_env_mac_native_arm64.sh b/ci/test/00_setup_env_mac_native_arm64.sh index cb0e13e77c..a6799d7b88 100755 --- a/ci/test/00_setup_env_mac_native_arm64.sh +++ b/ci/test/00_setup_env_mac_native_arm64.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index 4f1792a9f0..bb3f6997f3 100755 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -1,19 +1,26 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 -# We install an up-to-date 'bpfcc-tools' package from an untrusted PPA. -# This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages. -# See the if-then in ci/test/04_install.sh too. -export ADD_UNTRUSTED_BPFCC_PPA=true +# Only install BCC tracing packages in Cirrus CI. +if [[ "${CIRRUS_CI}" == "true" ]]; then + # We install an up-to-date 'bpfcc-tools' package from an untrusted PPA. + # This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages. + # See the if-then in ci/test/04_install.sh too. + export ADD_UNTRUSTED_BPFCC_PPA=true + export BPFCC_PACKAGE="bpfcc-tools" +else + export ADD_UNTRUSTED_BPFCC_PPA=false + export BPFCC_PACKAGE="" +fi export CONTAINER_NAME=ci_native_asan -export PACKAGES="systemtap-sdt-dev bpfcc-tools clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev" -export DOCKER_NAME_TAG=ubuntu:22.04 # May not run in docker unless --enable-usdt is dropped +export PACKAGES="systemtap-sdt-dev clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}" +export CI_IMAGE_NAME_TAG=ubuntu:22.04 export NO_DEPENDS=1 export GOAL="install" -export BITCOIN_CONFIG="--enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" +export BITCOIN_CONFIG="--enable-c++20 --enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh index d7caec8359..a2d393bb5a 100755 --- a/ci/test/00_setup_env_native_fuzz.sh +++ b/ci/test/00_setup_env_native_fuzz.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 DOCKER_NAME_TAG="ubuntu:22.04" +export CI_IMAGE_NAME_TAG="ubuntu:22.04" export CONTAINER_NAME=ci_native_fuzz export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev" export NO_DEPENDS=1 diff --git a/ci/test/00_setup_env_native_fuzz_with_msan.sh b/ci/test/00_setup_env_native_fuzz_with_msan.sh index 071bac8fb3..d35701160a 100755 --- a/ci/test/00_setup_env_native_fuzz_with_msan.sh +++ b/ci/test/00_setup_env_native_fuzz_with_msan.sh @@ -1,23 +1,23 @@ #!/usr/bin/env bash # -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 DOCKER_NAME_TAG="ubuntu:20.04" +export CI_IMAGE_NAME_TAG="ubuntu:20.04" LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/build/" export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls" LIBCXX_FLAGS="-nostdinc++ -stdlib=libc++ -L${LIBCXX_DIR}lib -lc++abi -I${LIBCXX_DIR}include -I${LIBCXX_DIR}include/c++/v1 -lpthread -Wl,-rpath,${LIBCXX_DIR}lib -Wno-unused-command-line-argument" export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}" -export CONTAINER_NAME="ci_native_msan" +export CONTAINER_NAME="ci_native_fuzz_msan" export PACKAGES="clang-12 llvm-12 cmake" # BDB generates false-positives and will be removed in future export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'" export GOAL="install" -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no --prefix=${DEPENDS_DIR}/x86_64-pc-linux-gnu/ CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" export USE_MEMORY_SANITIZER="true" export RUN_UNIT_TESTS="false" export RUN_FUNCTIONAL_TESTS="false" diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh index 97c530e19e..75c10046b7 100755 --- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 DOCKER_NAME_TAG="ubuntu:22.04" +export CI_IMAGE_NAME_TAG="ubuntu:22.04" export CONTAINER_NAME=ci_native_fuzz_valgrind export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev valgrind" export NO_DEPENDS=1 diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh index 34a792ec8f..48049a0a3c 100755 --- a/ci/test/00_setup_env_native_msan.sh +++ b/ci/test/00_setup_env_native_msan.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 DOCKER_NAME_TAG="ubuntu:20.04" +export CI_IMAGE_NAME_TAG="ubuntu:20.04" LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/build/" export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls" LIBCXX_FLAGS="-nostdinc++ -stdlib=libc++ -L${LIBCXX_DIR}lib -lc++abi -I${LIBCXX_DIR}include -I${LIBCXX_DIR}include/c++/v1 -lpthread -Wl,-rpath,${LIBCXX_DIR}lib -Wno-unused-command-line-argument" @@ -17,7 +17,7 @@ export PACKAGES="clang-12 llvm-12 cmake" # BDB generates false-positives and will be removed in future export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'" export GOAL="install" -export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no --prefix=${DEPENDS_DIR}/x86_64-pc-linux-gnu/ CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" +export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'" export USE_MEMORY_SANITIZER="true" export RUN_FUNCTIONAL_TESTS="false" export CCACHE_SIZE=250M diff --git a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh index 63560a5f5c..08bb5d1eab 100755 --- a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh +++ b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh @@ -1,14 +1,16 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 CONTAINER_NAME=ci_native_nowallet_libbitcoinkernel -export DOCKER_NAME_TAG=ubuntu:18.04 # Use bionic to have one config run the tests in python3.6, see doc/dependencies.md -export PACKAGES="python3-zmq clang-8 llvm-8 libc++abi-8-dev libc++-8-dev" # Use clang-8 to test C++17 compatibility, see doc/dependencies.md +export CI_IMAGE_NAME_TAG=debian:buster +# Use minimum supported python3.7 and clang-8, see doc/dependencies.md +export PACKAGES="-t buster-backports python3-zmq clang-8 llvm-8 libc++abi-8-dev libc++-8-dev" +export APPEND_APT_SOURCES_LIST="deb http://deb.debian.org/debian buster-backports main" export DEP_OPTS="NO_WALLET=1 CC=clang-8 CXX='clang++-8 -stdlib=libc++'" export GOAL="install" export BITCOIN_CONFIG="--enable-reduce-exports CC=clang-8 CXX='clang++-8 -stdlib=libc++' --enable-experimental-util-chainstate --with-experimental-kernel-lib --enable-shared" diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh index 8a6ea62d5c..3f39185ae8 100755 --- a/ci/test/00_setup_env_native_qt5.sh +++ b/ci/test/00_setup_env_native_qt5.sh @@ -1,13 +1,14 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 CONTAINER_NAME=ci_native_qt5 -export DOCKER_NAME_TAG=debian:buster # Check that buster gcc-8 can compile our C++17 and run our functional tests in python3, see doc/dependencies.md +export CI_IMAGE_NAME_TAG=debian:buster +# Use minimum supported python3.7 and gcc-8, see doc/dependencies.md export PACKAGES="gcc-8 g++-8 python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev" export DEP_OPTS="NO_QT=1 NO_UPNP=1 NO_NATPMP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1 CC=gcc-8 CXX=g++-8" export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh index 11a12e336a..06ffe14636 100755 --- a/ci/test/00_setup_env_native_tidy.sh +++ b/ci/test/00_setup_env_native_tidy.sh @@ -6,7 +6,7 @@ export LC_ALL=C.UTF-8 -export DOCKER_NAME_TAG="ubuntu:22.04" +export CI_IMAGE_NAME_TAG="ubuntu:22.04" export CONTAINER_NAME=ci_native_tidy export PACKAGES="clang libclang-dev llvm-dev clang-tidy bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev" export NO_DEPENDS=1 @@ -15,5 +15,5 @@ export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=false export RUN_TIDY=true export GOAL="install" -export BITCOIN_CONFIG="CC=clang CXX=clang++ --enable-c++20 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'" +export BITCOIN_CONFIG="CC=clang CXX=clang++ --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'" export CCACHE_SIZE=200M diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index 6bf8391209..61bcd98f0a 100755 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 CONTAINER_NAME=ci_native_tsan -export DOCKER_NAME_TAG=ubuntu:22.04 +export CI_IMAGE_NAME_TAG=ubuntu:22.04 export PACKAGES="clang-13 llvm-13 libc++abi-13-dev libc++-13-dev python3-zmq" export DEP_OPTS="CC=clang-13 CXX='clang++-13 -stdlib=libc++'" export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread CC=clang-13 CXX='clang++-13 -stdlib=libc++'" +export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread" diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh index d8c08fca39..039a22b02e 100755 --- a/ci/test/00_setup_env_native_valgrind.sh +++ b/ci/test/00_setup_env_native_valgrind.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 DOCKER_NAME_TAG="ubuntu:22.04" +export CI_IMAGE_NAME_TAG="ubuntu:22.04" export CONTAINER_NAME=ci_native_valgrind export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev" export USE_VALGRIND=1 diff --git a/ci/test/00_setup_env_s390x.sh b/ci/test/00_setup_env_s390x.sh index 136edb6662..af18703ce1 100755 --- a/ci/test/00_setup_env_s390x.sh +++ b/ci/test/00_setup_env_s390x.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,7 +18,7 @@ if [ -n "$QEMU_USER_CMD" ]; then fi # Use debian to avoid 404 apt errors export CONTAINER_NAME=ci_s390x -export DOCKER_NAME_TAG="debian:bookworm" +export CI_IMAGE_NAME_TAG="debian:bookworm" export TEST_RUNNER_ENV="LC_ALL=C" export TEST_RUNNER_EXTRA="--exclude feature_init,rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547 export RUN_FUNCTIONAL_TESTS=true diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh index 3600113551..817ee724c2 100755 --- a/ci/test/00_setup_env_win64.sh +++ b/ci/test/00_setup_env_win64.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 CONTAINER_NAME=ci_win64 -export DOCKER_NAME_TAG=ubuntu:22.04 # Check that Jammy can cross-compile to win64 +export CI_IMAGE_NAME_TAG=ubuntu:22.04 # Check that Jammy can cross-compile to win64 export HOST=x86_64-w64-mingw32 export DPKG_ADD_ARCH="i386" export PACKAGES="python3 nsis g++-mingw-w64-x86-64-posix wine-binfmt wine64 wine32 file" diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh index a4f1a8a7ff..9bfe555243 100755 --- a/ci/test/04_install.sh +++ b/ci/test/04_install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,14 +20,20 @@ export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/t export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1" env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|LC_ALL|BOOST_TEST_RANDOM|DEBIAN_FRONTEND|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|PREVIOUS_RELEASES_DIR)' | tee /tmp/env if [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764) - DOCKER_ADMIN="--cap-add SYS_PTRACE" + CI_CONTAINER_CAP="--cap-add SYS_PTRACE" fi export P_CI_DIR="$PWD" +export BINS_SCRATCH_DIR="${BASE_SCRATCH_DIR}/bins/" if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then - echo "Creating $DOCKER_NAME_TAG container to run in" - ${CI_RETRY_EXE} docker pull "$DOCKER_NAME_TAG" + echo "Creating $CI_IMAGE_NAME_TAG container to run in" + LOCAL_UID=$(id -u) + LOCAL_GID=$(id -g) + + # the name isn't important, so long as we use the same UID + LOCAL_USER=nonroot + ${CI_RETRY_EXE} docker pull "$CI_IMAGE_NAME_TAG" if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then echo "Restart docker before run to stop and clear all containers started with --rm" @@ -35,7 +41,7 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then fi # shellcheck disable=SC2086 - DOCKER_ID=$(docker run $DOCKER_ADMIN --rm --interactive --detach --tty \ + CI_CONTAINER_ID=$(docker run $CI_CONTAINER_CAP --rm --interactive --detach --tty \ --mount type=bind,src=$BASE_ROOT_DIR,dst=/ro_base,readonly \ --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR \ --mount type=bind,src=$DEPENDS_DIR,dst=$DEPENDS_DIR \ @@ -43,24 +49,40 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then -w $BASE_ROOT_DIR \ --env-file /tmp/env \ --name $CONTAINER_NAME \ - $DOCKER_NAME_TAG) - export DOCKER_CI_CMD_PREFIX="docker exec $DOCKER_ID" + $CI_IMAGE_NAME_TAG) + export CI_CONTAINER_ID + + # Create a non-root user inside the container which matches the local user. + # + # This prevents the root user in the container modifying the local file system permissions + # on the mounted directories + docker exec "$CI_CONTAINER_ID" useradd -u "$LOCAL_UID" -o -m "$LOCAL_USER" + docker exec "$CI_CONTAINER_ID" groupmod -o -g "$LOCAL_GID" "$LOCAL_USER" + docker exec "$CI_CONTAINER_ID" chown -R "$LOCAL_USER":"$LOCAL_USER" "${BASE_ROOT_DIR}" + export CI_EXEC_CMD_PREFIX_ROOT="docker exec -u 0 $CI_CONTAINER_ID" + export CI_EXEC_CMD_PREFIX="docker exec -u $LOCAL_UID $CI_CONTAINER_ID" else echo "Running on host system without docker wrapper" fi CI_EXEC () { - $DOCKER_CI_CMD_PREFIX bash -c "export PATH=$BASE_SCRATCH_DIR/bins/:\$PATH && cd \"$P_CI_DIR\" && $*" + $CI_EXEC_CMD_PREFIX bash -c "export PATH=${BINS_SCRATCH_DIR}:\$PATH && cd \"$P_CI_DIR\" && $*" +} +CI_EXEC_ROOT () { + $CI_EXEC_CMD_PREFIX_ROOT bash -c "export PATH=${BINS_SCRATCH_DIR}:\$PATH && cd \"$P_CI_DIR\" && $*" } export -f CI_EXEC +export -f CI_EXEC_ROOT + +CI_EXEC mkdir -p "${BINS_SCRATCH_DIR}" if [ -n "$DPKG_ADD_ARCH" ]; then - CI_EXEC dpkg --add-architecture "$DPKG_ADD_ARCH" + CI_EXEC_ROOT dpkg --add-architecture "$DPKG_ADD_ARCH" fi -if [[ $DOCKER_NAME_TAG == *centos* ]]; then - ${CI_RETRY_EXE} CI_EXEC dnf -y install epel-release - ${CI_RETRY_EXE} CI_EXEC dnf -y --allowerasing install "$DOCKER_PACKAGES" "$PACKAGES" +if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then + ${CI_RETRY_EXE} CI_EXEC_ROOT dnf -y install epel-release + ${CI_RETRY_EXE} CI_EXEC_ROOT dnf -y --allowerasing install "$CI_BASE_PACKAGES" "$PACKAGES" elif [ "$CI_USE_APT_INSTALL" != "no" ]; then if [[ "${ADD_UNTRUSTED_BPFCC_PPA}" == "true" ]]; then # Ubuntu 22.04 LTS and Debian 11 both have an outdated bpfcc-tools packages. @@ -68,10 +90,13 @@ elif [ "$CI_USE_APT_INSTALL" != "no" ]; then # packages. Meanwhile, use an untrusted PPA to install an up-to-date version of the bpfcc-tools # package. # TODO: drop this once we can use newer images in GCE - CI_EXEC add-apt-repository ppa:hadret/bpfcc + CI_EXEC_ROOT add-apt-repository ppa:hadret/bpfcc + fi + if [[ -n "${APPEND_APT_SOURCES_LIST}" ]]; then + CI_EXEC_ROOT echo "${APPEND_APT_SOURCES_LIST}" >> /etc/apt/sources.list fi - ${CI_RETRY_EXE} CI_EXEC apt-get update - ${CI_RETRY_EXE} CI_EXEC apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES" + ${CI_RETRY_EXE} CI_EXEC_ROOT apt-get update + ${CI_RETRY_EXE} CI_EXEC_ROOT apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$CI_BASE_PACKAGES" fi if [ -n "$PIP_PACKAGES" ]; then @@ -112,8 +137,8 @@ fi CI_EXEC mkdir -p "${BASE_SCRATCH_DIR}/sanitizer-output/" if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then - CI_EXEC "update-alternatives --install /usr/bin/clang++ clang++ \$(which clang++-12) 100" - CI_EXEC "update-alternatives --install /usr/bin/clang clang \$(which clang-12) 100" + CI_EXEC_ROOT "update-alternatives --install /usr/bin/clang++ clang++ \$(which clang++-12) 100" + CI_EXEC_ROOT "update-alternatives --install /usr/bin/clang clang \$(which clang-12) 100" CI_EXEC "mkdir -p ${BASE_SCRATCH_DIR}/msan/build/" CI_EXEC "git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-12.0.0 ${BASE_SCRATCH_DIR}/msan/llvm-project" CI_EXEC "cd ${BASE_SCRATCH_DIR}/msan/build/ && cmake -DLLVM_ENABLE_PROJECTS='libcxx;libcxxabi' -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_SANITIZER=MemoryWithOrigins -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_TARGETS_TO_BUILD=X86 ../llvm-project/llvm/" @@ -126,7 +151,7 @@ if [[ "${RUN_TIDY}" == "true" ]]; then CI_EXEC "mkdir -p ${DIR_IWYU}/build/" CI_EXEC "git clone --depth=1 https://github.com/include-what-you-use/include-what-you-use -b clang_14 ${DIR_IWYU}/include-what-you-use" CI_EXEC "cd ${DIR_IWYU}/build && cmake -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-14 ../include-what-you-use" - CI_EXEC "cd ${DIR_IWYU}/build && make install $MAKEJOBS" + CI_EXEC_ROOT "cd ${DIR_IWYU}/build && make install $MAKEJOBS" fi fi @@ -137,12 +162,10 @@ fi if [ "$USE_BUSY_BOX" = "true" ]; then echo "Setup to use BusyBox utils" - CI_EXEC mkdir -p "${BASE_SCRATCH_DIR}/bins/" # tar excluded for now because it requires passing in the exact archive type in ./depends (fixed in later BusyBox version) - # find excluded for now because it does not recognize the -delete option in ./depends (fixed in later BusyBox version) # ar excluded for now because it does not recognize the -q option in ./depends (unknown if fixed) # shellcheck disable=SC1010 - CI_EXEC for util in \$\(busybox --list \| grep -v "^ar$" \| grep -v "^tar$" \| grep -v "^find$"\)\; do ln -s \$\(command -v busybox\) "${BASE_SCRATCH_DIR}/bins/\$util"\; done + CI_EXEC for util in \$\(busybox --list \| grep -v "^ar$" \| grep -v "^tar$" \)\; do ln -s \$\(command -v busybox\) "${BINS_SCRATCH_DIR}/\$util"\; done # Print BusyBox version CI_EXEC patch --help fi diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh index ef3dff86ca..f49305597d 100755 --- a/ci/test/05_before_script.sh +++ b/ci/test/05_before_script.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +11,7 @@ if [ "$CI_OS_NAME" == "macos" ]; then echo > "${HOME}/Library/Application Support/Bitcoin" else CI_EXEC echo \> \$HOME/.bitcoin + CI_EXEC_ROOT echo \> \$HOME/.bitcoin fi CI_EXEC mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources" @@ -37,7 +38,7 @@ if [ -n "$ANDROID_HOME" ] && [ ! -d "$ANDROID_HOME" ]; then fi if [ -z "$NO_DEPENDS" ]; then - if [[ $DOCKER_NAME_TAG == *centos* ]]; then + if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then # CentOS has problems building the depends if the config shell is not explicitly set # (i.e. for libevent a Makefile with an empty SHELL variable is generated, leading to # an error as the first command is executed) diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh index 13693a2ecf..5856d33d2d 100755 --- a/ci/test/06_script_a.sh +++ b/ci/test/06_script_a.sh @@ -1,12 +1,15 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 -BITCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking --prefix=$DEPENDS_DIR/$HOST" +BITCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking" +if [ -z "$NO_DEPENDS" ]; then + BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} CONFIG_SITE=$DEPENDS_DIR/$HOST/share/config.site" +fi if [ -z "$NO_WERROR" ]; then BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror" fi @@ -23,7 +26,7 @@ if [ -n "$ANDROID_TOOLS_URL" ]; then exit 0 fi -BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib" +BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --prefix=$BASE_OUTDIR" if [ -n "$CONFIG_SHELL" ]; then CI_EXEC "$CONFIG_SHELL" -c "./autogen.sh" diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh index 6177736722..f792a9f192 100755 --- a/ci/test/06_script_b.sh +++ b/ci/test/06_script_b.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,7 +31,7 @@ if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then fi if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then - CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${TEST_RUNNER_ENV}" test/functional/test_runner.py --ci "$MAKEJOBS" --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=4000 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA}" --quiet --failfast + CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${TEST_RUNNER_ENV}" test/functional/test_runner.py --ci "$MAKEJOBS" --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA}" --quiet --failfast fi if [ "${RUN_TIDY}" = "true" ]; then @@ -56,7 +56,7 @@ if [ "${RUN_TIDY}" = "true" ]; then " src/rpc/fees.cpp"\ " src/rpc/signmessage.cpp"\ " src/test/fuzz/txorphan.cpp"\ - " src/threadinterrupt.cpp"\ + " src/test/fuzz/util/"\ " src/util/bip32.cpp"\ " src/util/bytevectorhash.cpp"\ " src/util/check.cpp"\ @@ -70,6 +70,7 @@ if [ "${RUN_TIDY}" = "true" ]; then " src/util/strencodings.cpp"\ " src/util/string.cpp"\ " src/util/syserror.cpp"\ + " src/util/threadinterrupt.cpp"\ " src/zmq"\ " -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp" fi @@ -81,3 +82,8 @@ fi if [ "$RUN_FUZZ_TESTS" = "true" ]; then CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/fuzz/test_runner.py "${FUZZ_TESTS_CONFIG}" "$MAKEJOBS" -l DEBUG "${DIR_FUZZ_IN}" fi + +if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then + echo "Stop and remove CI container by ID" + docker container kill "${CI_CONTAINER_ID}" +fi diff --git a/ci/test/wrap-qemu.sh b/ci/test/wrap-qemu.sh index eb31edbce8..e028ede378 100755 --- a/ci/test/wrap-qemu.sh +++ b/ci/test/wrap-qemu.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/ci/test/wrap-wine.sh b/ci/test/wrap-wine.sh index 1662f8f6a3..90e53887bc 100755 --- a/ci/test/wrap-wine.sh +++ b/ci/test/wrap-wine.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/configure.ac b/configure.ac index 685c840f2b..c982ee8b8c 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ define(_CLIENT_VERSION_MINOR, 99) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, false) -define(_COPYRIGHT_YEAR, 2022) +define(_COPYRIGHT_YEAR, 2023) define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]]) AC_INIT([Bitcoin Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_BUILD)m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/]) @@ -120,8 +120,8 @@ AC_PATH_TOOL([AR], [ar]) AC_PATH_TOOL([GCOV], [gcov]) AC_PATH_TOOL([LLVM_COV], [llvm-cov]) AC_PATH_PROG([LCOV], [lcov]) -dnl Python 3.6 is specified in .python-version and should be used if available, see doc/dependencies.md -AC_PATH_PROGS([PYTHON], [python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3 python]) +dnl Python 3.7 is specified in .python-version and should be used if available, see doc/dependencies.md +AC_PATH_PROGS([PYTHON], [python3.7 python3.8 python3.9 python3.10 python3.11 python3.12 python3 python]) AC_PATH_PROG([GENHTML], [genhtml]) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG([CCACHE], [ccache]) @@ -1006,7 +1006,7 @@ if test "$TARGET_OS" = "darwin"; then AX_CHECK_LINK_FLAG([-Wl,-bind_at_load], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-bind_at_load"], [], [$LDFLAG_WERROR]) fi -AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h unistd.h sys/types.h sys/stat.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h]) +AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h]) AC_CHECK_DECLS([getifaddrs, freeifaddrs],[CHECK_SOCKET],, [#include <sys/types.h> @@ -1461,7 +1461,7 @@ if test "$use_natpmp" != "no"; then CPPFLAGS="$TEMP_CPPFLAGS" fi -if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench" = "nonononononono"; then +if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench" = "nononononononono"; then use_boost=no else use_boost=yes @@ -1870,7 +1870,7 @@ else AC_MSG_RESULT([no]) fi -if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then +if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nononononononononono"; then AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests]) fi @@ -1984,10 +1984,6 @@ AC_SUBST(HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([doc/Doxyfile])]) -AC_CONFIG_LINKS([contrib/devtools/security-check.py:contrib/devtools/security-check.py]) -AC_CONFIG_LINKS([contrib/devtools/symbol-check.py:contrib/devtools/symbol-check.py]) -AC_CONFIG_LINKS([contrib/devtools/test-security-check.py:contrib/devtools/test-security-check.py]) -AC_CONFIG_LINKS([contrib/devtools/test-symbol-check.py:contrib/devtools/test-symbol-check.py]) AC_CONFIG_LINKS([contrib/devtools/iwyu/bitcoin.core.imp:contrib/devtools/iwyu/bitcoin.core.imp]) AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) AC_CONFIG_LINKS([contrib/macdeploy/background.tiff:contrib/macdeploy/background.tiff]) @@ -2016,7 +2012,7 @@ LIBS_TEMP="$LIBS" unset LIBS LIBS="$LIBS_TEMP" -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --disable-module-ecdh" AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT diff --git a/contrib/README.md b/contrib/README.md index ae1372e95d..3c6e978061 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -26,9 +26,6 @@ The [Debian](/contrib/debian) subfolder contains the copyright file. All other packaging related files can be found in the [bitcoin-core/packaging](https://github.com/bitcoin-core/packaging) repository. -### [Builder keys](/contrib/builder-keys) -PGP keys used for signing Bitcoin Core [release](/doc/release-process.md) results. - ### [MacDeploy](/contrib/macdeploy) ### Scripts and notes for Mac builds. @@ -40,3 +37,9 @@ Utilities to generate test vectors for the data-driven Bitcoin tests. ### [Verify Binaries](/contrib/verifybinaries) ### This script attempts to download and verify the signature file SHA256SUMS.asc from bitcoin.org. + +Command Line Tools +--------------------- + +### [Completions](/contrib/completions) ### +Shell completions for bash and fish. diff --git a/contrib/builder-keys/README.md b/contrib/builder-keys/README.md deleted file mode 100644 index a6179d6012..0000000000 --- a/contrib/builder-keys/README.md +++ /dev/null @@ -1,33 +0,0 @@ -## PGP keys of builders and Developers - -The file `keys.txt` contains fingerprints of the public keys of builders and -active developers. - -The associated keys are mainly used to sign git commits or the build results -of Guix builds. - -The most recent version of each pgp key can be found on most pgp key servers. - -Fetch the latest version from the key server to see if any key was revoked in -the meantime. -To fetch the latest version of all pgp keys in your gpg homedir, - -```sh -gpg --refresh-keys -``` - -To fetch keys of builders and active developers, feed the list of fingerprints -of the primary keys into gpg: - -On \*NIX: -```sh -while read fingerprint keyholder_name; do gpg --keyserver hkps://keys.openpgp.org --recv-keys ${fingerprint}; done < ./keys.txt -``` - -On Windows (requires Gpg4win >= 4.0.0): -``` -FOR /F "tokens=1" %i IN (keys.txt) DO gpg --keyserver hkps://keys.openpgp.org --recv-keys %i -``` - -Add your key to the list if you provided Guix attestations for two major or -minor releases of Bitcoin Core. diff --git a/contrib/builder-keys/keys.txt b/contrib/builder-keys/keys.txt deleted file mode 100644 index 2d96b863ef..0000000000 --- a/contrib/builder-keys/keys.txt +++ /dev/null @@ -1,58 +0,0 @@ -982A193E3CE0EED535E09023188CBB2648416AD5 0xB10C (0xb10c) -9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C Aaron Clauson (sipsorcery) -617C90010B3BD370B0AC7D424BB42E31C79111B8 Akira Takizawa (akx20000) -E944AE667CF960B1004BC32FCA662BE18B877A60 Andreas Schildbach (aschildbach) -152812300785C96444D3334D17565732E08E5E41 Andrew Chow (achow101) -590B7292695AFFA5B672CBB2E13FC145CD3F4304 Antoine Poinsot (darosior) -0AD83877C1F0CD1EE9BD660AD7CC770B81FD22A8 Ben Carman (benthecarman) -912FD3228387123DC97E0E57D5566241A0295FA9 BtcDrak (btcdrak) -04017A2A6D9A0CCDC81D8EC296AB007F1A7ED999 Carl Dong (dongcarl) -C519EBCF3B926298946783EFF6430754120EC2F4 Christian Decker (cdecker) -18AE2F798E0D239755DA4FD24B79F986CBDF8736 Chun Kuan Le (ken2812221) -101598DC823C1B5F9A6624ABA5E0907A0380E6C3 CoinForensics (CoinForensics) -F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur (centaur) -C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields (cfields) -BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random (devrandom) -6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark (droark) -948444FCE03B05BA5AB0591EC37B1C1D44C786EE Duncan Dean (dunxen) -1C6621605EC50319C463D56C7F81D87985D61612 Emanuele Cisbani (cisba) -9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos) -D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece (fivepiece) -6F993B250557E7B016ADE5713BDCDA2D87A881D9 Fuzzbawls (Fuzzbawls) -01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen (gavinandresen) -6B002C6EA3F91B1B0DF0C9BC8F617F1200A6D25C Gloria Zhao (glozow) -D1DBF2C4B96F2DEBF4C16654410108112E7EA81F Hennadii Stepanov (hebasto) -A2FD494D0021AA9B4FA58F759102B7AE654A4A5A Ilyas Ridhuan (IlyasRidhuan) -2688F5A9A4BE0F295E921E8A25F27A38A47AD566 James O'Beirne (jamesob) -D3F22A3A4C366C2DCB66D3722DA9C5A7FA81EA35 Jarol Rodriguez (jarolrod) -7480909378D544EA6B6DCEB7535B12980BB8A4D3 Jeffri H Frontz (jhfrontz) -D3CC177286005BB8FF673294C5242A1AB3936517 jl2012 (jl2012) -82921A4B88FD454B7EB8CE3C796C4109063D4EAF Jon Atack (jonatack) -32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli (jonasschnelli) -4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon (jtimon) -C42AFF7C61B3E44A1454CD3557AF762DB3353322 Karl-Johan Alm (kallewoof) -70A1D47DD44F59DF8B22244333E472FE870C7E5D Kristaps Kaupe (kristapsk) -30DE693AE0DE9E37B3E7EB6BBFF0F67810C1EED1 Lisa Neigut (niftynei) -E463A93F5F3117EEDE6C7316BD02942421F4889F Luke Dashjr (luke-jr) -B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B Marco Falke (marco) -07DF3E57A548CCFB7530709189BBB8663E2E65CE Matt Corallo (BlueMatt) -CA03882CB1FC067B5D3ACFE4D300116E1C875A3D MeshCollider (meshcollider) -E777299FC265DD04793070EB944D35F9AC3DB76A Michael Ford (fanquake) -AD5764F4ADCE1B99BDFD179E12335A271D4D62EC Michael Tidwell (miketwenty1) -9692B91BBF0E8D34DFD33B1882C5C009628ECF0C Michagogo (michagogo) -C57E4B42223FDE851D4F69DD28DF2724F241D8EE midnightmagic (midnightmagic) -F4FC70F07310028424EFC20A8E4256593F177720 Oliver Gugger (guggero, Oliver Gugger) -D62A803E27E7F43486035ADBBCD04D8E9CCCAC2A Paul Rabahy (prab) -37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04 Peter Todd (petertodd) -D762373D24904A3E42F33B08B9A408E71DAAC974 Pieter Wuille [Location: Leuven, Belgium] (sipa) -133EAC179436F14A5CF1B794860FEB804E669320 Pieter Wuille (sipa) -6A8F9C266528E25AEB1D7731C2371D91CB716EA7 Sebastian Falbesoner (theStack) -A8FC55F3B04BA3146F3492E79303B33A305224CB Sebastian Kung (TheCharlatan) -ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost (sjors) -867345026B6763E8B07EE73AB6737117397F5C4F Stephan Oeste (Emzy) -9EDAFF80E080659604F4A76B2EBB056FD847F8A7 Stephan Oeste (Emzy) -6DEEF79B050C4072509B743F8C275BC595448867 Tomas Kanocz (KanoczTomas) -AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami (wtogami) -74E2DEF5D77260B98BC19438099BAD163C70FBFA Will Clark (will8clark) -79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko (willyko) -71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan (laanwj) diff --git a/contrib/bitcoin-cli.bash-completion b/contrib/completions/bash/bitcoin-cli.bash-completion index ddea58a05c..89e01bc09a 100644 --- a/contrib/bitcoin-cli.bash-completion +++ b/contrib/completions/bash/bitcoin-cli.bash-completion @@ -1,5 +1,5 @@ # bash programmable completion for bitcoin-cli(1) -# Copyright (c) 2012-2019 The Bitcoin Core developers +# Copyright (c) 2012-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/bitcoin-tx.bash-completion b/contrib/completions/bash/bitcoin-tx.bash-completion index a83d2979ed..51a9fe31cb 100644 --- a/contrib/bitcoin-tx.bash-completion +++ b/contrib/completions/bash/bitcoin-tx.bash-completion @@ -1,5 +1,5 @@ # bash programmable completion for bitcoin-tx(1) -# Copyright (c) 2016 The Bitcoin Core developers +# Copyright (c) 2016-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/bitcoind.bash-completion b/contrib/completions/bash/bitcoind.bash-completion index ec1d9512d4..c11d99ef31 100644 --- a/contrib/bitcoind.bash-completion +++ b/contrib/completions/bash/bitcoind.bash-completion @@ -1,5 +1,5 @@ # bash programmable completion for bitcoind(1) and bitcoin-qt(1) -# Copyright (c) 2012-2019 The Bitcoin Core developers +# Copyright (c) 2012-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/completions/fish/bitcoin-cli.fish b/contrib/completions/fish/bitcoin-cli.fish new file mode 100644 index 0000000000..2f034c475c --- /dev/null +++ b/contrib/completions/fish/bitcoin-cli.fish @@ -0,0 +1,99 @@ +# Disable files from being included in completions by default +complete --command bitcoin-cli --no-files + +function __fish_bitcoin_cli_get_commands_helper + set --local cmd (commandline -oc) + + # Don't return commands if '-help or -?' in commandline + if string match --quiet --regex -- '^-help$|^-\?$' $cmd + return + end + + # Strip help cmd from token to avoid duplication errors + set --local cmd (string match --invert --regex -- '^help$' $cmd) + # Strip -stdin* options to avoid waiting for input while we fetch completions + # TODO: this appears to be broken when run as tab completion (requires ctrl+c to exit) + set --local cmd (string match --invert --regex -- '^-stdin.*$' $cmd) + + # Match, format and return commands + for command in ($cmd help 2>&1 | string match --invert -r '^\=\=.*' | string match --invert -r '^\\s*$') + echo $command + end +end + +function __fish_bitcoin_cli_get_commands + argparse 'nohelp' 'commandsonly' -- $argv + set --local commands + + # Exclude description, exclude help + if set -q _flag_nohelp; and set -q _flag_commandsonly + set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace -r ' .*$' '' | string match --invert -r 'help') + # Include description, exclude help + else if set -q _flag_nohelp + set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace ' ' \t | string match --invert -r 'help') + # Exclude description, include help + else if set -q _flag_commandsonly + set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace -r ' .*$' '') + # Include description, include help + else + set --append commands (__fish_bitcoin_cli_get_commands_helper | string replace ' ' \t) + end + + if string match -q -r '^.*error.*$' $commands[1] + # RPC offline or RPC wallet not loaded + return + else + for command in $commands + echo $command + end + end +end + + +function __fish_bitcoin_cli_get_options + argparse 'nofiles' -- $argv + set --local cmd (commandline -oc) + # Don't return options if '-help or -?' in commandline + if string match --quiet --regex -- '^-help$|-\?$' $cmd + return + end + set --local options + + if set -q _flag_nofiles + set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$') + else + set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$') + end + + for option in $options + echo $option + end +end + +# Add options with file completion +# Don't offer after a command is given +complete \ + --command bitcoin-cli \ + --no-files \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_cli_get_commands --commandsonly)" \ + --arguments "(__fish_bitcoin_cli_get_options)" +# Enable file completions only if the commandline now contains a `*.=` style option +complete --command bitcoin-cli \ + --condition 'string match --regex -- ".*=" (commandline -pt)' \ + --force-files + +# Add options without file completion +# Don't offer after a command is given +complete \ + --command bitcoin-cli \ + --no-files \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_cli_get_commands --commandsonly)" \ + --arguments "(__fish_bitcoin_cli_get_options --nofiles)" + +# Add commands +# Permit command completions after `bitcoin-cli help` but not after other commands +complete \ + --command bitcoin-cli \ + --no-files \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_cli_get_commands --commandsonly --nohelp)" \ + --arguments "(__fish_bitcoin_cli_get_commands)" diff --git a/contrib/completions/fish/bitcoin-qt.fish b/contrib/completions/fish/bitcoin-qt.fish new file mode 100644 index 0000000000..15a355ae88 --- /dev/null +++ b/contrib/completions/fish/bitcoin-qt.fish @@ -0,0 +1,35 @@ +# Disable files from being included in completions by default +complete --command bitcoin-qt --no-files + +# Extract options +function __fish_bitcoinqt_get_options + argparse 'nofiles' -- $argv + set --local cmd (commandline -opc)[1] + set --local options + + if set -q _flag_nofiles + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$') + else + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$') + end + + for option in $options + echo $option + end +end + + +# Add options with file completion +complete \ + --command bitcoin-qt \ + --arguments "(__fish_bitcoinqt_get_options)" +# Enable file completions only if the commandline now contains a `*.=` style option +complete -c bitcoin-qt \ + --condition 'string match --regex -- ".*=" (commandline -pt)' \ + --force-files + +# Add options without file completion +complete \ + --command bitcoin-qt \ + --arguments "(__fish_bitcoinqt_get_options --nofiles)" + diff --git a/contrib/completions/fish/bitcoin-tx.fish b/contrib/completions/fish/bitcoin-tx.fish new file mode 100644 index 0000000000..0ff262b948 --- /dev/null +++ b/contrib/completions/fish/bitcoin-tx.fish @@ -0,0 +1,65 @@ +# Disable files from being included in completions by default +complete --command bitcoin-tx --no-files + +# Modified version of __fish_seen_subcommand_from +# Uses regex to detect cmd= syntax +function __fish_bitcoin_seen_cmd + set -l cmd (commandline -oc) + set -e cmd[1] + for i in $cmd + for j in $argv + if string match --quiet --regex -- "^$j.*" $i + return 0 + end + end + end + return 1 +end + +# Extract options +function __fish_bitcoin_tx_get_options + set --local cmd (commandline -oc)[1] + if string match --quiet --regex -- '^-help$|-\?$' $cmd + return + end + + for option in ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=') + echo $option + end +end + +# Extract commands +function __fish_bitcoin_tx_get_commands + argparse 'commandsonly' -- $argv + set --local cmd (commandline -oc)[1] + set --local commands + + if set -q _flag_commandsonly + set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '' | string replace -r '=.*' '') + else + set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '') + end + + for command in $commands + echo $command + end +end + +# Add options +complete \ + --command bitcoin-tx \ + --condition "not __fish_bitcoin_seen_cmd (__fish_bitcoin_tx_get_commands --commandsonly)" \ + --arguments "(__fish_bitcoin_tx_get_options)" \ + --no-files + +# Add commands +complete \ + --command bitcoin-tx \ + --arguments "(__fish_bitcoin_tx_get_commands)" \ + --no-files + +# Add file completions for load and set commands +complete \ + --command bitcoin-tx \ + --condition 'string match --regex -- "(load|set)=" (commandline -pt)' \ + --force-files diff --git a/contrib/completions/fish/bitcoin-util.fish b/contrib/completions/fish/bitcoin-util.fish new file mode 100644 index 0000000000..0650bf2cb6 --- /dev/null +++ b/contrib/completions/fish/bitcoin-util.fish @@ -0,0 +1,38 @@ +# Disable files from being included in completions by default +complete --command bitcoin-util --no-files + +# Extract options +function __fish_bitcoin_util_get_options + set --local cmd (commandline -opc)[1] + set --local options + + set --append options ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=') + + for option in $options + echo $option + end +end + +# Extract commands +function __fish_bitcoin_util_get_commands + set --local cmd (commandline -opc)[1] + set --local commands + + set --append commands ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '') + for command in $commands + echo $command + end +end + +# Add options +complete \ + --command bitcoin-util \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_util_get_commands)" \ + --arguments "(__fish_bitcoin_util_get_options)" + +# Add commands +complete \ + --command bitcoin-util \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_util_get_commands)" \ + --arguments "(__fish_bitcoin_util_get_commands)" + diff --git a/contrib/completions/fish/bitcoin-wallet.fish b/contrib/completions/fish/bitcoin-wallet.fish new file mode 100644 index 0000000000..82d8277c9b --- /dev/null +++ b/contrib/completions/fish/bitcoin-wallet.fish @@ -0,0 +1,35 @@ +# Disable files from being included in completions by default +complete --command bitcoin-wallet --no-files + +# Extract options +function __fish_bitcoin_wallet_get_options + set --local cmd (commandline -opc)[1] + for option in ($cmd -help 2>&1 | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=') + echo $option + end +end + +# Extract commands +function __fish_bitcoin_wallet_get_commands + set --local cmd (commandline -opc)[1] + for command in ($cmd -help | sed -e '1,/Commands:/d' -e 's/=/=\t/' -e 's/(=/=/' -e '/^ [a-z]/ p' -e d | string replace -r '\ \ ' '') + echo $command + end +end + +# Add options +complete \ + --command bitcoin-wallet \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_wallet_get_commands)" \ + --arguments "(__fish_bitcoin_wallet_get_options)" + +# Add commands +complete \ + --command bitcoin-wallet \ + --condition "not __fish_seen_subcommand_from (__fish_bitcoin_wallet_get_commands)" \ + --arguments "(__fish_bitcoin_wallet_get_commands)" + +# Add file completions for load and set commands +complete --command bitcoin-wallet \ + --condition "string match -r -- '(dumpfile|datadir)*=' (commandline -pt)" \ + --force-files diff --git a/contrib/completions/fish/bitcoind.fish b/contrib/completions/fish/bitcoind.fish new file mode 100644 index 0000000000..fa245ae17f --- /dev/null +++ b/contrib/completions/fish/bitcoind.fish @@ -0,0 +1,35 @@ +# Disable files from being included in completions by default +complete --command bitcoind --no-files + +# Extract options +function __fish_bitcoind_get_options + argparse 'nofiles' -- $argv + set --local cmd (commandline -opc)[1] + set --local options + + if set -q _flag_nofiles + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match --invert -r '^.*=$') + else + set --append options ($cmd -help-debug | string match -r '^ -.*' | string replace -r ' -' '-' | string replace -r '=.*' '=' | string match -r '^.*=$') + end + + for option in $options + echo $option + end +end + + +# Add options with file completion +complete \ + --command bitcoind \ + --arguments "(__fish_bitcoind_get_options)" +# Enable file completions only if the commandline now contains a `*.=` style option +complete --command bitcoind \ + --condition 'string match --regex -- ".*=" (commandline -pt)' \ + --force-files + +# Add options without file completion +complete \ + --command bitcoind \ + --arguments "(__fish_bitcoind_get_options --nofiles)" + diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 95a281ce05..ca430170a1 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -5,24 +5,16 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com> Source: https://github.com/bitcoin/bitcoin Files: * -Copyright: 2009-2022, Bitcoin Core Developers +Copyright: 2009-2023, Bitcoin Core Developers License: Expat -Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org, - as well as the numerous contributors to the project. +Comment: The Bitcoin Core Developers encompasses all contributors to the + project, listed in the release notes or the git log. Files: debian/* Copyright: 2010-2011, Jonas Smedegaard <dr@jones.dk> 2011, Matt Corallo <matt@bluematt.me> License: GPL-2+ -Files: src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 -Copyright: 2008 Don Anderson <dda@sleepycat.com> -License: GNU-All-permissive-License - -Files: src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 -Copyright: 2008 Paolo Bonzini <bonzini@gnu.org> -License: GNU-All-permissive-License - Files: src/qt/res/icons/add.png src/qt/res/icons/address-book.png src/qt/res/icons/chevron.png @@ -112,12 +104,6 @@ License: Expat TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -License: GNU-All-permissive-License - Copying and distribution of this file, with or without modification, are - permitted in any medium without royalty provided the copyright notice - and this notice are preserved. This file is offered as-is, without any - warranty. - License: GPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py index 98eee67f43..420bf7ff33 100755 --- a/contrib/devtools/clang-format-diff.py +++ b/contrib/devtools/clang-format-diff.py @@ -146,7 +146,7 @@ def main(): stdout=subprocess.PIPE, stderr=None, stdin=subprocess.PIPE, - universal_newlines=True) + text=True) stdout, stderr = p.communicate() if p.returncode != 0: sys.exit(p.returncode) diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index 680de1f1b3..3dddffe324 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/devtools/gen-manpages.py b/contrib/devtools/gen-manpages.py index 38cdb3acb8..2860e7db99 100755 --- a/contrib/devtools/gen-manpages.py +++ b/contrib/devtools/gen-manpages.py @@ -23,7 +23,7 @@ help2man = os.getenv('HELP2MAN', 'help2man') # If not otherwise specified, get top directory from git. topdir = os.getenv('TOPDIR') if not topdir: - r = subprocess.run([git, 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, check=True, universal_newlines=True) + r = subprocess.run([git, 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, check=True, text=True) topdir = r.stdout.rstrip() # Get input and output directories. @@ -36,7 +36,7 @@ versions = [] for relpath in BINARIES: abspath = os.path.join(builddir, relpath) try: - r = subprocess.run([abspath, "--version"], stdout=subprocess.PIPE, check=True, universal_newlines=True) + r = subprocess.run([abspath, "--version"], stdout=subprocess.PIPE, check=True, text=True) except IOError: print(f'{abspath} not found or not an executable', file=sys.stderr) sys.exit(1) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 05c0af029e..8377b92736 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' @@ -146,6 +146,12 @@ def check_PE_control_flow(binary) -> bool: return True return False +def check_PE_Canary(binary) -> bool: + ''' + Check for use of stack canary + ''' + return binary.has_symbol('__stack_chk_fail') + def check_MACHO_NOUNDEFS(binary) -> bool: ''' Check for no undefined references. @@ -203,6 +209,7 @@ BASE_PE = [ ('NX', check_NX), ('RELOC_SECTION', check_PE_RELOC_SECTION), ('CONTROL_FLOW', check_PE_control_flow), + ('Canary', check_PE_Canary), ] BASE_MACHO = [ diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index d3d225f3ab..54718fd7a1 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' @@ -39,7 +39,7 @@ def call_security_check(cc, source, executable, options): env_flags += filter(None, os.environ.get(var, '').split(' ')) subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True) - p = subprocess.run(['./contrib/devtools/security-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True) + p = subprocess.run([os.path.join(os.path.dirname(__file__), 'security-check.py'), executable], stdout=subprocess.PIPE, text=True) return (p.returncode, p.stdout.rstrip()) def get_arch(cc, source, executable): @@ -94,19 +94,19 @@ class TestSecurityChecks(unittest.TestCase): cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc') write_testcode(source) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--disable-nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE']), - (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE']), + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--disable-nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fno-stack-protector']), + (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW Canary')) + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']), (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE']), + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-no-pie','-fno-PIE','-fstack-protector-all', '-lssp']), (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE']), + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--disable-dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']), (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) # -pie -fPIE does nothing unless --dynamicbase is also supplied - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE']), + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--disable-high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']), (1, executable+': failed HIGH_ENTROPY_VA CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE']), + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE','-fstack-protector-all', '-lssp']), (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full']), + self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full','-fstack-protector-all', '-lssp']), (0, '')) clean_files(source, executable) diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py index 2881e3efac..de73b02090 100755 --- a/contrib/devtools/test-symbol-check.py +++ b/contrib/devtools/test-symbol-check.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' @@ -23,13 +23,13 @@ def call_symbol_check(cc: List[str], source, executable, options): env_flags += filter(None, os.environ.get(var, '').split(' ')) subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True) - p = subprocess.run(['./contrib/devtools/symbol-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True) + p = subprocess.run([os.path.join(os.path.dirname(__file__), 'symbol-check.py'), executable], stdout=subprocess.PIPE, text=True) os.remove(source) os.remove(executable) return (p.returncode, p.stdout.rstrip()) def get_machine(cc: List[str]): - p = subprocess.run([*cc,'-dumpmachine'], stdout=subprocess.PIPE, universal_newlines=True) + p = subprocess.run([*cc,'-dumpmachine'], stdout=subprocess.PIPE, text=True) return p.stdout.rstrip() class TestSymbolChecks(unittest.TestCase): diff --git a/contrib/guix/INSTALL.md b/contrib/guix/INSTALL.md index a9a41ddff6..bbd88e58f3 100644 --- a/contrib/guix/INSTALL.md +++ b/contrib/guix/INSTALL.md @@ -167,6 +167,10 @@ For reference, the graphic below outlines Guix v1.3.0's dependency graph: ![bootstrap map](https://user-images.githubusercontent.com/6399679/125064185-a9a59880-e0b0-11eb-82c1-9b8e5dc9950d.png) +#### Consider /tmp on tmpfs + +If you use an NVME (SSD) drive, you may encounter [cryptic build errors](#coreutils-fail-teststail-2inotify-dir-recreate). Mounting a [tmpfs at /tmp](https://ubuntu.com/blog/data-driven-analysis-tmp-on-tmpfs) should prevent this and may improve performance as a bonus. + #### Guile ##### Choosing a Guile version and sticking to it @@ -334,6 +338,8 @@ packages in Debian at the time of writing. |-----------------------|---------------------| | guile-gcrypt | libgcrypt-dev | | guile-git | libgit2-dev | +| guile-gnutls | (none) | +| guile-json | (none) | | guile-lzlib | liblz-dev | | guile-ssh | libssh-dev | | guile-sqlite3 | libsqlite3-dev | @@ -384,8 +390,9 @@ cd guix ``` You will likely want to build the latest release, however, if the latest release -when you're reading this is still 1.2.0 then you may want to use 95aca29 instead -to avoid a problem in the GnuTLS test suite. +when you're reading this is still 1.3.0 then you may want to use 998eda30 instead +to avoid the issues described in [#25099]( +https://github.com/bitcoin/bitcoin/pull/25099). ``` git branch -a -l 'origin/version-*' # check for the latest release @@ -609,6 +616,8 @@ systemctl enable guix-daemon systemctl start guix-daemon ``` +Remember to set `--no-substitute` in `$libdir/systemd/system/guix-daemon.service` and other customizations if you used them for `guix-daemon-original.service`. + ##### If you installed Guix via the Debian/Ubuntu distribution packages You will need to create a `guix-daemon-latest` service which points to the new @@ -717,6 +726,19 @@ $ bzcat /var/log/guix/drvs/../...-foo-3.6.12.drv.bz2 | less times, it may be `/tmp/...drv-1` or `/tmp/...drv-2`. Always consult the build failure output for the most accurate, up-to-date information. +### openssl-1.1.1l and openssl-1.1.1n + +OpenSSL includes tests that will fail once some certificate has expired. A workaround +is to change your system clock: + +```sh +sudo timedatectl set-ntp no +sudo date --set "28 may 2022 15:00:00" +sudo --login guix build --cores=1 /gnu/store/g9alz81w4q03ncm542487xd001s6akd4-openssl-1.1.1l.drv +sudo --login guix build --cores=1 /gnu/store/mw6ax0gk33gh082anrdrxp2flrbskxv6-openssl-1.1.1n.drv +sudo timedatectl set-ntp yes +``` + ### python(-minimal): [Errno 84] Invalid or incomplete multibyte or wide character This error occurs when your `$TMPDIR` (default: /tmp) exists on a filesystem @@ -774,7 +796,7 @@ The inotify-dir-create test fails on "remote" filesystems such as overlayfs as non-remote. A relatively easy workaround to this is to make sure that a somewhat traditional -filesystem is mounted at `/tmp` (where `guix-daemon` performs its builds). For +filesystem is mounted at `/tmp` (where `guix-daemon` performs its builds), see [/tmp on tmpfs](#consider-tmp-on-tmpfs). For Docker users, this might mean [using a volume][docker/volumes], [binding mounting][docker/bind-mnt] from host, or (for those with enough RAM and swap) [mounting a tmpfs][docker/tmpfs] using the `--tmpfs` flag. @@ -782,7 +804,7 @@ mounting][docker/bind-mnt] from host, or (for those with enough RAM and swap) Please see the following links for more details: - An upstream coreutils bug has been filed: [debbugs#47940](https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47940) -- A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935) +- A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935), [guix-issues#49985](https://issues.guix.gnu.org/49985#5) - A commit to skip this test in Guix has been merged into the core-updates branch: [savannah/guix@6ba1058](https://git.savannah.gnu.org/cgit/guix.git/commit/?id=6ba1058df0c4ce5611c2367531ae5c3cdc729ab4) @@ -799,3 +821,39 @@ Please see the following links for more details: [docker/volumes]: https://docs.docker.com/storage/volumes/ [docker/bind-mnt]: https://docs.docker.com/storage/bind-mounts/ [docker/tmpfs]: https://docs.docker.com/storage/tmpfs/ + +# Purging/Uninstalling Guix + +In the extraordinarily rare case where you messed up your Guix installation in +an irreversible way, you may want to completely purge Guix from your system and +start over. + +1. Uninstall Guix itself according to the way you installed it (e.g. `sudo apt + purge guix` for Ubuntu packaging, `sudo make uninstall` for a build from source). +2. Remove all build users and groups + + You may check for relevant users and groups using: + + ``` + getent passwd | grep guix + getent group | grep guix + ``` + + Then, you may remove users and groups using: + + ``` + sudo userdel <user> + sudo groupdel <group> + ``` + +3. Remove all possible Guix-related directories + - `/var/guix/` + - `/var/log/guix/` + - `/gnu/` + - `/etc/guix/` + - `/home/*/.config/guix/` + - `/home/*/.cache/guix/` + - `/home/*/.guix-profile/` + - `/root/.config/guix/` + - `/root/.cache/guix/` + - `/root/.guix-profile/` diff --git a/contrib/guix/README.md b/contrib/guix/README.md index ed6ac8d589..c0feb486ff 100644 --- a/contrib/guix/README.md +++ b/contrib/guix/README.md @@ -430,55 +430,6 @@ used. If you start `guix-daemon` using an init script, you can edit said script to supply this flag. - -# Purging/Uninstalling Guix - -In the extraordinarily rare case where you messed up your Guix installation in -an irreversible way, you may want to completely purge Guix from your system and -start over. - -1. Uninstall Guix itself according to the way you installed it (e.g. `sudo apt - purge guix` for Ubuntu packaging, `sudo make uninstall` for a build from source). -2. Remove all build users and groups - - You may check for relevant users and groups using: - - ``` - getent passwd | grep guix - getent group | grep guix - ``` - - Then, you may remove users and groups using: - - ``` - sudo userdel <user> - sudo groupdel <group> - ``` - -3. Remove all possible Guix-related directories - - `/var/guix/` - - `/var/log/guix/` - - `/gnu/` - - `/etc/guix/` - - `/home/*/.config/guix/` - - `/home/*/.cache/guix/` - - `/home/*/.guix-profile/` - - `/root/.config/guix/` - - `/root/.cache/guix/` - - `/root/.guix-profile/` - [b17e]: https://bootstrappable.org/ [r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/ - -[guix/install.sh]: https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh -[guix/bin-install]: https://www.gnu.org/software/guix/manual/en/html_node/Binary-Installation.html -[guix/env-setup]: https://www.gnu.org/software/guix/manual/en/html_node/Build-Environment-Setup.html -[guix/substitutes]: https://www.gnu.org/software/guix/manual/en/html_node/Substitutes.html -[guix/substitute-server-auth]: https://www.gnu.org/software/guix/manual/en/html_node/Substitute-Server-Authorization.html -[guix/time-machine]: https://guix.gnu.org/manual/en/html_node/Invoking-guix-time_002dmachine.html - -[debian/guix-bullseye]: https://packages.debian.org/bullseye/guix -[ubuntu/guix-hirsute]: https://packages.ubuntu.com/hirsute/guix -[fanquake/guix-docker]: https://github.com/fanquake/core-review/tree/master/guix - [env-vars-list]: #recognized-environment-variables diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index f39f83d443..f2be3677eb 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 @@ -69,16 +69,12 @@ unset CPLUS_INCLUDE_PATH unset OBJC_INCLUDE_PATH unset OBJCPLUS_INCLUDE_PATH -export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64:${NATIVE_GCC_STATIC}/lib:${NATIVE_GCC_STATIC}/lib64" +export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC_STATIC}/lib" export C_INCLUDE_PATH="${NATIVE_GCC}/include" export CPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include" export OBJC_INCLUDE_PATH="${NATIVE_GCC}/include" export OBJCPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include" -prepend_to_search_env_var() { - export "${1}=${2}${!1:+:}${!1}" -} - # Set environment variables to point the CROSS toolchain to the right # includes/libs for $HOST case "$HOST" in diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh index 9a5d3a1ce5..f6322d761c 100755 --- a/contrib/guix/libexec/codesign.sh +++ b/contrib/guix/libexec/codesign.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh index 2850c4b993..c7d39f5b99 100755 --- a/contrib/install_db4.sh +++ b/contrib/install_db4.sh @@ -32,16 +32,15 @@ check_exists() { sha256_check() { # Args: <sha256_hash> <filename> # - if check_exists sha256sum; then - echo "${1} ${2}" | sha256sum -c + if [ "$(uname)" = "FreeBSD" ]; then + # sha256sum exists on FreeBSD, but takes different arguments than the GNU version + sha256 -c "${1}" "${2}" + elif check_exists sha256sum; then + echo "${1} ${2}" | sha256sum -c elif check_exists sha256; then - if [ "$(uname)" = "FreeBSD" ]; then - sha256 -c "${1}" "${2}" - else - echo "${1} ${2}" | sha256 -c - fi + echo "${1} ${2}" | sha256 -c else - echo "${1} ${2}" | shasum -a 256 -c + echo "${1} ${2}" | shasum -a 256 -c fi } diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index b72c7b0d08..24f6b29a26 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -2,7 +2,7 @@ # # linearize-data.py: Construct a linear, no-fork version of the chain. # -# Copyright (c) 2013-2021 The Bitcoin Core developers +# Copyright (c) 2013-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py index 5959300e74..695bafad34 100755 --- a/contrib/linearize/linearize-hashes.py +++ b/contrib/linearize/linearize-hashes.py @@ -2,7 +2,7 @@ # # linearize-hashes.py: List blocks in a linear, no-fork version of the chain. # -# Copyright (c) 2013-2019 The Bitcoin Core developers +# Copyright (c) 2013-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -78,7 +78,7 @@ def get_block_hashes(settings, max_blocks_per_call=10000): if rpc.response_is_error(resp_obj): print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr) sys.exit(1) - assert(resp_obj['id'] == x) # assume replies are in-sequence + assert resp_obj['id'] == x # assume replies are in-sequence if settings['rev_hash_bytes'] == 'true': resp_obj['result'] = bytes.fromhex(resp_obj['result'])[::-1].hex() print(resp_obj['result']) diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index f393331084..626381cf43 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 2420539b7c..f8677ba7b8 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -187,7 +187,7 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]: if verbose: print(f"Inspecting with otool: {binaryPath}") otoolbin=os.getenv("OTOOL", "otool") - otool = run([otoolbin, "-L", binaryPath], stdout=PIPE, stderr=PIPE, universal_newlines=True) + otool = run([otoolbin, "-L", binaryPath], stdout=PIPE, stderr=PIPE, text=True) if otool.returncode != 0: sys.stderr.write(otool.stderr) sys.stderr.flush() @@ -577,17 +577,17 @@ if config.dmg is not None: tempname: str = appname + ".temp.dmg" - run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, universal_newlines=True) + run(["hdiutil", "create", tempname, "-srcfolder", "dist", "-format", "UDRW", "-size", str(size), "-volname", appname], check=True, text=True) if verbose: print("Attaching temp image...") - output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, universal_newlines=True, stdout=PIPE).stdout + output = run(["hdiutil", "attach", tempname, "-readwrite"], check=True, text=True, stdout=PIPE).stdout print("+ Finalizing .dmg disk image +") - run(["hdiutil", "detach", f"/Volumes/{appname}"], universal_newlines=True) + run(["hdiutil", "detach", f"/Volumes/{appname}"], text=True) - run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, universal_newlines=True) + run(["hdiutil", "convert", tempname, "-format", "UDZO", "-o", appname, "-imagekey", "zlib-level=9"], check=True, text=True) os.unlink(tempname) diff --git a/contrib/message-capture/message-capture-parser.py b/contrib/message-capture/message-capture-parser.py index 33759ee713..d6ddc1c149 100755 --- a/contrib/message-capture/message-capture-parser.py +++ b/contrib/message-capture/message-capture-parser.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Parse message capture binary files. To be used in conjunction with -capturemessages.""" diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 44345e3987..a6f435af0d 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -70,13 +70,13 @@ def name_to_bip155(addr): if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end continue x += 1 # :: skips to suffix - assert(x < 2) + assert x < 2 else: # two bytes per component val = int(comp, 16) sub[x].append(val >> 8) sub[x].append(val & 0xff) nullbytes = 16 - len(sub[0]) - len(sub[1]) - assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) + assert (x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0) addr_bytes = bytes(sub[0] + ([0] * nullbytes) + sub[1]) if addr_bytes[0] == 0xfc: # Assume that seeds with fc00::/8 addresses belong to CJDNS, diff --git a/contrib/signet/getcoins.py b/contrib/signet/getcoins.py index a069f5fad3..d4e436626f 100755 --- a/contrib/signet/getcoins.py +++ b/contrib/signet/getcoins.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -129,7 +129,7 @@ if args.captcha != '': # Retrieve a captcha # Convert SVG image to PPM, and load it try: - rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + rv = subprocess.run([args.imagemagick, 'svg:-', '-depth', '8', 'ppm:-'], input=res.content, check=True, capture_output=True) except FileNotFoundError: raise SystemExit(f"The binary {args.imagemagick} could not be found. Please make sure ImageMagick (or a compatible fork) is installed and that the correct path is specified.") diff --git a/contrib/tracing/log_utxocache_flush.py b/contrib/tracing/log_utxocache_flush.py index 8c073bea0d..6c568998e9 100755 --- a/contrib/tracing/log_utxocache_flush.py +++ b/contrib/tracing/log_utxocache_flush.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py index 2ff14c1f86..3825caf5de 100755 --- a/contrib/verify-commits/verify-commits.py +++ b/contrib/verify-commits/verify-commits.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2019 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Verify commits against a trusted keys list.""" diff --git a/depends/Makefile b/depends/Makefile index 11fdd6dd53..27bf804c6b 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -32,6 +32,8 @@ SOURCES_PATH ?= $(BASEDIR)/sources WORK_PATH = $(BASEDIR)/work BASE_CACHE ?= $(BASEDIR)/built SDK_PATH ?= $(BASEDIR)/SDKs +NO_BOOST ?= +NO_LIBEVENT ?= NO_QT ?= NO_QR ?= NO_BDB ?= @@ -147,6 +149,10 @@ include packages/packages.mk build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))') $(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(host_AR)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))') +boost_packages_$(NO_BOOST) = $(boost_packages) + +libevent_packages_$(NO_LIBEVENT) = $(libevent_packages) + qrencode_packages_$(NO_QR) = $(qrencode_$(host_os)_packages) qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) $(qrencode_packages_) @@ -162,7 +168,7 @@ zmq_packages_$(NO_ZMQ) = $(zmq_packages) multiprocess_packages_$(MULTIPROCESS) = $(multiprocess_packages) usdt_packages_$(NO_USDT) = $(usdt_$(host_os)_packages) -packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_) $(usdt_packages_) +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(boost_packages_) $(libevent_packages_) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_) $(usdt_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) ifneq ($(zmq_packages_),) diff --git a/depends/README.md b/depends/README.md index 66e1ddc4eb..a8831eb0fc 100644 --- a/depends/README.md +++ b/depends/README.md @@ -62,7 +62,7 @@ For more information, see [SDK Extraction](../contrib/macdeploy/README.md#sdk-ex Common linux dependencies: - sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch bison + sudo apt-get install make automake cmake curl g++-multilib libtool binutils bsdmainutils pkg-config python3 patch bison For linux ARM cross compilation: diff --git a/depends/funcs.mk b/depends/funcs.mk index a00f380236..2b21d053b1 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -87,9 +87,9 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) $(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) $(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_TAR) --no-same-owner --strip-components=1 -xf $$($(1)_source) $(1)_preprocess_cmds ?= true -$(1)_build_cmds ?= -$(1)_config_cmds ?= -$(1)_stage_cmds ?= +$(1)_build_cmds ?= true +$(1)_config_cmds ?= true +$(1)_stage_cmds ?= true $(1)_set_vars ?= @@ -137,6 +137,7 @@ $(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$( $(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig +$(1)_config_env+=PKG_CONFIG_SYSROOT_DIR=/ $(1)_config_env+=CMAKE_MODULE_PATH=$($($(1)_type)_prefix)/lib/cmake $(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH) $(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH) @@ -214,17 +215,17 @@ $($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed) echo Configuring $(1)... rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), $(build_TAR) --no-same-owner -xf $($(package)_cached); ) mkdir -p $$(@D) - +{ cd $$(@D); $($(1)_config_env) $($(1)_config_cmds); } $$($(1)_logging) + +{ cd $$(@D); export $($(1)_config_env); $($(1)_config_cmds); } $$($(1)_logging) touch $$@ $($(1)_built): | $($(1)_configured) echo Building $(1)... mkdir -p $$(@D) - +{ cd $$(@D); $($(1)_build_env) $($(1)_build_cmds); } $$($(1)_logging) + +{ cd $$(@D); export $($(1)_build_env); $($(1)_build_cmds); } $$($(1)_logging) touch $$@ $($(1)_staged): | $($(1)_built) echo Staging $(1)... mkdir -p $($(1)_staging_dir)/$(host_prefix) - +{ cd $($(1)_build_dir); $($(1)_stage_env) $($(1)_stage_cmds); } $$($(1)_logging) + +{ cd $($(1)_build_dir); export $($(1)_stage_env); $($(1)_stage_cmds); } $$($(1)_logging) rm -rf $($(1)_extract_dir) touch $$@ $($(1)_postprocessed): | $($(1)_staged) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 2370c5b759..262587690c 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -15,6 +15,9 @@ $(package)_config_opts_netbsd=--with-pic $(package)_config_opts_openbsd=--with-pic $(package)_config_opts_android=--with-pic $(package)_cflags+=-Wno-error=implicit-function-declaration -Wno-error=format-security +$(package)_cppflags_freebsd=-D_XOPEN_SOURCE=600 +$(package)_cppflags_netbsd=-D_XOPEN_SOURCE=600 +$(package)_cppflags_openbsd=-D_XOPEN_SOURCE=600 $(package)_cppflags_mingw32=-DUNICODE -D_UNICODE endef diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index e3625d97f5..ebc097d686 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1.80.0 +$(package)_version=1.81.0 $(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/ $(package)_file_name=boost_$(subst .,_,$($(package)_version)).tar.bz2 -$(package)_sha256_hash=1e19565d82e43bc59209a168f5ac899d3ba471d55c7610c677d4ccf2c9c500c0 +$(package)_sha256_hash=71feeed900fbccca04a3b4f2f84a7c217186f28a940ed8b7ed4725986baf99fa define $(package)_stage_cmds mkdir -p $($(package)_staging_prefix_dir)/include && \ diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk index 9b66207fc5..6da5693b3f 100644 --- a/depends/packages/libmultiprocess.mk +++ b/depends/packages/libmultiprocess.mk @@ -24,5 +24,5 @@ define $(package)_build_cmds endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install + $(MAKE) DESTDIR=$($(package)_staging_dir) install-lib endef diff --git a/depends/packages/native_libmultiprocess.mk b/depends/packages/native_libmultiprocess.mk index 6e600c5720..e647afba5f 100644 --- a/depends/packages/native_libmultiprocess.mk +++ b/depends/packages/native_libmultiprocess.mk @@ -1,8 +1,8 @@ package=native_libmultiprocess -$(package)_version=d576d975debdc9090bd2582f83f49c76c0061698 +$(package)_version=1af83d15239ccfa7e47b8764029320953dd7fdf1 $(package)_download_path=https://github.com/chaincodelabs/libmultiprocess/archive $(package)_file_name=$($(package)_version).tar.gz -$(package)_sha256_hash=9f8b055c8bba755dc32fe799b67c20b91e7b13e67cadafbc54c0f1def057a370 +$(package)_sha256_hash=e5587d3feedc7f8473f178a89b94163a11076629825d664964799bbbd5844da5 $(package)_dependencies=native_capnp define $(package)_config_cmds @@ -14,5 +14,5 @@ define $(package)_build_cmds endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install + $(MAKE) DESTDIR=$($(package)_staging_dir) install-bin endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 998cc0221c..b3600b72d0 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,4 +1,8 @@ -packages:=boost libevent +packages:= + +boost_packages = boost + +libevent_packages = libevent qrencode_linux_packages = qrencode qrencode_android_packages = qrencode diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index d9ae918d71..2f7ddf6a5f 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -33,6 +33,7 @@ $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) define $(package)_set_vars +$(package)_config_env = QT_MAC_SDK_NO_VERSION_CHECK=1 $(package)_config_opts_release = -release $(package)_config_opts_release += -silent $(package)_config_opts_debug = -debug @@ -261,9 +262,6 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds - export PKG_CONFIG_SYSROOT_DIR=/ && \ - export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ - export QT_MAC_SDK_NO_VERSION_CHECK=1 && \ cd qtbase && \ ./configure -top-level $($(package)_config_opts) endef diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md index 12807bfb86..ab5db58cdd 100644 --- a/doc/JSON-RPC-interface.md +++ b/doc/JSON-RPC-interface.md @@ -5,6 +5,28 @@ The headless daemon `bitcoind` has the JSON-RPC API enabled by default, the GUI option. In the GUI it is possible to execute RPC methods in the Debug Console Dialog. +## Parameter passing + +The JSON-RPC server supports both _by-position_ and _by-name_ [parameter +structures](https://www.jsonrpc.org/specification#parameter_structures) +described in the JSON-RPC specification. For extra convenience, to avoid the +need to name every parameter value, all RPC methods accept a named parameter +called `args`, which can be set to an array of initial positional values that +are combined with named values. + +Examples: + +```sh +# "params": ["mywallet", false, false, "", false, false, true] +bitcoin-cli createwallet mywallet false false "" false false true + +# "params": {"wallet_name": "mywallet", "load_on_startup": true} +bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=true + +# "params": {"args": ["mywallet"], "load_on_startup": true} +bitcoin-cli -named createwallet mywallet load_on_startup=true +``` + ## Versioning The RPC interface might change from one major version of Bitcoin Core to the diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index a8e643a2ab..d45e9c4d0d 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -72,7 +72,7 @@ There is an included test suite that is useful for testing code changes when dev To run the test suite (recommended), you will need to have Python 3 installed: ```bash -pkg install python3 +pkg install python3 databases/py-sqlite3 ``` --- diff --git a/doc/build-windows.md b/doc/build-windows.md index e35d3bcbd0..027e8f80f5 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -6,8 +6,8 @@ Below are some notes on how to build Bitcoin Core for Windows. The options known to work for building Bitcoin Core on Windows are: * On Linux, using the [Mingw-w64](https://www.mingw-w64.org/) cross compiler tool chain. -* On Windows, using [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/windows/wsl/about) and Mingw-w64. -* On Windows, using [Microsoft Visual Studio](https://www.visualstudio.com). See [README.md](/build_msvc/README.md). +* On Windows, using [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/about) and Mingw-w64. +* On Windows, using [Microsoft Visual Studio](https://visualstudio.microsoft.com). See [README.md](/build_msvc/README.md). Other options which may work, but which have not been extensively tested are (please contribute instructions): @@ -16,7 +16,7 @@ Other options which may work, but which have not been extensively tested are (pl Installing Windows Subsystem for Linux --------------------------------------- -Follow the upstream installation instructions, available [here](https://docs.microsoft.com/windows/wsl/install-win10). +Follow the upstream installation instructions, available [here](https://learn.microsoft.com/en-us/windows/wsl/install). Cross-compilation for Ubuntu and Windows Subsystem for Linux ------------------------------------------------------------ @@ -66,7 +66,7 @@ Note that for WSL the Bitcoin Core source path MUST be somewhere in the default example /usr/src/bitcoin, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. This means you cannot use a directory that is located directly on the host Windows file system to perform the build. -Additional WSL Note: WSL support for [launching Win32 applications](https://docs.microsoft.com/en-us/archive/blogs/wsl/windows-and-ubuntu-interoperability#launching-win32-applications-from-within-wsl) +Additional WSL Note: WSL support for [launching Win32 applications](https://learn.microsoft.com/en-us/archive/blogs/wsl/windows-and-ubuntu-interoperability#launching-win32-applications-from-within-wsl) results in `Autoconf` configure scripts being able to execute Windows Portable Executable files. This can cause unexpected behaviour during the build, such as Win32 error dialogs for missing libraries. The recommended approach is to temporarily disable WSL support for Win32 applications. diff --git a/doc/dependencies.md b/doc/dependencies.md index ef8faff06c..3349c81c46 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -10,14 +10,14 @@ You can find installation instructions in the `build-*.md` file for your platfor | [Automake](https://www.gnu.org/software/automake/) | [1.13](https://github.com/bitcoin/bitcoin/pull/18290) | | [Clang](https://clang.llvm.org) | [8.0](https://github.com/bitcoin/bitcoin/pull/24164) | | [GCC](https://gcc.gnu.org) | [8.1](https://github.com/bitcoin/bitcoin/pull/23060) | -| [Python](https://www.python.org) (tests) | [3.6](https://github.com/bitcoin/bitcoin/pull/19504) | +| [Python](https://www.python.org) (tests) | [3.7](https://github.com/bitcoin/bitcoin/pull/26226) | | [systemtap](https://sourceware.org/systemtap/) ([tracing](tracing.md))| N/A | ## Required | Dependency | Releases | Version used | Minimum required | Runtime | | --- | --- | --- | --- | --- | -| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.80.0](https://github.com/bitcoin/bitcoin/pull/25873) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No | +| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.81.0](https://github.com/bitcoin/bitcoin/pull/26557) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No | | [libevent](../depends/packages/libevent.mk) | [link](https://github.com/libevent/libevent/releases) | [2.1.12-stable](https://github.com/bitcoin/bitcoin/pull/21991) | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No | | glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.18](https://github.com/bitcoin/bitcoin/pull/23511) | Yes | | Linux Kernel | [link](https://www.kernel.org/) | N/A | 3.2.0 | Yes | diff --git a/doc/fuzzing.md b/doc/fuzzing.md index 9abfbc9213..b498f2f41b 100644 --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -283,8 +283,8 @@ $ sudo apt-get install libtool libtool-bin wget automake autoconf bison gdb ``` At this point, you must install the .NET core. The process differs, depending on your Linux distribution. -See [this link](https://docs.microsoft.com/en-us/dotnet/core/install/linux) for details. -On ubuntu 20.04, the following should work: +See [this link](https://learn.microsoft.com/en-us/dotnet/core/install/linux) for details. +On Ubuntu 20.04, the following should work: ```sh $ wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb diff --git a/doc/i2p.md b/doc/i2p.md index 1599c2fe0f..0432136554 100644 --- a/doc/i2p.md +++ b/doc/i2p.md @@ -16,8 +16,7 @@ enabled is required. Options include: Java - [i2pd (I2P Daemon)](https://github.com/PurpleI2P/i2pd) ([documentation](https://i2pd.readthedocs.io/en/latest)), a lighter - alternative in C++ (successfully tested with version 2.23 and up; version 2.36 - or later recommended) + alternative in C++ - [i2p-zero](https://github.com/i2p-zero/i2p-zero) - [other alternatives](https://en.wikipedia.org/wiki/I2P#Routers) @@ -33,12 +32,10 @@ Core configuration options: none) -i2pacceptincoming - If set and -i2psam is also set then incoming I2P connections are - accepted via the SAM proxy. If this is not set but -i2psam is set - then only outgoing connections will be made to the I2P network. - Ignored if -i2psam is not set. Listening for incoming I2P - connections is done through the SAM proxy, not by binding to a - local address and port (default: 1) + Whether to accept inbound I2P connections (default: 1). Ignored if + -i2psam is not set. Listening for inbound I2P connections is + done through the SAM proxy, not by binding to a local address and + port. ``` In a typical situation, this suffices: @@ -47,27 +44,6 @@ In a typical situation, this suffices: bitcoind -i2psam=127.0.0.1:7656 ``` -The first time Bitcoin Core connects to the I2P router, if -`-i2pacceptincoming=1`, then it will automatically generate a persistent I2P -address and its corresponding private key. The private key will be saved in a -file named `i2p_private_key` in the Bitcoin Core data directory. The persistent -I2P address is used for accepting incoming connections and for making outgoing -connections if `-i2pacceptincoming=1`. If `-i2pacceptincoming=0` then only -outbound I2P connections are made and a different transient I2P address is used -for each connection to improve privacy. - -## Persistent vs transient I2P addresses - -In I2P connections, the connection receiver sees the I2P address of the -connection initiator. This is unlike the Tor network where the recipient does -not know who is connecting to them and can't tell if two connections are from -the same peer or not. - -If an I2P node is not accepting incoming connections, then Bitcoin Core uses -random, one-time, transient I2P addresses for itself for outbound connections -to make it harder to discriminate, fingerprint or analyze it based on its I2P -address. - ## Additional configuration options related to I2P ``` @@ -100,7 +76,29 @@ In general, a node can be run with both onion and I2P hidden services (or any/all of IPv4/IPv6/onion/I2P/CJDNS), which can provide a potential fallback if one of the networks has issues. -## I2P-related information in Bitcoin Core +## Persistent vs transient I2P addresses + +The first time Bitcoin Core connects to the I2P router, it automatically +generates a persistent I2P address and its corresponding private key by default +or if `-i2pacceptincoming=1` is set. The private key is saved in a file named +`i2p_private_key` in the Bitcoin Core data directory. The persistent I2P +address is used for making outbound connections and accepting inbound +connections. + +In the I2P network, the receiver of an inbound connection sees the address of +the initiator. This is unlike the Tor network, where the recipient does not +know who is connecting to it. + +If your node is configured by setting `-i2pacceptincoming=0` to not accept +inbound I2P connections, then it will use a random transient I2P address for +itself on each outbound connection to make it harder to discriminate, +fingerprint or analyze it based on its I2P address. + +I2P addresses are designed to be long-lived. Waiting for tunnels to be built +for every peer connection adds delay to connection setup time. Therefore, I2P +listening should only be turned off if really needed. + +## Fetching I2P-related information from Bitcoin Core There are several ways to see your I2P address in Bitcoin Core if accepting incoming I2P connections (`-i2pacceptincoming`): @@ -133,3 +131,40 @@ listening port to 0 when listening for incoming I2P connections and advertises its own I2P address with port 0. Furthermore, it will not attempt to connect to I2P addresses with a non-zero port number because with SAM v3.1 the destination port (`TO_PORT`) is always set to 0 and is not in the control of Bitcoin Core. + +## Bandwidth + +By default, your node shares bandwidth and transit tunnels with the I2P network +in order to increase your anonymity with cover traffic, help the I2P router used +by your node integrate optimally with the network, and give back to the network. +It's important that the nodes of a popular application like Bitcoin contribute +as much to the I2P network as they consume. + +It is possible, though strongly discouraged, to change your I2P router +configuration to limit the amount of I2P traffic relayed by your node. + +With `i2pd`, this can be done by adjusting the `bandwidth`, `share` and +`transittunnels` options in your `i2pd.conf` file. For example, to limit total +I2P traffic to 256KB/s and share 50% of this limit for a maximum of 20 transit +tunnels: + +``` +bandwidth = 256 +share = 50 + +[limits] +transittunnels = 20 +``` + +Similar bandwidth configuration options for the Java I2P router can be found in +`http://127.0.0.1:7657/config` under the "Bandwidth" tab. + +Before doing this, please see the "Participating Traffic Considerations" section +in [Embedding I2P in your Application](https://geti2p.net/en/docs/applications/embedding). + +In most cases, the default router settings should work fine. + +## Bundling I2P in a Bitcoin application + +Please see the "General Guidance for Developers" section in https://geti2p.net/en/docs/api/samv3 +if you are developing a downstream application that may be bundling I2P with Bitcoin. diff --git a/doc/managing-wallets.md b/doc/managing-wallets.md index 366d7ec54b..22e006c963 100644 --- a/doc/managing-wallets.md +++ b/doc/managing-wallets.md @@ -88,7 +88,7 @@ In the RPC, the destination parameter must include the name of the file. Otherwi $ bitcoin-cli -rpcwallet="wallet-01" backupwallet /home/node01/Backups/backup-01.dat ``` -In the GUI, the wallet is selected in the `Wallet` drop-down list in the upper right corner. If this list is not present, the wallet can be loaded in `File` ->`Open wallet` if necessary. Then, the backup can be done in `File` -> `Backup Wallet...`. +In the GUI, the wallet is selected in the `Wallet` drop-down list in the upper right corner. If this list is not present, the wallet can be loaded in `File` ->`Open Wallet` if necessary. Then, the backup can be done in `File` -> `Backup Wallet…`. This backup file can be stored on one or multiple offline devices, which must be reliable enough to work in an emergency and be malware free. Backup files can be regularly tested to avoid problems in the future. @@ -108,7 +108,7 @@ Wallets created before version 0.13 are not HD and must be backed up every 100 k ### 1.6 Restoring the Wallet From a Backup -To restore a wallet, the `restorewallet` RPC must be used. +To restore a wallet, the `restorewallet` RPC or the `Restore Wallet` GUI menu item (`File` -> `Restore Wallet…`) must be used. ``` $ bitcoin-cli restorewallet "restored-wallet" /home/node01/Backups/backup-01.dat @@ -144,5 +144,5 @@ unforeseen configurations which result in some scripts being excluded. If a migr unexpectedly or otherwise misses any scripts, please create an issue on GitHub. A backup of the original wallet can be found in the wallet directory with the name `<name>-<timestamp>.legacy.bak`. -The backup can be restored using the `restorewallet` command as discussed in the -[Restoring the Wallet From a Backup](#16-restoring-the-wallet-from-a-backup) section +The backup can be restored using the methods discussed in the +[Restoring the Wallet From a Backup](#16-restoring-the-wallet-from-a-backup) section. diff --git a/doc/release-notes-19762.md b/doc/release-notes-19762.md new file mode 100644 index 0000000000..4dc45fb2c8 --- /dev/null +++ b/doc/release-notes-19762.md @@ -0,0 +1,19 @@ +JSON-RPC +--- + +All JSON-RPC methods accept a new [named +parameter](JSON-RPC-interface.md#parameter-passing) called `args` that can +contain positional parameter values. This is a convenience to allow some +parameter values to be passed by name without having to name every value. The +python test framework and `bitcoin-cli` tool both take advantage of this, so +for example: + +```sh +bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=1 +``` + +Can now be shortened to: + +```sh +bitcoin-cli -named createwallet mywallet load_on_startup=1 +``` diff --git a/doc/release-notes-23395.md b/doc/release-notes-23395.md new file mode 100644 index 0000000000..b9d7d9409c --- /dev/null +++ b/doc/release-notes-23395.md @@ -0,0 +1,8 @@ +Notable changes +=============== + +New settings +------------ + +- The `shutdownnotify` option is used to specify a command to execute synchronously +before Bitcoin Core has begun its shutdown sequence. (#23395) diff --git a/doc/release-notes-25375.md b/doc/release-notes-25375.md new file mode 100644 index 0000000000..504a2644f4 --- /dev/null +++ b/doc/release-notes-25375.md @@ -0,0 +1,11 @@ +Updated RPCs +-------- + +The `minconf` option, which allows a user to specify the minimum number +of confirmations a UTXO being spent has, and the `maxconf` option, +which allows specifying the maximum number of confirmations, have been +added to the following RPCs: +- `fundrawtransaction` +- `send` +- `walletcreatefundedpsbt` +- `sendall` diff --git a/doc/release-notes-25934.md b/doc/release-notes-25934.md new file mode 100644 index 0000000000..b4f1ae0d3c --- /dev/null +++ b/doc/release-notes-25934.md @@ -0,0 +1,8 @@ +Low-level changes +================= + +RPC +--- + +- RPC `listsinceblock` now accepts an optional `label` argument + to fetch incoming transactions having the specified label. (#25934)
\ No newline at end of file diff --git a/doc/release-notes-25957.md b/doc/release-notes-25957.md new file mode 100644 index 0000000000..c71afa2c2e --- /dev/null +++ b/doc/release-notes-25957.md @@ -0,0 +1,9 @@ +Wallet +------ + +- Rescans for descriptor wallets are now significantly faster if compact + block filters (BIP158) are available. Since those are not constructed + by default, the configuration option "-blockfilterindex=1" has to be + provided to take advantage of the optimization. This improves the + performance of the RPC calls `rescanblockchain`, `importdescriptors` + and `restorewallet`. (#25957) diff --git a/doc/release-notes-26213.md b/doc/release-notes-26213.md new file mode 100644 index 0000000000..e78d718ca9 --- /dev/null +++ b/doc/release-notes-26213.md @@ -0,0 +1,8 @@ +Low-level changes +================= + +- Previously `setban`, `addpeeraddress`, `walletcreatefundedpsbt`, methods + allowed non-boolean and non-null values to be passed as boolean parameters. + Any string, number, array, or object value that was passed would be treated + as false. After this change, passing any value except `true`, `false`, or + `null` now triggers a JSON value is not of expected type error. (#26213) diff --git a/doc/release-notes-26265.md b/doc/release-notes-26265.md new file mode 100644 index 0000000000..ca2313d956 --- /dev/null +++ b/doc/release-notes-26265.md @@ -0,0 +1,6 @@ +P2P and network changes +--------- + +- Transactions of non-witness size 65 and above are now allowed by mempool + and relay policy. This is to better reflect the actual afforded protections + against CVE-2017-12842 and open up additional use-cases of smaller transaction sizes. (#26265) diff --git a/doc/release-notes-26618.md b/doc/release-notes-26618.md new file mode 100644 index 0000000000..9d1ef3bd2e --- /dev/null +++ b/doc/release-notes-26618.md @@ -0,0 +1,4 @@ +RPC Wallet +---------- + +- RPC `unloadwallet` now fails if a rescan is in progress. (#26618) diff --git a/doc/release-notes-26628.md b/doc/release-notes-26628.md new file mode 100644 index 0000000000..48a07c1e81 --- /dev/null +++ b/doc/release-notes-26628.md @@ -0,0 +1,4 @@ +JSON-RPC +--- + +The JSON-RPC server now rejects requests where a parameter is specified multiple times with the same name, instead of silently overwriting earlier parameter values with later ones. (#26628) diff --git a/doc/release-notes-26646.md b/doc/release-notes-26646.md new file mode 100644 index 0000000000..7f94505a01 --- /dev/null +++ b/doc/release-notes-26646.md @@ -0,0 +1,8 @@ +JSON-RPC +-------- + +The `testmempoolaccept` RPC now returns 2 additional results within the "fees" result: +"effective-feerate" is the feerate including fees and sizes of transactions validated together if +package validation was used, and also includes any modified fees from prioritisetransaction. The +"effective-includes" result lists the wtxids of transactions whose modified fees and sizes were used +in the effective-feerate (#26646). diff --git a/doc/release-notes/release-notes-22.1.md b/doc/release-notes/release-notes-22.1.md new file mode 100644 index 0000000000..d304b7e57a --- /dev/null +++ b/doc/release-notes/release-notes-22.1.md @@ -0,0 +1,128 @@ +22.1 Release Notes +================== + +Bitcoin Core version 22.1 is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-22.1/> + +This release includes new features, various bug fixes and performance +improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes in some cases), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS) +or `bitcoind`/`bitcoin-qt` (on Linux). + +Upgrading directly from a version of Bitcoin Core that has reached its EOL is +possible, but it might take some time if the data directory needs to be migrated. Old +wallet versions of Bitcoin Core are generally supported. + +Compatibility +============== + +Bitcoin Core is supported and extensively tested on operating systems +using the Linux kernel, macOS 10.14+, and Windows 7 and newer. Bitcoin +Core should also work on most other Unix-like systems but is not as +frequently tested on them. It is not recommended to use Bitcoin Core on +unsupported systems. + +From Bitcoin Core 22.0 onwards, macOS versions earlier than 10.14 are no longer supported. + +Notable changes +=============== + +Updated settings +---------------- + +- In previous releases, the meaning of the command line option + `-persistmempool` (without a value provided) incorrectly disabled mempool + persistence. `-persistmempool` is now treated like other boolean options to + mean `-persistmempool=1`. Passing `-persistmempool=0`, `-persistmempool=1` + and `-nopersistmempool` is unaffected. (#23061) + +### P2P + +### RPC and other APIs + +- #25237 rpc: Capture UniValue by ref for rpcdoccheck +- #25983 Prevent data race for pathHandlers +- #26275 Fix crash on deriveaddresses when index is 2147483647 (2^31-1) + +### Wallet + +- #22781 wallet: fix the behavior of IsHDEnabled +- #22949 fee: Round up fee calculation to avoid a lower than expected feerate +- #23333 wallet: fix segfault by avoiding invalid default-ctored external_spk_managers entry + +### Build system + +- #22820 build, qt: Fix typo in QtInputSupport check +- #23045 build: Restrict check for CRC32C intrinsic to aarch64 +- #23148 build: Fix guix linker-loader path and add check_ELF_interpreter +- #23314 build: explicitly disable libsecp256k1 openssl based tests +- #23580 build: patch qt to explicitly define previously implicit header include +- #24215 guix: ignore additional failing certvalidator test +- #24256 build: Bump depends packages (zmq, libXau) +- #25201 windeploy: Renewed windows code signing certificate +- #25985 Revert "build: Use Homebrew's sqlite package if it is available" +- #26633 depends: update qt 5.12 url to archive location + +### GUI + +- #gui631 Disallow encryption of watchonly wallets +- #gui680 Fixes MacOS 13 segfault by preventing certain notifications +- #24498 qt: Avoid crash on startup if int specified in settings.json + +### Tests + +- #23716 test: replace hashlib.ripemd160 with an own implementation +- #24239 test: fix ceildiv division by using integers + +### Utilities + +- #22390 system: skip trying to set the locale on NetBSD +- #22895 don't call GetBlockPos in ReadBlockFromDisk without cs_main lock +- #24104 fs: Make compatible with boost 1.78 + +### Miscellaneous + +- #23335 refactor: include a missing <limits> header in fs.cpp +- #23504 ci: Replace soon EOL hirsute with jammy +- #26321 Adjust .tx/config for new Transifex CLI + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Andrew Chow +- BlackcoinDev +- Carl Dong +- Hennadii Stepanov +- Joan Karadimov +- John Moffett +- Jon Atack +- Kittywhiskers Van Gogh +- Marco Falke +- Martin Zumsande +- Michael Ford +- muxator +- Pieter Wuille +- Ryan Ofsky +- Saibato +- Sebastian Falbesoner +- W. J. van der Laan + +As well as to everyone that helped with translations on +[Transifex](https://www.transifex.com/bitcoin/bitcoin/). diff --git a/doc/release-notes/release-notes-23.1.md b/doc/release-notes/release-notes-23.1.md new file mode 100644 index 0000000000..31d9b7f068 --- /dev/null +++ b/doc/release-notes/release-notes-23.1.md @@ -0,0 +1,90 @@ +23.1 Release Notes +================== + +Bitcoin Core version 23.1 is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-23.1/> + +This release includes new features, various bug fixes and performance +improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes in some cases), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS) +or `bitcoind`/`bitcoin-qt` (on Linux). + +Upgrading directly from a version of Bitcoin Core that has reached its EOL is +possible, but it might take some time if the data directory needs to be migrated. Old +wallet versions of Bitcoin Core are generally supported. + +Compatibility +============== + +Bitcoin Core is supported and extensively tested on operating systems +using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin +Core should also work on most other Unix-like systems but is not as +frequently tested on them. It is not recommended to use Bitcoin Core on +unsupported systems. + +### P2P + +- #25314 p2p: always set nTime for self-advertisements + +### RPC and other APIs + +- #25220 rpc: fix incorrect warning for address type p2sh-segwit in createmultisig +- #25237 rpc: Capture UniValue by ref for rpcdoccheck +- #25983 Prevent data race for pathHandlers +- #26275 Fix crash on deriveaddresses when index is 2147483647 (2^31-1) + +### Build system + +- #25201 windeploy: Renewed windows code signing certificate +- #25788 guix: patch NSIS to remove .reloc sections from installer stubs +- #25861 guix: use --build={arch}-guix-linux-gnu in cross toolchain +- #25985 Revert "build: Use Homebrew's sqlite package if it is available" + +### GUI + +- #24668 build, qt: bump Qt5 version to 5.15.3 +- gui#631 Disallow encryption of watchonly wallets +- gui#680 Fixes MacOS 13 segfault by preventing certain notifications + +### Tests + +- #24454 tests: Fix calculation of external input weights + +### Miscellaneous + +- #26321 Adjust .tx/config for new Transifex CLI + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Andrew Chow +- brunoerg +- Hennadii Stepanov +- John Moffett +- MacroFake +- Martin Zumsande +- Michael Ford +- muxator +- Pavol Rusnak +- Sebastian Falbesoner +- W. J. van der Laan + +As well as to everyone that helped with translations on +[Transifex](https://www.transifex.com/bitcoin/bitcoin/). diff --git a/doc/release-notes/release-notes-24.0.1.md b/doc/release-notes/release-notes-24.0.1.md new file mode 100644 index 0000000000..24920ba450 --- /dev/null +++ b/doc/release-notes/release-notes-24.0.1.md @@ -0,0 +1,391 @@ +24.0.1 Release Notes +==================== + +Due to last-minute issues (#26616), 24.0, although tagged, was never fully +announced or released. + +Bitcoin Core version 24.0.1 is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-24.0.1/> + +This release includes new features, various bug fixes and performance +improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes in some cases), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS) +or `bitcoind`/`bitcoin-qt` (on Linux). + +Upgrading directly from a version of Bitcoin Core that has reached its EOL is +possible, but it might take some time if the data directory needs to be migrated. Old +wallet versions of Bitcoin Core are generally supported. + +Compatibility +============== + +Bitcoin Core is supported and extensively tested on operating systems +using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin +Core should also work on most other Unix-like systems but is not as +frequently tested on them. It is not recommended to use Bitcoin Core on +unsupported systems. + +Notice of new option for transaction replacement policies +========================================================= + +This version of Bitcoin Core adds a new `mempoolfullrbf` configuration +option which allows users to change the policy their individual node +will use for relaying and mining unconfirmed transactions. The option +defaults to the same policy that was used in previous releases and no +changes to node policy will occur if everyone uses the default. + +Some Bitcoin services today expect that the first version of an +unconfirmed transaction that they see will be the version of the +transaction that ultimately gets confirmed---a transaction acceptance +policy sometimes called "first-seen". + +The Bitcoin Protocol does not, and cannot, provide any assurance that +the first version of an unconfirmed transaction seen by a particular +node will be the version that gets confirmed. If there are multiple +versions of the same unconfirmed transaction available, only the miner +who includes one of those transactions in a block gets to decide which +version of the transaction gets confirmed. + +Despite this lack of assurance, multiple merchants and services today +still make this assumption. + +There are several benefits to users from removing this *first-seen* +simplification. One key benefit, the ability for the sender of a +transaction to replace it with an alternative version paying higher +fees, was realized in [Bitcoin Core 0.12.0][] (February 2016) with the +introduction of [BIP125][] opt-in Replace By Fee (RBF). + +Since then, there has been discussion about completely removing the +first-seen simplification and allowing users to replace any of their +older unconfirmed transactions with newer transactions, a feature called +*full-RBF*. This release includes a `mempoolfullrbf` configuration +option that allows enabling full-RBF, although it defaults to off +(allowing only opt-in RBF). + +Several alternative node implementations have already enabled full-RBF by +default for years, and several contributors to Bitcoin Core are +advocating for enabling full-RBF by default in a future version of +Bitcoin Core. + +As more nodes that participate in relay and mining begin enabling +full-RBF, replacement of unconfirmed transactions by ones offering higher +fees may rapidly become more reliable. + +Contributors to this project strongly recommend that merchants and services +not accept unconfirmed transactions as final, and if they insist on doing so, +to take the appropriate steps to ensure they have some recourse or plan for +when their assumptions do not hold. + +[Bitcoin Core 0.12.0]: https://bitcoincore.org/en/releases/0.12.0/#opt-in-replace-by-fee-transactions +[bip125]: https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki + +Notable changes +=============== + +P2P and network changes +----------------------- + +- To address a potential denial-of-service, the logic to download headers from peers + has been reworked. This is particularly relevant for nodes starting up for the + first time (or for nodes which are starting up after being offline for a long time). + + Whenever headers are received from a peer that have a total chainwork that is either + less than the node's `-minimumchainwork` value or is sufficiently below the work at + the node's tip, a "presync" phase will begin, in which the node will download the + peer's headers and verify the cumulative work on the peer's chain, prior to storing + those headers permanently. Once that cumulative work is verified to be sufficiently high, + the headers will be redownloaded from that peer and fully validated and stored. + + This may result in initial headers sync taking longer for new nodes starting up for + the first time, both because the headers will be downloaded twice, and because the effect + of a peer disconnecting during the presync phase (or while the node's best headers chain has less + than `-minimumchainwork`), will result in the node needing to use the headers presync mechanism + with the next peer as well (downloading the headers twice, again). (#25717) + +- With I2P connections, a new, transient address is used for each outbound + connection if `-i2pacceptincoming=0`. (#25355) + +Updated RPCs +------------ + +- The `-deprecatedrpc=softforks` configuration option has been removed. The + RPC `getblockchaininfo` no longer returns the `softforks` field, which was + previously deprecated in 23.0. (#23508) Information on soft fork status is + now only available via the `getdeploymentinfo` RPC. + +- The `deprecatedrpc=exclude_coinbase` configuration option has been removed. + The `receivedby` RPCs (`listreceivedbyaddress`, `listreceivedbylabel`, + `getreceivedbyaddress` and `getreceivedbylabel`) now always return results + accounting for received coins from coinbase outputs, without an option to + change that behaviour. Excluding coinbases was previously deprecated in 23.0. + (#25171) + +- The `deprecatedrpc=fees` configuration option has been removed. The top-level + fee fields `fee`, `modifiedfee`, `ancestorfees` and `descendantfees` are no + longer returned by RPCs `getmempoolentry`, `getrawmempool(verbose=true)`, + `getmempoolancestors(verbose=true)` and `getmempooldescendants(verbose=true)`. + The same fee fields can be accessed through the `fees` object in the result. + The top-level fee fields were previously deprecated in 23.0. (#25204) + +- The `getpeerinfo` RPC has been updated with a new `presynced_headers` field, + indicating the progress on the presync phase mentioned in the + "P2P and network changes" section above. + +Changes to wallet related RPCs can be found in the Wallet section below. + +New RPCs +-------- + +- The `sendall` RPC spends specific UTXOs to one or more recipients + without creating change. By default, the `sendall` RPC will spend + every UTXO in the wallet. `sendall` is useful to empty wallets or to + create a changeless payment from select UTXOs. When creating a payment + from a specific amount for which the recipient incurs the transaction + fee, continue to use the `subtractfeefromamount` option via the + `send`, `sendtoaddress`, or `sendmany` RPCs. (#24118) + +- A new `gettxspendingprevout` RPC has been added, which scans the mempool to find + transactions spending any of the given outpoints. (#24408) + +- The `simulaterawtransaction` RPC iterates over the inputs and outputs of the given + transactions, and tallies up the balance change for the given wallet. This can be + useful e.g. when verifying that a coin join like transaction doesn't contain unexpected + inputs that the wallet will then sign for unintentionally. (#22751) + +Updated REST APIs +----------------- + +- The `/headers/` and `/blockfilterheaders/` endpoints have been updated to use + a query parameter instead of path parameter to specify the result count. The + count parameter is now optional, and defaults to 5 for both endpoints. The old + endpoints are still functional, and have no documented behaviour change. + + For `/headers`, use + `GET /rest/headers/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>` + instead of + `GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated) + + For `/blockfilterheaders/`, use + `GET /rest/blockfilterheaders/<FILTERTYPE>/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>` + instead of + `GET /rest/blockfilterheaders/<FILTERTYPE>/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated) + + (#24098) + +Build System +------------ + +- Guix builds are now reproducible across architectures (x86_64 & aarch64). (#21194) + +New settings +------------ + +- A new `mempoolfullrbf` option has been added, which enables the mempool to + accept transaction replacement without enforcing BIP125 replaceability + signaling. (#25353) + +Wallet +------ + +- The `-walletrbf` startup option will now default to `true`. The + wallet will now default to opt-in RBF on transactions that it creates. (#25610) + +- The `replaceable` option for the `createrawtransaction` and + `createpsbt` RPCs will now default to `true`. Transactions created + with these RPCs will default to having opt-in RBF enabled. (#25610) + +- The `wsh()` output descriptor was extended with Miniscript support. You can import Miniscript + descriptors for P2WSH in a watchonly wallet to track coins, but you can't spend from them using + the Bitcoin Core wallet yet. + You can find more about Miniscript on the [reference website](https://bitcoin.sipa.be/miniscript/). (#24148) + +- The `tr()` output descriptor now supports multisig scripts through the `multi_a()` and + `sortedmulti_a()` functions. (#24043) + +- To help prevent fingerprinting transactions created by the Bitcoin Core wallet, change output + amounts are now randomized. (#24494) + +- The `listtransactions`, `gettransaction`, and `listsinceblock` + RPC methods now include a wtxid field (hash of serialized transaction, + including witness data) for each transaction. (#24198) + +- The `listsinceblock`, `listtransactions` and `gettransaction` output now contain a new + `parent_descs` field for every "receive" entry. (#25504) + +- A new optional `include_change` parameter was added to the `listsinceblock` command. + +- RPC `getreceivedbylabel` now returns an error, "Label not found + in wallet" (-4), if the label is not in the address book. (#25122) + +Migrating Legacy Wallets to Descriptor Wallets +--------------------------------------------- + +An experimental RPC `migratewallet` has been added to migrate Legacy (non-descriptor) wallets to +Descriptor wallets. More information about the migration process is available in the +[documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/managing-wallets.md#migrating-legacy-wallets-to-descriptor-wallets). + +GUI changes +----------- + +- A new menu item to restore a wallet from a backup file has been added (gui#471). + +- Configuration changes made in the bitcoin GUI (such as the pruning setting, +proxy settings, UPNP preferences) are now saved to `<datadir>/settings.json` +file rather than to the Qt settings backend (windows registry or unix desktop +config files), so these settings will now apply to bitcoind, instead of being +ignored. (#15936, gui#602) + +- Also, the interaction between GUI settings and `bitcoin.conf` settings is +simplified. Settings from `bitcoin.conf` are now displayed normally in the GUI +settings dialog, instead of in a separate warning message ("Options set in this +dialog are overridden by the configuration file: -setting=value"). And these +settings can now be edited because `settings.json` values take precedence over +`bitcoin.conf` values. (#15936) + +Low-level changes +================= + +RPC +--- + +- The `deriveaddresses`, `getdescriptorinfo`, `importdescriptors` and `scantxoutset` commands now + accept Miniscript expression within a `wsh()` descriptor. (#24148) + +- The `getaddressinfo`, `decodescript`, `listdescriptors` and `listunspent` commands may now output + a Miniscript descriptor inside a `wsh()` where a `wsh(raw())` descriptor was previously returned. (#24148) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- /dev/fd0 +- 0xb10c +- Adam Jonas +- akankshakashyap +- Ali Sherief +- amadeuszpawlik +- Andreas Kouloumos +- Andrew Chow +- Anthony Towns +- Antoine Poinsot +- Antoine Riard +- Aurèle Oulès +- avirgovi +- Ayush Sharma +- Baas +- Ben Woosley +- BrokenProgrammer +- brunoerg +- brydinh +- Bushstar +- Calvin Kim +- CAnon +- Carl Dong +- chinggg +- Cory Fields +- Daniel Kraft +- Daniela Brozzoni +- darosior +- Dave Scotese +- David Bakin +- dergoegge +- dhruv +- Dimitri +- dontbyte +- Duncan Dean +- eugene +- Eunoia +- Fabian Jahr +- furszy +- Gleb Naumenko +- glozow +- Greg Weber +- Gregory Sanders +- gruve-p +- Hennadii Stepanov +- hiago +- Igor Bubelov +- ishaanam +- Jacob P. +- Jadi +- James O'Beirne +- Janna +- Jarol Rodriguez +- Jeremy Rand +- Jeremy Rubin +- jessebarton +- João Barbosa +- John Newbery +- Jon Atack +- Josiah Baker +- Karl-Johan Alm +- KevinMusgrave +- Kiminuo +- klementtan +- Kolby Moroz +- kouloumos +- Kristaps Kaupe +- Larry Ruane +- Luke Dashjr +- MarcoFalke +- Marnix +- Martin Leitner-Ankerl +- Martin Zumsande +- Michael Dietz +- Michael Folkson +- Michael Ford +- Murch +- mutatrum +- muxator +- Oskar Mendel +- Pablo Greco +- pasta +- Patrick Strateman +- Pavol Rusnak +- Peter Bushnell +- phyBrackets +- Pieter Wuille +- practicalswift +- randymcmillan +- Robert Spigler +- Russell Yanofsky +- S3RK +- Samer Afach +- Sebastian Falbesoner +- Seibart Nedor +- Shashwat +- Sjors Provoost +- Smlep +- sogoagain +- Stacie +- Stéphan Vuylsteke +- Suhail Saqan +- Suhas Daftuar +- t-bast +- TakeshiMusgrave +- Vasil Dimov +- W. J. van der Laan +- w0xlt +- whiteh0rse +- willcl-ark +- William Casarin +- Yancy Ribbens + +As well as to everyone that helped with translations on +[Transifex](https://www.transifex.com/bitcoin/bitcoin/). diff --git a/doc/release-notes/release-notes-24.0.md b/doc/release-notes/release-notes-24.0.md index a9240567d7..a0227aa17f 100644 --- a/doc/release-notes/release-notes-24.0.md +++ b/doc/release-notes/release-notes-24.0.md @@ -1,388 +1,4 @@ -24.0 Release Notes -================== +Due to last-minute issues (#26616), 24.0, although tagged, was never fully +announced or released. -Bitcoin Core version 24.0 is now available from: - - <https://bitcoincore.org/bin/bitcoin-core-24.0/> - -This release includes new features, various bug fixes and performance -improvements, as well as updated translations. - -Please report bugs using the issue tracker at GitHub: - - <https://github.com/bitcoin/bitcoin/issues> - -To receive security and update notifications, please subscribe to: - - <https://bitcoincore.org/en/list/announcements/join/> - -How to Upgrade -============== - -If you are running an older version, shut it down. Wait until it has completely -shut down (which might take a few minutes in some cases), then run the -installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS) -or `bitcoind`/`bitcoin-qt` (on Linux). - -Upgrading directly from a version of Bitcoin Core that has reached its EOL is -possible, but it might take some time if the data directory needs to be migrated. Old -wallet versions of Bitcoin Core are generally supported. - -Compatibility -============== - -Bitcoin Core is supported and extensively tested on operating systems -using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin -Core should also work on most other Unix-like systems but is not as -frequently tested on them. It is not recommended to use Bitcoin Core on -unsupported systems. - -Notice of new option for transaction replacement policies -========================================================= - -This version of Bitcoin Core adds a new `mempoolfullrbf` configuration -option which allows users to change the policy their individual node -will use for relaying and mining unconfirmed transactions. The option -defaults to the same policy that was used in previous releases and no -changes to node policy will occur if everyone uses the default. - -Some Bitcoin services today expect that the first version of an -unconfirmed transaction that they see will be the version of the -transaction that ultimately gets confirmed---a transaction acceptance -policy sometimes called "first-seen". - -The Bitcoin Protocol does not, and cannot, provide any assurance that -the first version of an unconfirmed transaction seen by a particular -node will be the version that gets confirmed. If there are multiple -versions of the same unconfirmed transaction available, only the miner -who includes one of those transactions in a block gets to decide which -version of the transaction gets confirmed. - -Despite this lack of assurance, multiple merchants and services today -still make this assumption. - -There are several benefits to users from removing this *first-seen* -simplification. One key benefit, the ability for the sender of a -transaction to replace it with an alternative version paying higher -fees, was realized in [Bitcoin Core 0.12.0][] (February 2016) with the -introduction of [BIP125][] opt-in Replace By Fee (RBF). - -Since then, there has been discussion about completely removing the -first-seen simplification and allowing users to replace any of their -older unconfirmed transactions with newer transactions, a feature called -*full-RBF*. This release includes a `mempoolfullrbf` configuration -option that allows enabling full-RBF, although it defaults to off -(allowing only opt-in RBF). - -Several alternative node implementations have already enabled full-RBF by -default for years, and several contributors to Bitcoin Core are -advocating for enabling full-RBF by default in a future version of -Bitcoin Core. - -As more nodes that participate in relay and mining begin enabling -full-RBF, replacement of unconfirmed transactions by ones offering higher -fees may rapidly become more reliable. - -Contributors to this project strongly recommend that merchants and services -not accept unconfirmed transactions as final, and if they insist on doing so, -to take the appropriate steps to ensure they have some recourse or plan for -when their assumptions do not hold. - -[Bitcoin Core 0.12.0]: https://bitcoincore.org/en/releases/0.12.0/#opt-in-replace-by-fee-transactions -[bip125]: https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki - -Notable changes -=============== - -P2P and network changes ------------------------ - -- To address a potential denial-of-service, the logic to download headers from peers - has been reworked. This is particularly relevant for nodes starting up for the - first time (or for nodes which are starting up after being offline for a long time). - - Whenever headers are received from a peer that have a total chainwork that is either - less than the node's `-minimumchainwork` value or is sufficiently below the work at - the node's tip, a "presync" phase will begin, in which the node will download the - peer's headers and verify the cumulative work on the peer's chain, prior to storing - those headers permanently. Once that cumulative work is verified to be sufficiently high, - the headers will be redownloaded from that peer and fully validated and stored. - - This may result in initial headers sync taking longer for new nodes starting up for - the first time, both because the headers will be downloaded twice, and because the effect - of a peer disconnecting during the presync phase (or while the node's best headers chain has less - than `-minimumchainwork`), will result in the node needing to use the headers presync mechanism - with the next peer as well (downloading the headers twice, again). (#25717) - -- With I2P connections, a new, transient address is used for each outbound - connection if `-i2pacceptincoming=0`. (#25355) - -Updated RPCs ------------- - -- The `-deprecatedrpc=softforks` configuration option has been removed. The - RPC `getblockchaininfo` no longer returns the `softforks` field, which was - previously deprecated in 23.0. (#23508) Information on soft fork status is - now only available via the `getdeploymentinfo` RPC. - -- The `deprecatedrpc=exclude_coinbase` configuration option has been removed. - The `receivedby` RPCs (`listreceivedbyaddress`, `listreceivedbylabel`, - `getreceivedbyaddress` and `getreceivedbylabel`) now always return results - accounting for received coins from coinbase outputs, without an option to - change that behaviour. Excluding coinbases was previously deprecated in 23.0. - (#25171) - -- The `deprecatedrpc=fees` configuration option has been removed. The top-level - fee fields `fee`, `modifiedfee`, `ancestorfees` and `descendantfees` are no - longer returned by RPCs `getmempoolentry`, `getrawmempool(verbose=true)`, - `getmempoolancestors(verbose=true)` and `getmempooldescendants(verbose=true)`. - The same fee fields can be accessed through the `fees` object in the result. - The top-level fee fields were previously deprecated in 23.0. (#25204) - -- The `getpeerinfo` RPC has been updated with a new `presynced_headers` field, - indicating the progress on the presync phase mentioned in the - "P2P and network changes" section above. - -Changes to wallet related RPCs can be found in the Wallet section below. - -New RPCs --------- - -- The `sendall` RPC spends specific UTXOs to one or more recipients - without creating change. By default, the `sendall` RPC will spend - every UTXO in the wallet. `sendall` is useful to empty wallets or to - create a changeless payment from select UTXOs. When creating a payment - from a specific amount for which the recipient incurs the transaction - fee, continue to use the `subtractfeefromamount` option via the - `send`, `sendtoaddress`, or `sendmany` RPCs. (#24118) - -- A new `gettxspendingprevout` RPC has been added, which scans the mempool to find - transactions spending any of the given outpoints. (#24408) - -- The `simulaterawtransaction` RPC iterates over the inputs and outputs of the given - transactions, and tallies up the balance change for the given wallet. This can be - useful e.g. when verifying that a coin join like transaction doesn't contain unexpected - inputs that the wallet will then sign for unintentionally. (#22751) - -Updated REST APIs ------------------ - -- The `/headers/` and `/blockfilterheaders/` endpoints have been updated to use - a query parameter instead of path parameter to specify the result count. The - count parameter is now optional, and defaults to 5 for both endpoints. The old - endpoints are still functional, and have no documented behaviour change. - - For `/headers`, use - `GET /rest/headers/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>` - instead of - `GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated) - - For `/blockfilterheaders/`, use - `GET /rest/blockfilterheaders/<FILTERTYPE>/<BLOCK-HASH>.<bin|hex|json>?count=<COUNT=5>` - instead of - `GET /rest/blockfilterheaders/<FILTERTYPE>/<COUNT>/<BLOCK-HASH>.<bin|hex|json>` (deprecated) - - (#24098) - -Build System ------------- - -- Guix builds are now reproducible across architectures (x86_64 & aarch64). (#21194) - -New settings ------------- - -- A new `mempoolfullrbf` option has been added, which enables the mempool to - accept transaction replacement without enforcing BIP125 replaceability - signaling. (#25353) - -Wallet ------- - -- The `-walletrbf` startup option will now default to `true`. The - wallet will now default to opt-in RBF on transactions that it creates. (#25610) - -- The `replaceable` option for the `createrawtransaction` and - `createpsbt` RPCs will now default to `true`. Transactions created - with these RPCs will default to having opt-in RBF enabled. (#25610) - -- The `wsh()` output descriptor was extended with Miniscript support. You can import Miniscript - descriptors for P2WSH in a watchonly wallet to track coins, but you can't spend from them using - the Bitcoin Core wallet yet. - You can find more about Miniscript on the [reference website](https://bitcoin.sipa.be/miniscript/). (#24148) - -- The `tr()` output descriptor now supports multisig scripts through the `multi_a()` and - `sortedmulti_a()` functions. (#24043) - -- To help prevent fingerprinting transactions created by the Bitcoin Core wallet, change output - amounts are now randomized. (#24494) - -- The `listtransactions`, `gettransaction`, and `listsinceblock` - RPC methods now include a wtxid field (hash of serialized transaction, - including witness data) for each transaction. (#24198) - -- The `listsinceblock`, `listtransactions` and `gettransaction` output now contain a new - `parent_descs` field for every "receive" entry. (#25504) - -- A new optional `include_change` parameter was added to the `listsinceblock` command. - -- RPC `getreceivedbylabel` now returns an error, "Label not found - in wallet" (-4), if the label is not in the address book. (#25122) - -Migrating Legacy Wallets to Descriptor Wallets ---------------------------------------------- - -An experimental RPC `migratewallet` has been added to migrate Legacy (non-descriptor) wallets to -Descriptor wallets. More information about the migration process is available in the -[documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/managing-wallets.md#migrating-legacy-wallets-to-descriptor-wallets). - -GUI changes ------------ - -- A new menu item to restore a wallet from a backup file has been added (gui#471). - -- Configuration changes made in the bitcoin GUI (such as the pruning setting, -proxy settings, UPNP preferences) are now saved to `<datadir>/settings.json` -file rather than to the Qt settings backend (windows registry or unix desktop -config files), so these settings will now apply to bitcoind, instead of being -ignored. (#15936, gui#602) - -- Also, the interaction between GUI settings and `bitcoin.conf` settings is -simplified. Settings from `bitcoin.conf` are now displayed normally in the GUI -settings dialog, instead of in a separate warning message ("Options set in this -dialog are overridden by the configuration file: -setting=value"). And these -settings can now be edited because `settings.json` values take precedence over -`bitcoin.conf` values. (#15936) - -Low-level changes -================= - -RPC ---- - -- The `deriveaddresses`, `getdescriptorinfo`, `importdescriptors` and `scantxoutset` commands now - accept Miniscript expression within a `wsh()` descriptor. (#24148) - -- The `getaddressinfo`, `decodescript`, `listdescriptors` and `listunspent` commands may now output - a Miniscript descriptor inside a `wsh()` where a `wsh(raw())` descriptor was previously returned. (#24148) - -Credits -======= - -Thanks to everyone who directly contributed to this release: - -- /dev/fd0 -- 0xb10c -- Adam Jonas -- akankshakashyap -- Ali Sherief -- amadeuszpawlik -- Andreas Kouloumos -- Andrew Chow -- Anthony Towns -- Antoine Poinsot -- Antoine Riard -- Aurèle Oulès -- avirgovi -- Ayush Sharma -- Baas -- Ben Woosley -- BrokenProgrammer -- brunoerg -- brydinh -- Bushstar -- Calvin Kim -- CAnon -- Carl Dong -- chinggg -- Cory Fields -- Daniel Kraft -- Daniela Brozzoni -- darosior -- Dave Scotese -- David Bakin -- dergoegge -- dhruv -- Dimitri -- dontbyte -- Duncan Dean -- eugene -- Eunoia -- Fabian Jahr -- furszy -- Gleb Naumenko -- glozow -- Greg Weber -- Gregory Sanders -- gruve-p -- Hennadii Stepanov -- hiago -- Igor Bubelov -- ishaanam -- Jacob P. -- Jadi -- James O'Beirne -- Janna -- Jarol Rodriguez -- Jeremy Rand -- Jeremy Rubin -- jessebarton -- João Barbosa -- John Newbery -- Jon Atack -- Josiah Baker -- Karl-Johan Alm -- KevinMusgrave -- Kiminuo -- klementtan -- Kolby Moroz -- kouloumos -- Kristaps Kaupe -- Larry Ruane -- Luke Dashjr -- MarcoFalke -- Marnix -- Martin Leitner-Ankerl -- Martin Zumsande -- Michael Dietz -- Michael Folkson -- Michael Ford -- Murch -- mutatrum -- muxator -- Oskar Mendel -- Pablo Greco -- pasta -- Patrick Strateman -- Pavol Rusnak -- Peter Bushnell -- phyBrackets -- Pieter Wuille -- practicalswift -- randymcmillan -- Robert Spigler -- Russell Yanofsky -- S3RK -- Samer Afach -- Sebastian Falbesoner -- Seibart Nedor -- Shashwat -- Sjors Provoost -- Smlep -- sogoagain -- Stacie -- Stéphan Vuylsteke -- Suhail Saqan -- Suhas Daftuar -- t-bast -- TakeshiMusgrave -- Vasil Dimov -- W. J. van der Laan -- w0xlt -- whiteh0rse -- willcl-ark -- William Casarin -- Yancy Ribbens - -As well as to everyone that helped with translations on -[Transifex](https://www.transifex.com/bitcoin/bitcoin/). +See the release notes for 24.0.1 instead. diff --git a/doc/release-process.md b/doc/release-process.md index 17a03f7dcd..59ac2e884a 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -134,7 +134,6 @@ Follow the relevant Guix README.md sections: ### Verify other builders' signatures to your own (optional) -- [Add other builders keys to your gpg keyring, and/or refresh keys](/contrib/builder-keys/README.md) - [Verifying build output attestations](/contrib/guix/README.md#verifying-build-output-attestations) ### Commit your non codesigned signature to guix.sigs @@ -193,7 +192,6 @@ popd ### Verify other builders' signatures to your own (optional) -- [Add other builders keys to your gpg keyring, and/or refresh keys](/contrib/builder-keys/README.md) - [Verifying build output attestations](/contrib/guix/README.md#verifying-build-output-attestations) ### Commit your codesigned signature to guix.sigs (for the signed macOS/Windows binaries) diff --git a/src/.clang-tidy b/src/.clang-tidy index 9d78ccc959..b2e6914548 100644 --- a/src/.clang-tidy +++ b/src/.clang-tidy @@ -7,22 +7,13 @@ modernize-use-default-member-init, modernize-use-nullptr, performance-for-range-copy, performance-move-const-arg, +performance-no-automatic-move, performance-unnecessary-copy-initialization, readability-redundant-declaration, readability-redundant-string-init, ' -WarningsAsErrors: ' -bugprone-argument-comment, -bugprone-use-after-move, -misc-unused-using-decls, -modernize-use-default-member-init, -modernize-use-nullptr, -performance-for-range-copy, -performance-move-const-arg, -performance-unnecessary-copy-initialization, -readability-redundant-declaration, -readability-redundant-string-init, -' +WarningsAsErrors: '*' CheckOptions: - key: performance-move-const-arg.CheckTriviallyCopyableMove value: false +HeaderFilterRegex: './qt' diff --git a/src/Makefile.am b/src/Makefile.am index eb56639795..35b0ad24c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -177,6 +177,8 @@ BITCOIN_CORE_H = \ kernel/checks.h \ kernel/coinstats.h \ kernel/context.h \ + kernel/cs_main.h \ + kernel/mempool_entry.h \ kernel/mempool_limits.h \ kernel/mempool_options.h \ kernel/mempool_persist.h \ @@ -258,13 +260,11 @@ BITCOIN_CORE_H = \ support/events.h \ support/lockedpool.h \ sync.h \ - threadinterrupt.h \ threadsafety.h \ timedata.h \ torcontrol.h \ txdb.h \ txmempool.h \ - txmempool_entry.h \ txorphanage.h \ txrequest.h \ undo.h \ @@ -298,6 +298,7 @@ BITCOIN_CORE_H = \ util/syserror.h \ util/system.h \ util/thread.h \ + util/threadinterrupt.h \ util/threadnames.h \ util/time.h \ util/tokenpipe.h \ @@ -375,6 +376,7 @@ libbitcoin_node_a_SOURCES = \ kernel/checks.cpp \ kernel/coinstats.cpp \ kernel/context.cpp \ + kernel/cs_main.cpp \ kernel/mempool_persist.cpp \ mapport.cpp \ net.cpp \ @@ -633,6 +635,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ common/bloom.cpp \ + common/interfaces.cpp \ common/run_command.cpp \ compressor.cpp \ core_read.cpp \ @@ -652,8 +655,9 @@ libbitcoin_common_a_SOURCES = \ policy/policy.cpp \ protocol.cpp \ psbt.cpp \ - rpc/rawtransaction_util.cpp \ rpc/external_signer.cpp \ + rpc/rawtransaction_util.cpp \ + rpc/request.cpp \ rpc/util.cpp \ scheduler.cpp \ script/descriptor.cpp \ @@ -671,23 +675,18 @@ endif # # util # -libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/lockedpool.cpp \ chainparamsbase.cpp \ clientversion.cpp \ fs.cpp \ - interfaces/echo.cpp \ - interfaces/handler.cpp \ - interfaces/init.cpp \ logging.cpp \ random.cpp \ randomenv.cpp \ - rpc/request.cpp \ support/cleanse.cpp \ sync.cpp \ - threadinterrupt.cpp \ util/asmap.cpp \ util/bip32.cpp \ util/bytevectorhash.cpp \ @@ -705,6 +704,7 @@ libbitcoin_util_a_SOURCES = \ util/readwritefile.cpp \ util/settings.cpp \ util/thread.cpp \ + util/threadinterrupt.cpp \ util/threadnames.cpp \ util/serfloat.cpp \ util/spanparsing.cpp \ @@ -908,6 +908,7 @@ libbitcoinkernel_la_SOURCES = \ kernel/checks.cpp \ kernel/coinstats.cpp \ kernel/context.cpp \ + kernel/cs_main.cpp \ kernel/mempool_persist.cpp \ key.cpp \ logging.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 9a9424e84c..1a29e9a47a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -174,7 +174,6 @@ BITCOIN_TESTS += \ wallet/test/wallet_crypto_tests.cpp \ wallet/test/wallet_transaction_tests.cpp \ wallet/test/coinselector_tests.cpp \ - wallet/test/availablecoins_tests.cpp \ wallet/test/init_tests.cpp \ wallet/test/ismine_tests.cpp \ wallet/test/rpc_util_tests.cpp \ @@ -199,8 +198,6 @@ FUZZ_WALLET_SRC += \ endif # USE_SQLITE BITCOIN_TEST_SUITE += \ - wallet/test/util.cpp \ - wallet/test/util.h \ wallet/test/wallet_test_fixture.cpp \ wallet/test/wallet_test_fixture.h \ wallet/test/init_test_fixture.cpp \ @@ -378,7 +375,7 @@ if TARGET_WINDOWS else if ENABLE_BENCH @echo "Running bench/bench_bitcoin (one iteration sanity check, only high priority)..." - $(BENCH_BINARY) -sanity-check -priority-level=high > /dev/null + $(BENCH_BINARY) -sanity-check -priority-level=high endif endif $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index d142572b27..a4e8b3f842 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -18,8 +18,11 @@ TEST_UTIL_H = \ test/util/str.h \ test/util/transaction_utils.h \ test/util/txmempool.h \ - test/util/validation.h \ - test/util/wallet.h + test/util/validation.h + +if ENABLE_WALLET +TEST_UTIL_H += wallet/test/util.h +endif # ENABLE_WALLET libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) @@ -33,6 +36,10 @@ libtest_util_a_SOURCES = \ test/util/str.cpp \ test/util/transaction_utils.cpp \ test/util/txmempool.cpp \ - test/util/validation.cpp \ - test/util/wallet.cpp \ - $(TEST_UTIL_H) + test/util/validation.cpp + +if ENABLE_WALLET +libtest_util_a_SOURCES += wallet/test/util.cpp +endif # ENABLE_WALLET + +libtest_util_a_SOURCES += $(TEST_UTIL_H) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 7106d819b0..7c954dbf3a 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,10 +34,9 @@ bool SerializeDB(Stream& stream, const Data& data) { // Write and commit header, data try { - CHashWriter hasher(stream.GetType(), stream.GetVersion()); - stream << Params().MessageStart() << data; - hasher << Params().MessageStart() << data; - stream << hasher.GetHash(); + HashedSourceWriter hashwriter{stream}; + hashwriter << Params().MessageStart() << data; + stream << hashwriter.GetHash(); } catch (const std::exception& e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } diff --git a/src/addrman.cpp b/src/addrman.cpp index f16ff2230b..f86bdfa3df 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2012 Pieter Wuille -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1112,7 +1112,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision() { LOCK(cs); Check(); - const auto ret = SelectTriedCollision_(); + auto ret = SelectTriedCollision_(); Check(); return ret; } @@ -1121,7 +1121,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool newOnly) const { LOCK(cs); Check(); - const auto addrRet = Select_(newOnly); + auto addrRet = Select_(newOnly); Check(); return addrRet; } @@ -1130,7 +1130,7 @@ std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct, { LOCK(cs); Check(); - const auto addresses = GetAddr_(max_addresses, max_pct, network); + auto addresses = GetAddr_(max_addresses, max_pct, network); Check(); return addresses; } @@ -1178,8 +1178,7 @@ void AddrMan::Unserialize(Stream& s_) } // explicit instantiation -template void AddrMan::Serialize(CHashWriter& s) const; -template void AddrMan::Serialize(CAutoFile& s) const; +template void AddrMan::Serialize(HashedSourceWriter<CAutoFile>& s) const; template void AddrMan::Serialize(CDataStream& s) const; template void AddrMan::Unserialize(CAutoFile& s); template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s); diff --git a/src/addrman.h b/src/addrman.h index 5099c8c7a3..0f1f808fa1 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -1,5 +1,5 @@ // Copyright (c) 2012 Pieter Wuille -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/addrman_impl.h b/src/addrman_impl.h index 376e79f49f..39754b673e 100644 --- a/src/addrman_impl.h +++ b/src/addrman_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index e614102de3..3776cfb6de 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/arith_uint256.h b/src/arith_uint256.h index b7b3b3a285..a6065dd9bd 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/banman.cpp b/src/banman.cpp index 3cd646c148..ece949d997 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/banman.h b/src/banman.h index 77b043f081..241f01dd2e 100644 --- a/src/banman.h +++ b/src/banman.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 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_BANMAN_H diff --git a/src/base58.cpp b/src/base58.cpp index 11c1ce7397..cf5d62f164 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2021 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/base58.h b/src/base58.h index d2a8d5e3bc..2f4d0b74b1 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bech32.cpp b/src/bech32.cpp index 8e0025b8f4..ba3c419d8b 100644 --- a/src/bech32.cpp +++ b/src/bech32.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2017, 2021 Pieter Wuille -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp index 019b133345..d6b52eb587 100644 --- a/src/bench/addrman.cpp +++ b/src/bench/addrman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp index 3d08b7201b..78748bc5bd 100644 --- a/src/bench/base58.cpp +++ b/src/bench/base58.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp index 1a166e7081..9922653766 100644 --- a/src/bench/bech32.cpp +++ b/src/bench/bech32.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 1a3a006286..4374a63250 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -83,7 +83,7 @@ void BenchRunner::RunAll(const Args& args) std::smatch baseMatch; if (args.sanity_check) { - std::cout << "Running with --sanity-check option, benchmark results will be useless." << std::endl; + std::cout << "Running with -sanity-check option, output is being suppressed as benchmark results will be useless." << std::endl; } std::vector<ankerl::nanobench::Result> benchmarkResults; @@ -106,6 +106,7 @@ void BenchRunner::RunAll(const Args& args) Bench bench; if (args.sanity_check) { bench.epochs(1).epochIterations(1); + bench.output(nullptr); } bench.name(name); if (args.min_time > 0ms) { diff --git a/src/bench/bench.h b/src/bench/bench.h index 63e1bf67e2..22c63a797b 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 1ac8db19fd..06e32f684f 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,7 +31,7 @@ static void SetupBenchArgs(ArgsManager& argsman) argsman.AddArg("-min-time=<milliseconds>", strprintf("Minimum runtime per benchmark, in milliseconds (default: %d)", DEFAULT_MIN_TIME_MS), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); argsman.AddArg("-output-csv=<output.csv>", "Generate CSV file with the most important benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-output-json=<output.json>", "Generate JSON file with all benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration with no output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-priority-level=<l1,l2,l3>", strprintf("Run benchmarks of one or multiple priority level(s) (%s), default: '%s'", benchmark::ListPriorities(), DEFAULT_PRIORITY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); } diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 09be011fda..8dd4117a3e 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -1,14 +1,14 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 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 <bench/bench.h> #include <consensus/validation.h> #include <crypto/sha256.h> +#include <node/miner.h> #include <test/util/mining.h> #include <test/util/script.h> #include <test/util/setup_common.h> -#include <test/util/wallet.h> #include <txmempool.h> #include <validation.h> @@ -46,5 +46,18 @@ static void AssembleBlock(benchmark::Bench& bench) PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE); }); } +static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench) +{ + FastRandomContext det_rand{true}; + auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()}; + testing_setup->PopulateMempool(det_rand, /*num_transactions=*/1000, /*submit=*/true); + node::BlockAssembler::Options assembler_options; + assembler_options.test_block_validity = false; + + bench.run([&] { + PrepareBlock(testing_setup->m_node, P2WSH_OP_TRUE, assembler_options); + }); +} BENCHMARK(AssembleBlock, benchmark::PriorityLevel::HIGH); +BENCHMARK(BlockAssemblerAddPackageTxns, benchmark::PriorityLevel::LOW); diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index 5d55ed9332..4a3ec67c2b 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,7 +18,6 @@ // (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484) static void CCoinsCaching(benchmark::Bench& bench) { - const ECCVerifyHandle verify_handle; ECC_Start(); FillableSigningProvider keystore; diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp index 9584dd58bb..656fb833e7 100644 --- a/src/bench/chacha20.cpp +++ b/src/bench/chacha20.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/chacha_poly_aead.cpp b/src/bench/chacha_poly_aead.cpp index 15b3a4f310..db88841c32 100644 --- a/src/bench/chacha_poly_aead.cpp +++ b/src/bench/chacha_poly_aead.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index 747279c161..ee76f7b767 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index 8517c9fee2..dfd7275f46 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -25,7 +25,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) // We shouldn't ever be running with the checkqueue on a single core machine. if (GetNumCores() <= 1) return; - const ECCVerifyHandle verify_handle; ECC_Start(); struct PrevectorJob { diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 53d89039a7..087e1442fe 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -99,9 +99,9 @@ static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool) utxo_pool.clear(); CAmount target = 0; for (int i = 0; i < utxos; ++i) { - target += (CAmount)1 << (utxos+i); - add_coin((CAmount)1 << (utxos+i), 2*i, utxo_pool); - add_coin(((CAmount)1 << (utxos+i)) + ((CAmount)1 << (utxos-1-i)), 2*i + 1, utxo_pool); + target += CAmount{1} << (utxos+i); + add_coin(CAmount{1} << (utxos+i), 2*i, utxo_pool); + add_coin((CAmount{1} << (utxos+i)) + (CAmount{1} << (utxos-1-i)), 2*i + 1, utxo_pool); } return target; } diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 162b02f344..bd524e7458 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/descriptors.cpp b/src/bench/descriptors.cpp index 972a6ff953..5d28d26909 100644 --- a/src/bench/descriptors.cpp +++ b/src/bench/descriptors.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,7 +13,6 @@ static void ExpandDescriptor(benchmark::Bench& bench) { - const ECCVerifyHandle verify_handle; ECC_Start(); const auto desc_str = "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))"; diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index 559854ff48..b3799ad1b7 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/examples.cpp b/src/bench/examples.cpp index abef69cc42..671902ef2f 100644 --- a/src/bench/examples.cpp +++ b/src/bench/examples.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp index b795ebff39..51fbe15760 100644 --- a/src/bench/gcs_filter.cpp +++ b/src/bench/gcs_filter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/hashpadding.cpp b/src/bench/hashpadding.cpp index ac5aeebe51..e9d2c25fe3 100644 --- a/src/bench/hashpadding.cpp +++ b/src/bench/hashpadding.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp index ac8262654c..161f9af621 100644 --- a/src/bench/lockedpool.cpp +++ b/src/bench/lockedpool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/logging.cpp b/src/bench/logging.cpp index 49a9e59893..c38552f0b8 100644 --- a/src/bench/logging.cpp +++ b/src/bench/logging.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 29feb42528..735dc92dfb 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -1,12 +1,12 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 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 <bench/bench.h> +#include <kernel/mempool_entry.h> #include <policy/policy.h> #include <test/util/setup_common.h> #include <txmempool.h> -#include <txmempool_entry.h> static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index 1e40d78aa5..80c959cdfb 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -1,12 +1,12 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 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 <bench/bench.h> +#include <kernel/mempool_entry.h> #include <policy/policy.h> #include <test/util/setup_common.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <validation.h> #include <vector> diff --git a/src/bench/merkle_root.cpp b/src/bench/merkle_root.cpp index 4140d67bc7..55409335bd 100644 --- a/src/bench/merkle_root.cpp +++ b/src/bench/merkle_root.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/nanobench.h b/src/bench/nanobench.h index 916a7d61ef..70e02083c9 100644 --- a/src/bench/nanobench.h +++ b/src/bench/nanobench.h @@ -1905,7 +1905,7 @@ PerformanceCounters& performanceCounters() { // Windows version of doNotOptimizeAway // see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307 // see https://github.com/facebook/folly/blob/master/folly/Benchmark.h#L280 -// see https://docs.microsoft.com/en-us/cpp/preprocessor/optimize +// see https://learn.microsoft.com/en-us/cpp/preprocessor/optimize # if defined(_MSC_VER) # pragma optimize("", off) void doNotOptimizeAwaySink(void const*) {} diff --git a/src/bench/peer_eviction.cpp b/src/bench/peer_eviction.cpp index c3e3670de7..e04f3c403c 100644 --- a/src/bench/peer_eviction.cpp +++ b/src/bench/peer_eviction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,7 +40,7 @@ static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_network = NET_IPV4; @@ -51,7 +51,7 @@ static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = false; @@ -67,7 +67,7 @@ static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = false; @@ -85,7 +85,7 @@ static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 50 /* num_candidates */, + /*num_candidates=*/50, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id == 28 || c.id == 47); // 2 localhost @@ -103,7 +103,7 @@ static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 100 /* num_candidates */, + /*num_candidates=*/100, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id >= 55 && c.id < 60); // 5 localhost @@ -121,7 +121,7 @@ static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench) { EvictionProtectionCommon( bench, - 250 /* num_candidates */, + /*num_candidates=*/250, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp index ad5a72ffde..f7d17dfa96 100644 --- a/src/bench/poly1305.cpp +++ b/src/bench/poly1305.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index 9e2e7d11c4..ef1ea1162b 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index 865d99f9e8..de76a87278 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 5a178f308a..f68b6acb5b 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp index 5ae4829d16..e3e1a07c83 100644 --- a/src/bench/rpc_mempool.cpp +++ b/src/bench/rpc_mempool.cpp @@ -1,13 +1,14 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 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 <bench/bench.h> #include <chainparamsbase.h> +#include <kernel/cs_main.h> +#include <kernel/mempool_entry.h> #include <rpc/mempool.h> #include <test/util/setup_common.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <univalue.h> diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp index 8256b5f7ba..8dbbdec28c 100644 --- a/src/bench/util_time.cpp +++ b/src/bench/util_time.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index f0e9db8ba1..757094167a 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,7 +18,6 @@ // modified to measure performance of other types of scripts. static void VerifyScriptBench(benchmark::Bench& bench) { - const ECCVerifyHandle verify_handle; ECC_Start(); const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH}; diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp index 22d99c0e29..ea272b2120 100644 --- a/src/bench/wallet_balance.cpp +++ b/src/bench/wallet_balance.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,7 +7,7 @@ #include <node/context.h> #include <test/util/mining.h> #include <test/util/setup_common.h> -#include <test/util/wallet.h> +#include <wallet/test/util.h> #include <validationinterface.h> #include <wallet/receive.h> #include <wallet/wallet.h> @@ -20,6 +20,8 @@ using wallet::DBErrors; using wallet::GetBalance; using wallet::WALLET_FLAG_DESCRIPTORS; +const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj"; + static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_mine) { const auto test_setup = MakeNoLogFileContext<const TestingSetup>(); diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp index 8f5c50872b..820c9d5d50 100644 --- a/src/bench/wallet_create_tx.cpp +++ b/src/bench/wallet_create_tx.cpp @@ -9,9 +9,9 @@ #include <kernel/chain.h> #include <node/context.h> #include <test/util/setup_common.h> -#include <test/util/wallet.h> #include <validation.h> #include <wallet/spend.h> +#include <wallet/test/util.h> #include <wallet/wallet.h> using wallet::CWallet; @@ -133,11 +133,51 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type }); } +static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType>& output_type) +{ + const auto test_setup = MakeNoLogFileContext<const TestingSetup>(); + CWallet wallet{test_setup->m_node.chain.get(), "", gArgs, CreateMockWalletDatabase()}; + { + LOCK(wallet.cs_wallet); + wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); + wallet.SetupDescriptorScriptPubKeyMans(); + if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false); + } + + // Generate destinations + std::vector<CScript> dest_wallet; + for (auto type : output_type) { + dest_wallet.emplace_back(GetScriptForDestination(getNewDestination(wallet, type))); + } + + // Generate chain; each coinbase will have two outputs to fill-up the wallet + const auto& params = Params(); + unsigned int chain_size = 1000; + for (unsigned int i = 0; i < chain_size / dest_wallet.size(); ++i) { + for (const auto& dest : dest_wallet) { + generateFakeBlock(params, test_setup->m_node, wallet, dest); + } + } + + // Check available balance + auto bal = wallet::GetAvailableBalance(wallet); // Cache + assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY)); + + bench.epochIterations(2).run([&] { + LOCK(wallet.cs_wallet); + const auto& res = wallet::AvailableCoins(wallet); + assert(res.All().size() == (chain_size - COINBASE_MATURITY) * 2); + }); +} + static void WalletCreateTxUseOnlyPresetInputs(benchmark::Bench& bench) { WalletCreateTx(bench, OutputType::BECH32, /*allow_other_inputs=*/false, {{/*num_of_internal_inputs=*/4}}); } static void WalletCreateTxUsePresetInputsAndCoinSelection(benchmark::Bench& bench) { WalletCreateTx(bench, OutputType::BECH32, /*allow_other_inputs=*/true, {{/*num_of_internal_inputs=*/4}}); } +static void WalletAvailableCoins(benchmark::Bench& bench) { AvailableCoins(bench, {OutputType::BECH32M}); } + BENCHMARK(WalletCreateTxUseOnlyPresetInputs, benchmark::PriorityLevel::LOW) BENCHMARK(WalletCreateTxUsePresetInputsAndCoinSelection, benchmark::PriorityLevel::LOW) +BENCHMARK(WalletAvailableCoins, benchmark::PriorityLevel::LOW);
\ No newline at end of file diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 8bfaf3044b..2f7dc53b0c 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -7,7 +7,7 @@ #include <node/context.h> #include <test/util/mining.h> #include <test/util/setup_common.h> -#include <test/util/wallet.h> +#include <wallet/test/util.h> #include <util/translation.h> #include <validationinterface.h> #include <wallet/context.h> @@ -52,30 +52,6 @@ static void AddTx(CWallet& wallet) wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{}); } -static std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options) -{ - auto new_database = CreateMockWalletDatabase(options); - - // Get a cursor to the original database - auto batch = database.MakeBatch(); - batch->StartCursor(); - - // Get a batch for the new database - auto new_batch = new_database->MakeBatch(); - - // Read all records from the original database and write them to the new one - while (true) { - CDataStream key(SER_DISK, CLIENT_VERSION); - CDataStream value(SER_DISK, CLIENT_VERSION); - bool complete; - batch->ReadAtCursor(key, value, complete); - if (complete) break; - new_batch->Write(key, value); - } - - return new_database; -} - static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) { const auto test_setup = MakeNoLogFileContext<TestingSetup>(); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 55fa3116ac..e6e33007d5 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -642,7 +642,7 @@ public: " send Time since last message sent to the peer, in seconds\n" " recv Time since last message received from the peer, in seconds\n" " txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n" - " \"*\" - whether we relay transactions to this peer (relaytxes is false)\n" + " \"*\" - we do not relay transactions to this peer (relaytxes is false)\n" " blk Time since last novel block passing initial validity checks received from the peer, in minutes\n" " hb High-bandwidth BIP152 compact block relay\n" " \".\" (to) - we selected the peer as a high-bandwidth peer\n" @@ -822,7 +822,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co UniValue valReply(UniValue::VSTR); if (!valReply.read(response.body)) throw std::runtime_error("couldn't parse reply from server"); - const UniValue reply = rh->ProcessReply(valReply); + UniValue reply = rh->ProcessReply(valReply); if (reply.empty()) throw std::runtime_error("expected reply to have result, error and id properties"); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 010cac5920..57ca2bbe8a 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -681,8 +681,6 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) class Secp256k1Init { - ECCVerifyHandle globalVerifyHandle; - public: Secp256k1Init() { ECC_Start(); diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp index fb184c0486..7327875b64 100644 --- a/src/bitcoin-util.cpp +++ b/src/bitcoin-util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -82,13 +82,12 @@ static int AppInitUtil(ArgsManager& args, int argc, char* argv[]) return CONTINUE_EXECUTION; } -static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offset, uint32_t step, std::atomic<bool>& found) +static void grind_task(uint32_t nBits, CBlockHeader header, uint32_t offset, uint32_t step, std::atomic<bool>& found, uint32_t& proposed_nonce) { arith_uint256 target; bool neg, over; target.SetCompact(nBits, &neg, &over); if (target == 0 || neg || over) return; - CBlockHeader header = header_orig; // working copy header.nNonce = offset; uint32_t finish = std::numeric_limits<uint32_t>::max() - step; @@ -99,7 +98,7 @@ static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offse do { if (UintToArith256(header.GetHash()) <= target) { if (!found.exchange(true)) { - header_orig.nNonce = header.nNonce; + proposed_nonce = header.nNonce; } return; } @@ -123,16 +122,19 @@ static int Grind(const std::vector<std::string>& args, std::string& strPrint) uint32_t nBits = header.nBits; std::atomic<bool> found{false}; + uint32_t proposed_nonce{}; std::vector<std::thread> threads; int n_tasks = std::max(1u, std::thread::hardware_concurrency()); for (int i = 0; i < n_tasks; ++i) { - threads.emplace_back( grind_task, nBits, std::ref(header), i, n_tasks, std::ref(found) ); + threads.emplace_back(grind_task, nBits, header, i, n_tasks, std::ref(found), std::ref(proposed_nonce)); } for (auto& t : threads) { t.join(); } - if (!found) { + if (found) { + header.nNonce = proposed_nonce; + } else { strPrint = "Could not satisfy difficulty target"; return EXIT_FAILURE; } diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 78c1a2060c..12cb60e6de 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -130,7 +130,6 @@ MAIN_FUNCTION return EXIT_FAILURE; } - ECCVerifyHandle globalVerifyHandle; ECC_Start(); if (!wallet::WalletTool::ExecuteWalletToolFunc(args, command->command)) { return EXIT_FAILURE; diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index d8d4e34e47..07002cc8a3 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index f96353510f..bcb86d75cc 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blockencodings.h b/src/blockencodings.h index 67c4e57156..e60c1e3db4 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 85929747be..fc6dde20f9 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blockfilter.h b/src/blockfilter.h index 0cb627d9df..fb5114edb3 100644 --- a/src/blockfilter.h +++ b/src/blockfilter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/chain.cpp b/src/chain.cpp index 66a0830394..82007a8a1e 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/chain.h b/src/chain.h index 2d3b084b9b..f5dd0fd315 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,7 @@ #include <arith_uint256.h> #include <consensus/params.h> #include <flatfile.h> +#include <kernel/cs_main.h> #include <primitives/block.h> #include <sync.h> #include <uint256.h> @@ -38,8 +39,6 @@ static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; */ static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60; -extern RecursiveMutex cs_main; - class CBlockFileInfo { public: @@ -213,10 +212,6 @@ public: //! (memory only) Maximum nTime in the chain up to and including this block. unsigned int nTimeMax{0}; - CBlockIndex() - { - } - explicit CBlockIndex(const CBlockHeader& block) : nVersion{block.nVersion}, hashMerkleRoot{block.hashMerkleRoot}, @@ -355,6 +350,24 @@ public: //! Efficiently find an ancestor of this block. CBlockIndex* GetAncestor(int height); const CBlockIndex* GetAncestor(int height) const; + + CBlockIndex() = default; + ~CBlockIndex() = default; + +protected: + //! CBlockIndex should not allow public copy construction because equality + //! comparison via pointer is very common throughout the codebase, making + //! use of copy a footgun. Also, use of copies do not have the benefit + //! of simplifying lifetime considerations due to attributes like pprev and + //! pskip, which are at risk of becoming dangling pointers in a copied + //! instance. + //! + //! We declare these protected instead of simply deleting them so that + //! CDiskBlockIndex can reuse copy construction. + CBlockIndex(const CBlockIndex&) = default; + CBlockIndex& operator=(const CBlockIndex&) = delete; + CBlockIndex(CBlockIndex&&) = delete; + CBlockIndex& operator=(CBlockIndex&&) = delete; }; arith_uint256 GetBlockProof(const CBlockIndex& block); diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c6d4eee7b9..19b5c332f4 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/checkqueue.h b/src/checkqueue.h index c4a64444e9..d83f717fb7 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 192e9c52bc..e7d63e34c6 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/clientversion.h b/src/clientversion.h index d2efd7dcab..9da0cd0b39 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/coins.cpp b/src/coins.cpp index 5983a8a39f..976118e23c 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/coins.h b/src/coins.h index 67fecc9785..b0d6bdf333 100644 --- a/src/coins.h +++ b/src/coins.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/common/bloom.cpp b/src/common/bloom.cpp index aa3fcf1ce2..3ba0414b31 100644 --- a/src/common/bloom.cpp +++ b/src/common/bloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/common/interfaces.cpp b/src/common/interfaces.cpp new file mode 100644 index 0000000000..c8bbe2b3c0 --- /dev/null +++ b/src/common/interfaces.cpp @@ -0,0 +1,53 @@ +// Copyright (c) 2021-2022 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 <interfaces/echo.h> +#include <interfaces/handler.h> + +#include <boost/signals2/connection.hpp> +#include <memory> +#include <utility> + +namespace common { +namespace { +class CleanupHandler : public interfaces::Handler +{ +public: + explicit CleanupHandler(std::function<void()> cleanup) : m_cleanup(std::move(cleanup)) {} + ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } + void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } + std::function<void()> m_cleanup; +}; + +class SignalHandler : public interfaces::Handler +{ +public: + explicit SignalHandler(boost::signals2::connection connection) : m_connection(std::move(connection)) {} + + void disconnect() override { m_connection.disconnect(); } + + boost::signals2::scoped_connection m_connection; +}; + +class EchoImpl : public interfaces::Echo +{ +public: + std::string echo(const std::string& echo) override { return echo; } +}; +} // namespace +} // namespace common + +namespace interfaces { +std::unique_ptr<Handler> MakeCleanupHandler(std::function<void()> cleanup) +{ + return std::make_unique<common::CleanupHandler>(std::move(cleanup)); +} + +std::unique_ptr<Handler> MakeSignalHandler(boost::signals2::connection connection) +{ + return std::make_unique<common::SignalHandler>(std::move(connection)); +} + +std::unique_ptr<Echo> MakeEcho() { return std::make_unique<common::EchoImpl>(); } +} // namespace interfaces diff --git a/src/common/url.cpp b/src/common/url.cpp index 5200d55096..053e1a825c 100644 --- a/src/common/url.cpp +++ b/src/common/url.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/common/url.h b/src/common/url.h index 7bbd8b60de..b16b8241af 100644 --- a/src/common/url.h +++ b/src/common/url.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h index 2f4232fa5c..9ee71ef267 100644 --- a/src/compat/byteswap.h +++ b/src/compat/byteswap.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/compat.h b/src/compat/compat.h index cc37797577..88f58120b8 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/cpuid.h b/src/compat/cpuid.h index e78c1ce6d1..4237c8ebc9 100644 --- a/src/compat/cpuid.h +++ b/src/compat/cpuid.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/endian.h b/src/compat/endian.h index bdd8b84c1b..882de2dbf0 100644 --- a/src/compat/endian.h +++ b/src/compat/endian.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/stdin.cpp b/src/compat/stdin.cpp index 61d66e39f2..c11763f68f 100644 --- a/src/compat/stdin.cpp +++ b/src/compat/stdin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -58,7 +58,7 @@ bool StdinReady() return false; #else struct pollfd fds; - fds.fd = 0; /* this is STDIN */ + fds.fd = STDIN_FILENO; fds.events = POLLIN; return poll(&fds, 1, 0) == 1; #endif diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 10bdbf31a8..384f70bc10 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/consensus/params.h b/src/consensus/params.h index 7c35222713..be92556611 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index 1209c0faa5..d2cf792cf3 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -63,8 +63,8 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); /** * Calculates the block height and previous block's median time past at * which the transaction will be considered final in the context of BIP 68. - * Also removes from the vector of input heights any entries which did not - * correspond to sequence locked inputs as they do not affect the calculation. + * For each input that is not sequence locked, the corresponding entries in + * prevHeights are set to 0 as they do not affect the calculation. */ std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block); diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 9c0aa09356..ad8ee676b2 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_io.h b/src/core_io.h index c91c8199d8..33e1ad82fc 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_read.cpp b/src/core_read.cpp index ec21a2f7f4..7bab171c89 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_write.cpp b/src/core_write.cpp index cfd4cb1b49..91a6eb2864 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp index c7e12b0612..25d7baa8cc 100644 --- a/src/crypto/chacha20.cpp +++ b/src/crypto/chacha20.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h index de16a77878..624c083191 100644 --- a/src/crypto/chacha20.h +++ b/src/crypto/chacha20.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/chacha_poly_aead.cpp b/src/crypto/chacha_poly_aead.cpp index f736b2d867..6511f46adc 100644 --- a/src/crypto/chacha_poly_aead.cpp +++ b/src/crypto/chacha_poly_aead.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/hkdf_sha256_32.h b/src/crypto/hkdf_sha256_32.h index 878b03a37f..d373520300 100644 --- a/src/crypto/hkdf_sha256_32.h +++ b/src/crypto/hkdf_sha256_32.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/hmac_sha256.h b/src/crypto/hmac_sha256.h index 9c25edd7c1..abd731d1fe 100644 --- a/src/crypto/hmac_sha256.h +++ b/src/crypto/hmac_sha256.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/hmac_sha512.h b/src/crypto/hmac_sha512.h index 6acce8992e..8fa55d2844 100644 --- a/src/crypto/hmac_sha512.h +++ b/src/crypto/hmac_sha512.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp index 7d14b7938e..26f0248663 100644 --- a/src/crypto/muhash.cpp +++ b/src/crypto/muhash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/poly1305.h b/src/crypto/poly1305.h index c80faada7e..650e35bbca 100644 --- a/src/crypto/poly1305.h +++ b/src/crypto/poly1305.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/ripemd160.h b/src/crypto/ripemd160.h index f1d89b8407..ae9c339181 100644 --- a/src/crypto/ripemd160.h +++ b/src/crypto/ripemd160.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2016 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h index 6ef0187efd..4bd6c331a8 100644 --- a/src/crypto/sha1.h +++ b/src/crypto/sha1.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2016 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index 196f81ea16..7cd5b3661b 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h index 24bd1f2e7e..9fd73becfd 100644 --- a/src/crypto/sha256.h +++ b/src/crypto/sha256.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/sha256_sse4.cpp b/src/crypto/sha256_sse4.cpp index bc69703607..f4557291ce 100644 --- a/src/crypto/sha256_sse4.cpp +++ b/src/crypto/sha256_sse4.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/crypto/sha256_x86_shani.cpp b/src/crypto/sha256_x86_shani.cpp index a82802199f..e3143a55c2 100644 --- a/src/crypto/sha256_x86_shani.cpp +++ b/src/crypto/sha256_x86_shani.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/crypto/sha3.h b/src/crypto/sha3.h index 78608eae76..e8e91f1ee4 100644 --- a/src/crypto/sha3.h +++ b/src/crypto/sha3.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index 59b79609dd..8a822e0e7e 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/sha512.h b/src/crypto/sha512.h index 7356dff6d9..d8fa8d2e39 100644 --- a/src/crypto/sha512.h +++ b/src/crypto/sha512.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/siphash.cpp b/src/crypto/siphash.cpp index 2e90c393e1..2f7555d02e 100644 --- a/src/crypto/siphash.cpp +++ b/src/crypto/siphash.cpp @@ -119,10 +119,10 @@ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val) SIPROUND; SIPROUND; v0 ^= d; - v3 ^= ((uint64_t)4) << 59; + v3 ^= (uint64_t{4}) << 59; SIPROUND; SIPROUND; - v0 ^= ((uint64_t)4) << 59; + v0 ^= (uint64_t{4}) << 59; v2 ^= 0xFF; SIPROUND; SIPROUND; @@ -159,7 +159,7 @@ uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint3 SIPROUND; SIPROUND; v0 ^= d; - d = (((uint64_t)36) << 56) | extra; + d = ((uint64_t{36}) << 56) | extra; v3 ^= d; SIPROUND; SIPROUND; diff --git a/src/cuckoocache.h b/src/cuckoocache.h index 61f553806e..6adcc74516 100644 --- a/src/cuckoocache.h +++ b/src/cuckoocache.h @@ -344,7 +344,7 @@ public: collection_flags.setup(size); epoch_flags.resize(size); // Set to 45% as described above - epoch_size = std::max((uint32_t)1, (45 * size) / 100); + epoch_size = std::max(uint32_t{1}, (45 * size) / 100); // Initially set to wait for a whole epoch epoch_heuristic_counter = epoch_size; return size; diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 7f45e35aef..6efaf2ec19 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 1052da01d5..3d3eee32ce 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/deploymentstatus.cpp b/src/deploymentstatus.cpp index 3a524af29e..71f2702430 100644 --- a/src/deploymentstatus.cpp +++ b/src/deploymentstatus.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h index 9f5919f71b..03d3c531cc 100644 --- a/src/deploymentstatus.h +++ b/src/deploymentstatus.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/external_signer.cpp b/src/external_signer.cpp index f255834830..8a3e17a292 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/flatfile.cpp b/src/flatfile.cpp index 0fecf4f504..d6e84d02c1 100644 --- a/src/flatfile.cpp +++ b/src/flatfile.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/fs.cpp b/src/fs.cpp index 07cce269ed..0429b8cd0f 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/hash.cpp b/src/hash.cpp index 06caaac6ee..1ece8c5a79 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2021 The Bitcoin Core developers +// Copyright (c) 2013-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/hash.h b/src/hash.h index b1ff3acc7d..6500f1c709 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,11 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 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_HASH_H #define BITCOIN_HASH_H +#include <attributes.h> #include <crypto/common.h> #include <crypto/ripemd160.h> #include <crypto/sha256.h> @@ -199,6 +200,30 @@ public: } }; +/** Writes data to an underlying source stream, while hashing the written data. */ +template <typename Source> +class HashedSourceWriter : public CHashWriter +{ +private: + Source& m_source; + +public: + explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : CHashWriter{source.GetType(), source.GetVersion()}, m_source{source} {} + + void write(Span<const std::byte> src) + { + m_source.write(src); + CHashWriter::write(src); + } + + template <typename T> + HashedSourceWriter& operator<<(const T& obj) + { + ::Serialize(*this, obj); + return *this; + } +}; + /** Compute the 256-bit hash of an object's serialization. */ template<typename T> uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 4e7e72b037..33a75df68e 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 1a19555f76..720f5c9353 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -192,19 +192,16 @@ std::string RequestMethodString(HTTPRequest::RequestMethod m) switch (m) { case HTTPRequest::GET: return "GET"; - break; case HTTPRequest::POST: return "POST"; - break; case HTTPRequest::HEAD: return "HEAD"; - break; case HTTPRequest::PUT: return "PUT"; - break; - default: + case HTTPRequest::UNKNOWN: return "unknown"; - } + } // no default case, so the compiler can warn about missing cases + assert(false); } /** HTTP request callback */ @@ -282,7 +279,7 @@ static void http_reject_request_cb(struct evhttp_request* req, void*) } /** Event dispatcher thread */ -static bool ThreadHTTP(struct event_base* base) +static void ThreadHTTP(struct event_base* base) { util::ThreadRename("http"); SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_HTTP_SERVER); @@ -290,7 +287,6 @@ static bool ThreadHTTP(struct event_base* base) event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() LogPrint(BCLog::HTTP, "Exited http event loop\n"); - return event_base_got_break(base) == 0; } /** Bind HTTP server to specified addresses */ @@ -626,19 +622,14 @@ HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() const switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: return GET; - break; case EVHTTP_REQ_POST: return POST; - break; case EVHTTP_REQ_HEAD: return HEAD; - break; case EVHTTP_REQ_PUT: return PUT; - break; default: return UNKNOWN; - break; } } diff --git a/src/httpserver.h b/src/httpserver.h index 5ab3f18927..036a39a023 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/i2p.cpp b/src/i2p.cpp index 28be8009dc..586ee649a7 100644 --- a/src/i2p.cpp +++ b/src/i2p.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,6 +18,7 @@ #include <util/spanparsing.h> #include <util/strencodings.h> #include <util/system.h> +#include <util/threadinterrupt.h> #include <chrono> #include <memory> @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,8 +9,8 @@ #include <fs.h> #include <netaddress.h> #include <sync.h> -#include <threadinterrupt.h> #include <util/sock.h> +#include <util/threadinterrupt.h> #include <memory> #include <optional> diff --git a/src/index/base.cpp b/src/index/base.cpp index 3eea09b17d..a8b8cbe8a9 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/index/base.h b/src/index/base.h index 349178a535..231f36b605 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,7 +7,7 @@ #include <dbwrapper.h> #include <interfaces/chain.h> -#include <threadinterrupt.h> +#include <util/threadinterrupt.h> #include <validationinterface.h> #include <string> diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index 292e11c874..07b4cdc06b 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h index 9e69388dc8..ce1961c776 100644 --- a/src/index/blockfilterindex.h +++ b/src/index/blockfilterindex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index d3559b1b75..8cece7d78d 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -144,17 +144,13 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block) } } - // TODO: Deduplicate BIP30 related code - bool is_bip30_block{(block.height == 91722 && block.hash == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) || - (block.height == 91812 && block.hash == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))}; - // Add the new utxos created from the block assert(block.data); for (size_t i = 0; i < block.data->vtx.size(); ++i) { const auto& tx{block.data->vtx.at(i)}; // Skip duplicate txid coinbase transactions (BIP30). - if (is_bip30_block && tx->IsCoinBase()) { + if (IsBIP30Unspendable(*pindex) && tx->IsCoinBase()) { m_total_unspendable_amount += block_subsidy; m_total_unspendables_bip30 += block_subsidy; continue; diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h index aa0d7f9fd5..21ce4c4767 100644 --- a/src/index/coinstatsindex.h +++ b/src/index/coinstatsindex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index a4fe1b611e..25ccc3e636 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/index/txindex.h b/src/index/txindex.h index 4cea35045d..ef835fe5d7 100644 --- a/src/index/txindex.h +++ b/src/index/txindex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init.cpp b/src/init.cpp index 6f44ed6c3d..685583bcbd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -67,7 +67,6 @@ #include <torcontrol.h> #include <txdb.h> #include <txmempool.h> -#include <txorphanage.h> #include <util/asmap.h> #include <util/check.h> #include <util/moneystr.h> @@ -127,8 +126,9 @@ using node::fPruneMode; using node::fReindex; using node::nPruneTarget; -static const bool DEFAULT_PROXYRANDOMIZE = true; -static const bool DEFAULT_REST_ENABLE = false; +static constexpr bool DEFAULT_PROXYRANDOMIZE{true}; +static constexpr bool DEFAULT_REST_ENABLE{false}; +static constexpr bool DEFAULT_I2P_ACCEPT_INCOMING{true}; #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for @@ -191,8 +191,24 @@ static fs::path GetPidFile(const ArgsManager& args) // shutdown thing. // +#if HAVE_SYSTEM +static void ShutdownNotify(const ArgsManager& args) +{ + std::vector<std::thread> threads; + for (const auto& cmd : args.GetArgs("-shutdownnotify")) { + threads.emplace_back(runCommand, cmd); + } + for (auto& t : threads) { + t.join(); + } +} +#endif + void Interrupt(NodeContext& node) { +#if HAVE_SYSTEM + ShutdownNotify(*node.args); +#endif InterruptHTTPServer(); InterruptHTTPRPC(); InterruptRPC(); @@ -441,6 +457,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #if HAVE_SYSTEM argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-shutdownnotify=<cmd>", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif #ifndef WIN32 argsman.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -474,10 +491,11 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-i2pacceptincoming", "If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); // TODO: remove the sentence "Nodes not using ... incoming connections." once the changes from // https://github.com/bitcoin/bitcoin/pull/23542 have become widespread. argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, signet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); @@ -486,7 +504,6 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-torcontrol=<ip>:<port>", strprintf("Tor control port to use if onion listening enabled (default: %s)", DEFAULT_TOR_CONTROL), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-torpassword=<pass>", "Tor control port password (default: empty)", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::CONNECTION); @@ -1572,7 +1589,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) { - g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /* cache size */ 0, false, fReindex); + g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, fReindex); if (!g_coin_stats_index->Start()) { return false; } @@ -1830,7 +1847,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) SetReachable(NET_I2P, false); } - connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", true); + connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", DEFAULT_I2P_ACCEPT_INCOMING); if (!node.connman->Start(*node.scheduler, connOptions)) { return false; diff --git a/src/init.h b/src/init.h index e8e6a55eba..8c5b2e77d3 100644 --- a/src/init.h +++ b/src/init.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp index 2fa4add4e5..100b4ef7ee 100644 --- a/src/init/bitcoin-gui.cpp +++ b/src/init/bitcoin-gui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 78bc3e5980..1418e63777 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp index bb3bb945d0..e27be0e598 100644 --- a/src/init/bitcoin-qt.cpp +++ b/src/init/bitcoin-qt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/bitcoin-wallet.cpp b/src/init/bitcoin-wallet.cpp index c8d499da10..f3a9ea267c 100644 --- a/src/init/bitcoin-wallet.cpp +++ b/src/init/bitcoin-wallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index b473ebb805..7ad1f64e64 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/common.cpp b/src/init/common.cpp index f2d2c5640a..e1a37d7db9 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init/common.h b/src/init/common.h index 53c860c297..44c3a502ee 100644 --- a/src/init/common.h +++ b/src/init/common.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 7a3d88b18f..a3fa753a98 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -268,8 +268,8 @@ public: { public: virtual ~Notifications() {} - virtual void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {} - virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {} + virtual void transactionAddedToMempool(const CTransactionRef& tx) {} + virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {} virtual void blockConnected(const BlockInfo& block) {} virtual void blockDisconnected(const BlockInfo& block) {} virtual void updatedBlockTip() {} diff --git a/src/interfaces/echo.cpp b/src/interfaces/echo.cpp deleted file mode 100644 index 9bbb42217b..0000000000 --- a/src/interfaces/echo.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2021 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 <interfaces/echo.h> - -#include <memory> - -namespace interfaces { -namespace { -class EchoImpl : public Echo -{ -public: - std::string echo(const std::string& echo) override { return echo; } -}; -} // namespace -std::unique_ptr<Echo> MakeEcho() { return std::make_unique<EchoImpl>(); } -} // namespace interfaces diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp deleted file mode 100644 index adb7031cbc..0000000000 --- a/src/interfaces/handler.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2018-2021 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 <interfaces/handler.h> - - -#include <boost/signals2/connection.hpp> -#include <utility> - -namespace interfaces { -namespace { - -class HandlerImpl : public Handler -{ -public: - explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} - - void disconnect() override { m_connection.disconnect(); } - - boost::signals2::scoped_connection m_connection; -}; - -class CleanupHandler : public Handler -{ -public: - explicit CleanupHandler(std::function<void()> cleanup) : m_cleanup(std::move(cleanup)) {} - ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } - void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; } - std::function<void()> m_cleanup; -}; - -} // namespace - -std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection) -{ - return std::make_unique<HandlerImpl>(std::move(connection)); -} - -std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup) -{ - return std::make_unique<CleanupHandler>(std::move(cleanup)); -} - -} // namespace interfaces diff --git a/src/interfaces/handler.h b/src/interfaces/handler.h index 11baf9dd65..7751d82347 100644 --- a/src/interfaces/handler.h +++ b/src/interfaces/handler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -29,10 +29,10 @@ public: }; //! Return handler wrapping a boost signal connection. -std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection); +std::unique_ptr<Handler> MakeSignalHandler(boost::signals2::connection connection); //! Return handler wrapping a cleanup function. -std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup); +std::unique_ptr<Handler> MakeCleanupHandler(std::function<void()> cleanup); } // namespace interfaces diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp deleted file mode 100644 index f0f8aa5fed..0000000000 --- a/src/interfaces/init.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2021 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 <interfaces/chain.h> -#include <interfaces/echo.h> -#include <interfaces/init.h> -#include <interfaces/node.h> -#include <interfaces/wallet.h> - -namespace interfaces { -std::unique_ptr<Node> Init::makeNode() { return {}; } -std::unique_ptr<Chain> Init::makeChain() { return {}; } -std::unique_ptr<WalletLoader> Init::makeWalletLoader(Chain& chain) { return {}; } -std::unique_ptr<Echo> Init::makeEcho() { return {}; } -Ipc* Init::ipc() { return nullptr; } -} // namespace interfaces diff --git a/src/interfaces/init.h b/src/interfaces/init.h index 2153076366..addc45aa26 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -1,10 +1,15 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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_INTERFACES_INIT_H #define BITCOIN_INTERFACES_INIT_H +#include <interfaces/chain.h> +#include <interfaces/echo.h> +#include <interfaces/node.h> +#include <interfaces/wallet.h> + #include <memory> namespace node { @@ -12,11 +17,7 @@ struct NodeContext; } // namespace node namespace interfaces { -class Chain; -class Echo; class Ipc; -class Node; -class WalletLoader; //! Initial interface created when a process is first started, and used to give //! and get access to other interfaces (Node, Chain, Wallet, etc). @@ -29,11 +30,11 @@ class Init { public: virtual ~Init() = default; - virtual std::unique_ptr<Node> makeNode(); - virtual std::unique_ptr<Chain> makeChain(); - virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain); - virtual std::unique_ptr<Echo> makeEcho(); - virtual Ipc* ipc(); + virtual std::unique_ptr<Node> makeNode() { return nullptr; } + virtual std::unique_ptr<Chain> makeChain() { return nullptr; } + virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain) { return nullptr; } + virtual std::unique_ptr<Echo> makeEcho() { return nullptr; } + virtual Ipc* ipc() { return nullptr; } }; //! Return implementation of Init interface for the node process. If the argv diff --git a/src/interfaces/node.h b/src/interfaces/node.h index dbdb21eb91..ce6c44e2bc 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 1148dc7e4c..86707b20b1 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/ipc/interfaces.cpp b/src/ipc/interfaces.cpp index ee0d4123ce..396f3ddf25 100644 --- a/src/ipc/interfaces.cpp +++ b/src/ipc/interfaces.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp index 9474ad2c4a..4dc88ae44b 100644 --- a/src/ipc/process.cpp +++ b/src/ipc/process.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/kernel/context.cpp b/src/kernel/context.cpp index 15413c1840..1205da869e 100644 --- a/src/kernel/context.cpp +++ b/src/kernel/context.cpp @@ -21,12 +21,10 @@ Context::Context() LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); RandomInit(); ECC_Start(); - ecc_verify_handle.reset(new ECCVerifyHandle()); } Context::~Context() { - ecc_verify_handle.reset(); ECC_Stop(); } diff --git a/src/kernel/context.h b/src/kernel/context.h index 9746ef994b..f11b7b54f0 100644 --- a/src/kernel/context.h +++ b/src/kernel/context.h @@ -7,8 +7,6 @@ #include <memory> -class ECCVerifyHandle; - namespace kernel { //! Context struct holding the kernel library's logically global state, and //! passed to external libbitcoin_kernel functions which need access to this @@ -18,8 +16,6 @@ namespace kernel { //! State stored directly in this struct should be simple. More complex state //! should be stored to std::unique_ptr members pointing to opaque types. struct Context { - std::unique_ptr<ECCVerifyHandle> ecc_verify_handle; - //! Declare default constructor and destructor that are not inline, so code //! instantiating the kernel::Context struct doesn't need to #include class //! definitions for all the unique_ptr members. diff --git a/src/kernel/cs_main.cpp b/src/kernel/cs_main.cpp new file mode 100644 index 0000000000..c3a08c9695 --- /dev/null +++ b/src/kernel/cs_main.cpp @@ -0,0 +1,7 @@ +// Copyright (c) 2023 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 <sync.h> + +RecursiveMutex cs_main; diff --git a/src/kernel/cs_main.h b/src/kernel/cs_main.h new file mode 100644 index 0000000000..8d03903b8e --- /dev/null +++ b/src/kernel/cs_main.h @@ -0,0 +1,22 @@ +// Copyright (c) 2023 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_KERNEL_CS_MAIN_H +#define BITCOIN_KERNEL_CS_MAIN_H + +#include <sync.h> + +/** + * Mutex to guard access to validation specific variables, such as reading + * or changing the chainstate. + * + * This may also need to be locked when updating the transaction pool, e.g. on + * AcceptToMemoryPool. See CTxMemPool::cs comment for details. + * + * The transaction pool has a separate lock to allow reading from it and the + * chainstate at the same time. + */ +extern RecursiveMutex cs_main; + +#endif // BITCOIN_KERNEL_CS_MAIN_H diff --git a/src/txmempool_entry.h b/src/kernel/mempool_entry.h index dd71833200..e1ba4296ef 100644 --- a/src/txmempool_entry.h +++ b/src/kernel/mempool_entry.h @@ -2,8 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_TXMEMPOOL_ENTRY_H -#define BITCOIN_TXMEMPOOL_ENTRY_H +#ifndef BITCOIN_KERNEL_MEMPOOL_ENTRY_H +#define BITCOIN_KERNEL_MEMPOOL_ENTRY_H #include <consensus/amount.h> #include <consensus/validation.h> @@ -171,4 +171,4 @@ public: mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms }; -#endif // BITCOIN_TXMEMPOOL_ENTRY_H +#endif // BITCOIN_KERNEL_MEMPOOL_ENTRY_H diff --git a/src/key.cpp b/src/key.cpp index 199808505d..33913ed461 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -233,7 +233,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool gr secp256k1_pubkey pk; ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pk, begin()); assert(ret); - ret = secp256k1_ecdsa_verify(GetVerifyContext(), &sig, hash.begin(), &pk); + ret = secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pk); assert(ret); return true; } @@ -268,9 +268,9 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) secp256k1_pubkey epk, rpk; ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &epk, begin()); assert(ret); - ret = secp256k1_ecdsa_recover(GetVerifyContext(), &rpk, &rsig, hash.begin()); + ret = secp256k1_ecdsa_recover(secp256k1_context_static, &rpk, &rsig, hash.begin()); assert(ret); - ret = secp256k1_ec_pubkey_cmp(GetVerifyContext(), &epk, &rpk); + ret = secp256k1_ec_pubkey_cmp(secp256k1_context_static, &epk, &rpk); assert(ret == 0); return true; } @@ -286,14 +286,14 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2 unsigned char pubkey_bytes[32]; if (!secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey)) return false; uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root); - if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false; + if (!secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, &keypair, tweak.data())) return false; } bool ret = secp256k1_schnorrsig_sign32(secp256k1_context_sign, sig.data(), hash.data(), &keypair, aux.data()); if (ret) { // Additional verification step to prevent using a potentially corrupted signature secp256k1_xonly_pubkey pubkey_verify; - ret = secp256k1_keypair_xonly_pub(GetVerifyContext(), &pubkey_verify, nullptr, &keypair); - ret &= secp256k1_schnorrsig_verify(GetVerifyContext(), sig.data(), hash.begin(), 32, &pubkey_verify); + ret = secp256k1_keypair_xonly_pub(secp256k1_context_static, &pubkey_verify, nullptr, &keypair); + ret &= secp256k1_schnorrsig_verify(secp256k1_context_static, sig.data(), hash.begin(), 32, &pubkey_verify); } if (!ret) memory_cleanse(sig.data(), sig.size()); memory_cleanse(&keypair, sizeof(keypair)); @@ -392,7 +392,7 @@ bool ECC_InitSanityCheck() { void ECC_Start() { assert(secp256k1_context_sign == nullptr); - secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); assert(ctx != nullptr); { @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/logging.cpp b/src/logging.cpp index ed0c2a56a5..298ec9c013 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/logging.h b/src/logging.h index 14a0f08f8d..35fb598cef 100644 --- a/src/logging.h +++ b/src/logging.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/logging/timer.h b/src/logging/timer.h index d954e46301..ea0821dede 100644 --- a/src/logging/timer.h +++ b/src/logging/timer.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/mapport.cpp b/src/mapport.cpp index 6262e51879..e6a473c185 100644 --- a/src/mapport.cpp +++ b/src/mapport.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,10 +13,10 @@ #include <net.h> #include <netaddress.h> #include <netbase.h> -#include <threadinterrupt.h> #include <util/syscall_sandbox.h> #include <util/system.h> #include <util/thread.h> +#include <util/threadinterrupt.h> #ifdef USE_NATPMP #include <compat/compat.h> diff --git a/src/memusage.h b/src/memusage.h index fd85a7956c..9755be0ff5 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/net.cpp b/src/net.cpp index 3c28b9eddf..960d0ee841 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,6 +31,7 @@ #include <util/syscall_sandbox.h> #include <util/system.h> #include <util/thread.h> +#include <util/threadinterrupt.h> #include <util/trace.h> #include <util/translation.h> @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,10 +24,10 @@ #include <span.h> #include <streams.h> #include <sync.h> -#include <threadinterrupt.h> #include <uint256.h> #include <util/check.h> #include <util/sock.h> +#include <util/threadinterrupt.h> #include <atomic> #include <condition_variable> diff --git a/src/net_permissions.h b/src/net_permissions.h index 662464083c..b7f3bffe1c 100644 --- a/src/net_permissions.h +++ b/src/net_permissions.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -35,7 +35,8 @@ enum class NetPermissionFlags : uint32_t { // unlimited amounts of addrs. Addr = (1U << 7), - // True if the user did not specifically set fine grained permissions + // True if the user did not specifically set fine-grained permissions with + // the -whitebind or -whitelist configuration options. Implicit = (1U << 31), All = BloomFilter | ForceRelay | Relay | NoBan | Mempool | Download | Addr, }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0d5be42e0e..21a49bdebd 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,7 @@ #include <hash.h> #include <headerssync.h> #include <index/blockfilterindex.h> +#include <kernel/mempool_entry.h> #include <merkleblock.h> #include <netbase.h> #include <netmessagemaker.h> @@ -34,7 +35,6 @@ #include <timedata.h> #include <tinyformat.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <txorphanage.h> #include <txrequest.h> #include <util/check.h> // For NDEBUG compile time check @@ -295,7 +295,7 @@ struct Peer { std::atomic<std::chrono::seconds> m_last_mempool_req{0s}; /** The next time after which we will send an `inv` message containing * transaction announcements to this peer. */ - std::chrono::microseconds m_next_inv_send_time GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0}; + std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0}; /** Minimum fee rate with which to filter transaction announcements to this node. See BIP133. */ std::atomic<CAmount> m_fee_filter_received{0}; @@ -365,9 +365,6 @@ struct Peer { /** Total number of addresses that were processed (excludes rate-limited ones). */ std::atomic<uint64_t> m_addr_processed{0}; - /** Set of txids to reconsider once their parent transactions have been accepted **/ - std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans); - /** Whether we've sent this peer a getheaders in response to an inv prior to initial-headers-sync completing */ bool m_inv_triggered_getheaders_before_sync GUARDED_BY(NetEventsInterface::g_msgproc_mutex){false}; @@ -584,8 +581,17 @@ private: */ bool MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer); - void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + /** + * Reconsider orphan transactions after a parent has been accepted to the mempool. + * + * @peer[in] peer The peer whose orphan transactions we will reconsider. Generally only one + * orphan will be reconsidered on each call of this function. This set + * may be added to if accepting an orphan causes its children to be + * reconsidered. + * @return True if there are still orphans in this peer's work set. + */ + bool ProcessOrphanTx(Peer& peer) + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); /** Process a single headers message from a peer. * * @param[in] pfrom CNode of the peer @@ -655,9 +661,9 @@ private: */ bool MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& locator, Peer& peer) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); /** Potentially fetch blocks from this peer upon receipt of a new headers tip */ - void HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex* pindexLast); + void HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex& last_header); /** Update peer state based on received headers message */ - void UpdatePeerStateForReceivedHeaders(CNode& pfrom, const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers); + void UpdatePeerStateForReceivedHeaders(CNode& pfrom, const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers); void SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req); @@ -919,14 +925,14 @@ private: /** Storage for orphan information */ TxOrphanage m_orphanage; - void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); /** Orphan/conflicted/etc transactions that are kept for compact block reconstruction. * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of * these are kept in a ring buffer */ - std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans); + std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex); /** Offset into vExtraTxnForCompact to insert the next tx */ - size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; + size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0; /** Check whether the last unknown block a peer advertised is not yet known. */ void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -1490,7 +1496,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) for (const QueuedBlock& entry : state->vBlocksInFlight) { mapBlocksInFlight.erase(entry.pindex->GetBlockHash()); } - WITH_LOCK(g_cs_orphans, m_orphanage.EraseForPeer(nodeid)); + m_orphanage.EraseForPeer(nodeid); m_txrequest.DisconnectedPeer(nodeid); if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid); m_num_preferred_download_peers -= state->fPreferredDownload; @@ -1737,6 +1743,8 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl LOCK(cs_main); // Mark block as in-flight unless it already is (for this peer). + // If the peer does not send us a block, vBlocksInFlight remains non-empty, + // causing us to timeout and disconnect. // If a block was already in-flight for a different peer, its BLOCKTXN // response will be dropped. if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer"; @@ -2011,8 +2019,15 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid auto tx_relay = peer.GetTxRelay(); if (!tx_relay) continue; - const uint256& hash{peer.m_wtxid_relay ? wtxid : txid}; LOCK(tx_relay->m_tx_inventory_mutex); + // Only queue transactions for announcement once the version handshake + // is completed. The time of arrival for these transactions is + // otherwise at risk of leaking to a spy, if the spy is able to + // distinguish transactions received during the handshake from the rest + // in the announcement. + if (tx_relay->m_next_inv_send_time == 0s) continue; + + const uint256& hash{peer.m_wtxid_relay ? wtxid : txid}; if (!tx_relay->m_tx_inventory_known_filter.contains(hash)) { tx_relay->m_tx_inventory_to_send.insert(hash); } @@ -2285,9 +2300,9 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic std::vector<uint256> parent_ids_to_add; { LOCK(m_mempool.cs); - auto txiter = m_mempool.GetIter(tx->GetHash()); - if (txiter) { - const CTxMemPoolEntry::Parents& parents = (*txiter)->GetMemPoolParentsConst(); + auto tx_iter = m_mempool.GetIter(tx->GetHash()); + if (tx_iter) { + const CTxMemPoolEntry::Parents& parents = (*tx_iter)->GetMemPoolParentsConst(); parent_ids_to_add.reserve(parents.size()); for (const CTxMemPoolEntry& parent : parents) { if (parent.GetTime() > now - UNCONDITIONAL_RELAY_DELAY) { @@ -2607,22 +2622,21 @@ bool PeerManagerImpl::MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& loc } /* - * Given a new headers tip ending in pindexLast, potentially request blocks towards that tip. + * Given a new headers tip ending in last_header, potentially request blocks towards that tip. * We require that the given tip have at least as much work as our tip, and for * our current tip to be "close to synced" (see CanDirectFetch()). */ -void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex* pindexLast) +void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex& last_header) { const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); LOCK(cs_main); CNodeState *nodestate = State(pfrom.GetId()); - if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) { - + if (CanDirectFetch() && last_header.IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= last_header.nChainWork) { std::vector<const CBlockIndex*> vToFetch; - const CBlockIndex *pindexWalk = pindexLast; - // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. + const CBlockIndex* pindexWalk{&last_header}; + // Calculate all the blocks we'd need to switch to last_header, up to a limit. while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && !IsBlockRequested(pindexWalk->GetBlockHash()) && @@ -2638,8 +2652,8 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c // direct fetch and rely on parallel download instead. if (!m_chainman.ActiveChain().Contains(pindexWalk)) { LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", - pindexLast->GetBlockHash().ToString(), - pindexLast->nHeight); + last_header.GetBlockHash().ToString(), + last_header.nHeight); } else { std::vector<CInv> vGetData; // Download as much as possible, from earliest to latest. @@ -2656,14 +2670,15 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c } if (vGetData.size() > 1) { LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", - pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); + last_header.GetBlockHash().ToString(), + last_header.nHeight); } if (vGetData.size() > 0) { if (!m_ignore_incoming_txs && nodestate->m_provides_cmpctblocks && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && - pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) { + last_header.pprev->IsValid(BLOCK_VALID_CHAIN)) { // In any case, we want to download using a compact block, not a regular one vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); } @@ -2674,12 +2689,12 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c } /** - * Given receipt of headers from a peer ending in pindexLast, along with + * Given receipt of headers from a peer ending in last_header, along with * whether that header was new and whether the headers message was full, * update the state we keep for the peer. */ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, - const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers) + const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers) { LOCK(cs_main); CNodeState *nodestate = State(pfrom.GetId()); @@ -2688,14 +2703,13 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, } nodestate->nUnconnectingHeaders = 0; - assert(pindexLast); - UpdateBlockAvailability(pfrom.GetId(), pindexLast->GetBlockHash()); + UpdateBlockAvailability(pfrom.GetId(), last_header.GetBlockHash()); // From here, pindexBestKnownBlock should be guaranteed to be non-null, // because it is set in UpdateBlockAvailability. Some nullptr checks // are still present, however, as belt-and-suspenders. - if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) { + if (received_new_header && last_header.nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) { nodestate->m_last_block_announcement = GetTime(); } @@ -2861,7 +2875,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer, return; } } - Assume(pindexLast); + assert(pindexLast); // Consider fetching more headers if we are not using our headers-sync mechanism. if (nCount == MAX_HEADERS_RESULTS && !have_headers_sync) { @@ -2872,41 +2886,32 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer, } } - UpdatePeerStateForReceivedHeaders(pfrom, pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS); + UpdatePeerStateForReceivedHeaders(pfrom, *pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS); // Consider immediately downloading blocks. - HeadersDirectFetchBlocks(pfrom, peer, pindexLast); + HeadersDirectFetchBlocks(pfrom, peer, *pindexLast); return; } -/** - * Reconsider orphan transactions after a parent has been accepted to the mempool. - * - * @param[in,out] orphan_work_set The set of orphan transactions to reconsider. Generally only one - * orphan will be reconsidered on each call of this function. This set - * may be added to if accepting an orphan causes its children to be - * reconsidered. - */ -void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set) +bool PeerManagerImpl::ProcessOrphanTx(Peer& peer) { + AssertLockHeld(g_msgproc_mutex); AssertLockHeld(cs_main); - AssertLockHeld(g_cs_orphans); - while (!orphan_work_set.empty()) { - const uint256 orphanHash = *orphan_work_set.begin(); - orphan_work_set.erase(orphan_work_set.begin()); - - const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash); - if (porphanTx == nullptr) continue; + CTransactionRef porphanTx = nullptr; + NodeId from_peer = -1; + bool more = false; + while (CTransactionRef porphanTx = m_orphanage.GetTxToReconsider(peer.m_id, from_peer, more)) { const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx); const TxValidationState& state = result.m_state; + const uint256& orphanHash = porphanTx->GetHash(); if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString()); RelayTransaction(orphanHash, porphanTx->GetWitnessHash()); - m_orphanage.AddChildrenToWorkSet(*porphanTx, orphan_work_set); + m_orphanage.AddChildrenToWorkSet(*porphanTx, peer.m_id); m_orphanage.EraseTx(orphanHash); for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) { AddToCompactExtraTransactions(removedTx); @@ -2957,6 +2962,8 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set) break; } } + + return more; } bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, @@ -3274,17 +3281,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (greatest_common_version >= WTXID_RELAY_VERSION && m_txreconciliation) { // Per BIP-330, we announce txreconciliation support if: - // - protocol version per the VERSION message supports WTXID_RELAY; - // - we intended to exchange transactions over this connection while establishing it - // and the peer indicated support for transaction relay in the VERSION message; + // - protocol version per the peer's VERSION message supports WTXID_RELAY; + // - transaction relay is supported per the peer's VERSION message (see m_relays_txs); + // - this is not a block-relay-only connection and not a feeler (see m_relays_txs); + // - this is not an addr fetch connection; // - we are not in -blocksonly mode. - if (pfrom.m_relays_txs && !m_ignore_incoming_txs) { + if (pfrom.m_relays_txs && !pfrom.IsAddrFetchConn() && !m_ignore_incoming_txs) { const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.GetId()); - // We suggest our txreconciliation role (initiator/responder) based on - // the connection direction. m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDTXRCNCL, - !pfrom.IsInboundConn(), - pfrom.IsInboundConn(), TXRECONCILIATION_VERSION, recon_salt)); } } @@ -3299,39 +3303,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, m_num_preferred_download_peers += state->fPreferredDownload; } - // Self advertisement & GETADDR logic - if (!pfrom.IsInboundConn() && SetupAddressRelay(pfrom, *peer)) { - // For outbound peers, we try to relay our address (so that other - // nodes can try to find us more quickly, as we have no guarantee - // that an outbound peer is even aware of how to reach us) and do a - // one-time address fetch (to help populate/update our addrman). If - // we're starting up for the first time, our addrman may be pretty - // empty and no one will know who we are, so these mechanisms are - // important to help us connect to the network. - // + // Attempt to initialize address relay for outbound peers and use result + // to decide whether to send GETADDR, so that we don't send it to + // inbound or outbound block-relay-only peers. + bool send_getaddr{false}; + if (!pfrom.IsInboundConn()) { + send_getaddr = SetupAddressRelay(pfrom, *peer); + } + if (send_getaddr) { + // Do a one-time address fetch to help populate/update our addrman. + // If we're starting up for the first time, our addrman may be pretty + // empty, so this mechanism is important to help us connect to the network. // We skip this for block-relay-only peers. We want to avoid // potentially leaking addr information and we do not want to // indicate to the peer that we will participate in addr relay. - if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) - { - CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, Now<NodeSeconds>()}; - FastRandomContext insecure_rand; - if (addr.IsRoutable()) - { - LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString()); - PushAddress(*peer, addr, insecure_rand); - } else if (IsPeerAddrLocalGood(&pfrom)) { - // Override just the address with whatever the peer sees us as. - // Leave the port in addr as it was returned by GetLocalAddress() - // above, as this is an outbound connection and the peer cannot - // observe our listening port. - addr.SetIP(addrMe); - LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString()); - PushAddress(*peer, addr, insecure_rand); - } - } - - // Get recent addresses m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR)); peer->m_getaddr_sent = true; // When requesting a getaddr, accept an additional MAX_ADDR_TO_SEND addresses in response @@ -3428,6 +3413,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } } + if (auto tx_relay = peer->GetTxRelay()) { + // `TxRelay::m_tx_inventory_to_send` must be empty before the + // version handshake is completed as + // `TxRelay::m_next_inv_send_time` is first initialised in + // `SendMessages` after the verack is received. Any transactions + // received during the version handshake would otherwise + // immediately be advertised without random delay, potentially + // leaking the time of arrival to a spy. + Assume(WITH_LOCK( + tx_relay->m_tx_inventory_mutex, + return tx_relay->m_tx_inventory_to_send.empty() && + tx_relay->m_next_inv_send_time == 0s)); + } + pfrom.fSuccessfullyConnected = true; return; } @@ -3501,41 +3500,44 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (pfrom.fSuccessfullyConnected) { - // Disconnect peers that send a SENDTXRCNCL message after VERACK. LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received after verack from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } - if (!peer->GetTxRelay()) { - // Disconnect peers that send a SENDTXRCNCL message even though we indicated we don't - // support transaction relay. + // Peer must not offer us reconciliations if we specified no tx relay support in VERSION. + if (RejectIncomingTxs(pfrom)) { LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d to which we indicated no tx relay; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } - bool is_peer_initiator, is_peer_responder; + // Peer must not offer us reconciliations if they specified no tx relay support in VERSION. + // This flag might also be false in other cases, but the RejectIncomingTxs check above + // eliminates them, so that this flag fully represents what we are looking for. + if (!pfrom.m_relays_txs) { + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d which indicated no tx relay to us; disconnecting\n", pfrom.GetId()); + pfrom.fDisconnect = true; + return; + } + uint32_t peer_txreconcl_version; uint64_t remote_salt; - vRecv >> is_peer_initiator >> is_peer_responder >> peer_txreconcl_version >> remote_salt; + vRecv >> peer_txreconcl_version >> remote_salt; - if (m_txreconciliation->IsPeerRegistered(pfrom.GetId())) { - // A peer is already registered, meaning we already received SENDTXRCNCL from them. + const ReconciliationRegisterResult result = m_txreconciliation->RegisterPeer(pfrom.GetId(), pfrom.IsInboundConn(), + peer_txreconcl_version, remote_salt); + switch (result) { + case ReconciliationRegisterResult::NOT_FOUND: + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "Ignore unexpected txreconciliation signal from peer=%d\n", pfrom.GetId()); + break; + case ReconciliationRegisterResult::SUCCESS: + break; + case ReconciliationRegisterResult::ALREADY_REGISTERED: LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "txreconciliation protocol violation from peer=%d (sendtxrcncl received from already registered peer); disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; - } - - const ReconciliationRegisterResult result = m_txreconciliation->RegisterPeer(pfrom.GetId(), pfrom.IsInboundConn(), - is_peer_initiator, is_peer_responder, - peer_txreconcl_version, - remote_salt); - - // If it's a protocol violation, disconnect. - // If the peer was not found (but something unexpected happened) or it was registered, - // nothing to be done. - if (result == ReconciliationRegisterResult::PROTOCOL_VIOLATION) { + case ReconciliationRegisterResult::PROTOCOL_VIOLATION: LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "txreconciliation protocol violation from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; @@ -3990,7 +3992,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, AddKnownTx(*peer, txid); } - LOCK2(cs_main, g_cs_orphans); + LOCK(cs_main); m_txrequest.ReceivedResponse(pfrom.GetId(), txid); if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid); @@ -4031,7 +4033,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, m_txrequest.ForgetTxHash(tx.GetHash()); m_txrequest.ForgetTxHash(tx.GetWitnessHash()); RelayTransaction(tx.GetHash(), tx.GetWitnessHash()); - m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set); + m_orphanage.AddChildrenToWorkSet(tx, peer->m_id); pfrom.m_last_tx_time = GetTime<std::chrono::seconds>(); @@ -4045,7 +4047,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } // Recursively process any orphan transactions that depended on this one - ProcessOrphanTx(peer->m_orphan_work_set); + ProcessOrphanTx(*peer); } else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { @@ -4226,7 +4228,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, bool fBlockReconstructed = false; { - LOCK2(cs_main, g_cs_orphans); + LOCK(cs_main); // If AcceptBlockHeader returned true, it set pindex assert(pindex); UpdateBlockAvailability(pfrom.GetId(), pindex->GetBlockHash()); @@ -4854,16 +4856,17 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt } } + bool has_more_orphans; { - LOCK2(cs_main, g_cs_orphans); - if (!peer->m_orphan_work_set.empty()) { - ProcessOrphanTx(peer->m_orphan_work_set); - } + LOCK(cs_main); + has_more_orphans = ProcessOrphanTx(*peer); } if (pfrom->fDisconnect) return false; + if (has_more_orphans) return true; + // this maintains the order of responses // and prevents m_getdata_requests to grow unbounded { @@ -4871,11 +4874,6 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt if (!peer->m_getdata_requests.empty()) return true; } - { - LOCK(g_cs_orphans); - if (!peer->m_orphan_work_set.empty()) return true; - } - // Don't bother if send buffer is too full to respond anyway if (pfrom->fPauseSend) return false; @@ -5325,8 +5323,9 @@ bool PeerManagerImpl::SetupAddressRelay(const CNode& node, Peer& peer) if (node.IsBlockOnlyConn()) return false; if (!peer.m_addr_relay_enabled.exchange(true)) { - // First addr message we have received from the peer, initialize - // m_addr_known + // During version message processing (non-block-relay-only outbound peers) + // or on first addr-related message we have received (inbound peers), initialize + // m_addr_known. peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001); } diff --git a/src/net_processing.h b/src/net_processing.h index 0d0842fa8e..af9a02139b 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/net_types.cpp b/src/net_types.cpp index 90346715f0..2cdc10d8c9 100644 --- a/src/net_types.cpp +++ b/src/net_types.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/netaddress.cpp b/src/netaddress.cpp index eabab3dd99..782b692d30 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -179,7 +179,7 @@ bool CNetAddr::SetInternal(const std::string &name) } namespace torv3 { -// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt#n2135 +// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt?id=7116c9cdaba248aae07a3f1d0e15d9dd102f62c5#n2175 static constexpr size_t CHECKSUM_LEN = 2; static const unsigned char VERSION[] = {3}; static constexpr size_t TOTAL_LEN = ADDR_TORV3_SIZE + CHECKSUM_LEN + sizeof(VERSION); diff --git a/src/netaddress.h b/src/netaddress.h index 11086eaee0..7f782674d3 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/netbase.cpp b/src/netbase.cpp index 8169b40ea6..fac4b3b5d5 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/netbase.h b/src/netbase.h index f7816f5d1d..a43f22f240 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/netgroup.cpp b/src/netgroup.cpp index 96b5e29684..87a1c4e036 100644 --- a/src/netgroup.cpp +++ b/src/netgroup.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 04d46f4361..b8a57acf80 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 29501c1959..cdf667c754 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +8,7 @@ #include <attributes.h> #include <chain.h> #include <fs.h> +#include <kernel/cs_main.h> #include <protocol.h> #include <sync.h> #include <txdb.h> @@ -17,8 +18,6 @@ #include <unordered_map> #include <vector> -extern RecursiveMutex cs_main; - class ArgsManager; class BlockValidationState; class CBlock; diff --git a/src/node/caches.cpp b/src/node/caches.cpp index a39ad7aeb6..7622a03e19 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index 60acb614b4..99dc319ec0 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/chainstate.h b/src/node/chainstate.h index 2289310ece..d3c7656bf2 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/coin.h b/src/node/coin.h index 3d534463e8..b32e410e1c 100644 --- a/src/node/coin.h +++ b/src/node/coin.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/context.cpp b/src/node/context.cpp index d80b8ca7a7..af59ab932b 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/context.h b/src/node/context.h index 31be308787..84f4053c84 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp index fa90d6fda7..08d1e03541 100644 --- a/src/node/interface_ui.cpp +++ b/src/node/interface_ui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2021 The Bitcoin Core developers +// Copyright (c) 2010-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/interface_ui.h b/src/node/interface_ui.h index 316d75167e..9f6503b4a1 100644 --- a/src/node/interface_ui.h +++ b/src/node/interface_ui.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 212780b259..4f3dc99bbf 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,17 +15,18 @@ #include <interfaces/handler.h> #include <interfaces/node.h> #include <interfaces/wallet.h> +#include <kernel/chain.h> +#include <kernel/mempool_entry.h> #include <mapport.h> #include <net.h> #include <net_processing.h> #include <netaddress.h> #include <netbase.h> #include <node/blockstorage.h> -#include <kernel/chain.h> #include <node/coin.h> #include <node/context.h> -#include <node/transaction.h> #include <node/interface_ui.h> +#include <node/transaction.h> #include <policy/feerate.h> #include <policy/fees.h> #include <policy/policy.h> @@ -39,7 +40,6 @@ #include <support/allocators/secure.h> #include <sync.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <uint256.h> #include <univalue.h> #include <util/check.h> @@ -64,7 +64,7 @@ using interfaces::BlockTip; using interfaces::Chain; using interfaces::FoundBlock; using interfaces::Handler; -using interfaces::MakeHandler; +using interfaces::MakeSignalHandler; using interfaces::Node; using interfaces::WalletLoader; @@ -336,50 +336,50 @@ public: } std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override { - return MakeHandler(::uiInterface.InitMessage_connect(fn)); + return MakeSignalHandler(::uiInterface.InitMessage_connect(fn)); } std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override { - return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); + return MakeSignalHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); } std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override { - return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); + return MakeSignalHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); } std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override { - return MakeHandler(::uiInterface.ShowProgress_connect(fn)); + return MakeSignalHandler(::uiInterface.ShowProgress_connect(fn)); } std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override { - return MakeHandler(::uiInterface.InitWallet_connect(fn)); + return MakeSignalHandler(::uiInterface.InitWallet_connect(fn)); } std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); } std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); } std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override { - return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.NotifyAlertChanged_connect(fn)); } std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override { - return MakeHandler(::uiInterface.BannedListChanged_connect(fn)); + return MakeSignalHandler(::uiInterface.BannedListChanged_connect(fn)); } std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override { - return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { + return MakeSignalHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()}, GuessVerificationProgress(Params().TxData(), block)); })); } std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override { - return MakeHandler( + return MakeSignalHandler( ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, int64_t height, int64_t timestamp, bool presync) { fn(sync_state, BlockTip{(int)height, timestamp, uint256{}}, presync); })); @@ -420,11 +420,11 @@ public: virtual ~NotificationsProxy() = default; void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override { - m_notifications->transactionAddedToMempool(tx, mempool_sequence); + m_notifications->transactionAddedToMempool(tx); } void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override { - m_notifications->transactionRemovedFromMempool(tx, reason, mempool_sequence); + m_notifications->transactionRemovedFromMempool(tx, reason); } void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override { @@ -672,12 +672,9 @@ public: if (!m_node.mempool) return true; LockPoints lp; CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp); - CTxMemPool::setEntries ancestors; const CTxMemPool::Limits& limits{m_node.mempool->m_limits}; - std::string unused_error_string; LOCK(m_node.mempool->cs); - return m_node.mempool->CalculateMemPoolAncestors( - entry, ancestors, limits, unused_error_string); + return m_node.mempool->CalculateMemPoolAncestors(entry, limits).has_value(); } CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override { @@ -779,7 +776,7 @@ public: if (!m_node.mempool) return; LOCK2(::cs_main, m_node.mempool->cs); for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) { - notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */); + notifications.transactionAddedToMempool(entry.GetSharedTx()); } } bool hasAssumedValidChain() override diff --git a/src/node/miner.cpp b/src/node/miner.cpp index e11ec5b0f1..c2b6fd1dc3 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -60,10 +60,12 @@ BlockAssembler::Options::Options() { blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; + test_block_validity = true; } BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options) - : chainparams{chainstate.m_chainman.GetParams()}, + : test_block_validity{options.test_block_validity}, + chainparams{chainstate.m_chainman.GetParams()}, m_mempool(mempool), m_chainstate(chainstate) { @@ -72,11 +74,10 @@ BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight)); } -static BlockAssembler::Options DefaultOptions() +void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options) { // Block resource limits // If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT - BlockAssembler::Options options; options.nBlockMaxWeight = gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); if (gArgs.IsArgSet("-blockmintxfee")) { std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", "")); @@ -84,11 +85,16 @@ static BlockAssembler::Options DefaultOptions() } else { options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE}; } +} +static BlockAssembler::Options ConfiguredOptions() +{ + BlockAssembler::Options options; + ApplyArgsManOptions(gArgs, options); return options; } BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool) - : BlockAssembler(chainstate, mempool, DefaultOptions()) {} + : BlockAssembler(chainstate, mempool, ConfiguredOptions()) {} void BlockAssembler::resetBlock() { @@ -170,7 +176,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); BlockValidationState state; - if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, GetAdjustedTime, false, false)) { + if (test_block_validity && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, + GetAdjustedTime, /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString())); } const auto time_2{SteadyClock::now()}; @@ -394,9 +401,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele continue; } - CTxMemPool::setEntries ancestors; - std::string dummy; - mempool.CalculateMemPoolAncestors(*iter, ancestors, CTxMemPool::Limits::NoLimits(), dummy, false); + auto ancestors{mempool.AssumeCalculateMemPoolAncestors(__func__, *iter, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)}; onlyUnconfirmed(ancestors); ancestors.insert(iter); diff --git a/src/node/miner.h b/src/node/miner.h index 7269ce1186..ea9e470a64 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,7 @@ #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index_container.hpp> +class ArgsManager; class ChainstateManager; class CBlockIndex; class CChainParams; @@ -135,6 +136,9 @@ private: unsigned int nBlockMaxWeight; CFeeRate blockMinFeeRate; + // Whether to call TestBlockValidity() at the end of CreateNewBlock(). + const bool test_block_validity; + // Information on the current status of the block uint64_t nBlockWeight; uint64_t nBlockTx; @@ -155,6 +159,7 @@ public: Options(); size_t nBlockMaxWeight; CFeeRate blockMinFeeRate; + bool test_block_validity; }; explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool); @@ -197,6 +202,9 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman); + +/** Apply -blockmintxfee and -blockmaxweight options from ArgsManager to BlockAssembler options. */ +void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options); } // namespace node #endif // BITCOIN_NODE_MINER_H diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp index ca3fc0955d..51e252bffc 100644 --- a/src/node/psbt.cpp +++ b/src/node/psbt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/transaction.h b/src/node/transaction.h index 0604754a46..45f174f13c 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp index 974358fcda..ed04a78cec 100644 --- a/src/node/txreconciliation.cpp +++ b/src/node/txreconciliation.cpp @@ -39,7 +39,8 @@ public: * the following commits. * * Reconciliation protocol assumes using one role consistently: either a reconciliation - * initiator (requesting sketches), or responder (sending sketches). This defines our role. + * initiator (requesting sketches), or responder (sending sketches). This defines our role, + * based on the direction of the p2p connection. * */ bool m_we_initiate; @@ -81,31 +82,30 @@ public: { AssertLockNotHeld(m_txreconciliation_mutex); LOCK(m_txreconciliation_mutex); - // We do not support txreconciliation salt/version updates. - assert(m_states.find(peer_id) == m_states.end()); LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Pre-register peer=%d\n", peer_id); const uint64_t local_salt{GetRand(UINT64_MAX)}; // We do this exactly once per peer (which are unique by NodeId, see GetNewNodeId) so it's // safe to assume we don't have this record yet. - Assert(m_states.emplace(peer_id, local_salt).second); + Assume(m_states.emplace(peer_id, local_salt).second); return local_salt; } - ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, bool is_peer_recon_initiator, - bool is_peer_recon_responder, uint32_t peer_recon_version, - uint64_t remote_salt) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex) + ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, uint32_t peer_recon_version, + uint64_t remote_salt) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex) { AssertLockNotHeld(m_txreconciliation_mutex); LOCK(m_txreconciliation_mutex); auto recon_state = m_states.find(peer_id); - // A peer should be in the pre-registered state to proceed here. - if (recon_state == m_states.end()) return NOT_FOUND; - uint64_t* local_salt = std::get_if<uint64_t>(&recon_state->second); - // A peer is already registered. This should be checked by the caller. - Assume(local_salt); + if (recon_state == m_states.end()) return ReconciliationRegisterResult::NOT_FOUND; + + if (std::holds_alternative<TxReconciliationState>(recon_state->second)) { + return ReconciliationRegisterResult::ALREADY_REGISTERED; + } + + uint64_t local_salt = *std::get_if<uint64_t>(&recon_state->second); // If the peer supports the version which is lower than ours, we downgrade to the version // it supports. For now, this only guarantees that nodes with future reconciliation @@ -114,27 +114,14 @@ public: // satisfactory (e.g. too low). const uint32_t recon_version{std::min(peer_recon_version, m_recon_version)}; // v1 is the lowest version, so suggesting something below must be a protocol violation. - if (recon_version < 1) return PROTOCOL_VIOLATION; - - // Must match SENDTXRCNCL logic. - const bool they_initiate = is_peer_recon_initiator && is_peer_inbound; - const bool we_initiate = !is_peer_inbound && is_peer_recon_responder; - - // If we ever announce support for both requesting and responding, this will need - // tie-breaking. For now, this is mutually exclusive because both are based on the - // inbound flag. - assert(!(they_initiate && we_initiate)); - - // The peer set both flags to false, we treat it as a protocol violation. - if (!(they_initiate || we_initiate)) return PROTOCOL_VIOLATION; + if (recon_version < 1) return ReconciliationRegisterResult::PROTOCOL_VIOLATION; - LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Register peer=%d with the following params: " /* Continued */ - "we_initiate=%i, they_initiate=%i.\n", - peer_id, we_initiate, they_initiate); + LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Register peer=%d (inbound=%i)\n", + peer_id, is_peer_inbound); - const uint256 full_salt{ComputeSalt(*local_salt, remote_salt)}; - recon_state->second = TxReconciliationState(we_initiate, full_salt.GetUint64(0), full_salt.GetUint64(1)); - return SUCCESS; + const uint256 full_salt{ComputeSalt(local_salt, remote_salt)}; + recon_state->second = TxReconciliationState(!is_peer_inbound, full_salt.GetUint64(0), full_salt.GetUint64(1)); + return ReconciliationRegisterResult::SUCCESS; } void ForgetPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex) @@ -166,11 +153,9 @@ uint64_t TxReconciliationTracker::PreRegisterPeer(NodeId peer_id) } ReconciliationRegisterResult TxReconciliationTracker::RegisterPeer(NodeId peer_id, bool is_peer_inbound, - bool is_peer_recon_initiator, bool is_peer_recon_responder, uint32_t peer_recon_version, uint64_t remote_salt) { - return m_impl->RegisterPeer(peer_id, is_peer_inbound, is_peer_recon_initiator, is_peer_recon_responder, - peer_recon_version, remote_salt); + return m_impl->RegisterPeer(peer_id, is_peer_inbound, peer_recon_version, remote_salt); } void TxReconciliationTracker::ForgetPeer(NodeId peer_id) diff --git a/src/node/txreconciliation.h b/src/node/txreconciliation.h index a4f0870914..4591dd5df7 100644 --- a/src/node/txreconciliation.h +++ b/src/node/txreconciliation.h @@ -16,10 +16,11 @@ static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false}; /** Supported transaction reconciliation protocol version */ static constexpr uint32_t TXRECONCILIATION_VERSION{1}; -enum ReconciliationRegisterResult { - NOT_FOUND = 0, - SUCCESS = 1, - PROTOCOL_VIOLATION = 2, +enum class ReconciliationRegisterResult { + NOT_FOUND, + SUCCESS, + ALREADY_REGISTERED, + PROTOCOL_VIOLATION, }; /** @@ -72,8 +73,8 @@ public: * Step 0. Once the peer agreed to reconcile txs with us, generate the state required to track * ongoing reconciliations. Must be called only after pre-registering the peer and only once. */ - ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, bool is_peer_recon_initiator, - bool is_peer_recon_responder, uint32_t peer_recon_version, uint64_t remote_salt); + ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, + uint32_t peer_recon_version, uint64_t remote_salt); /** * Attempts to forget txreconciliation-related state of the peer (if we previously stored any). diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h index c94521792f..b5ed9ef9fe 100644 --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/noui.cpp b/src/noui.cpp index 54cb5f3cbf..af5a180ce3 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/outputtype.cpp b/src/outputtype.cpp index 9ab2902256..270212dca5 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/outputtype.h b/src/outputtype.h index c59262591b..7c50f445fc 100644 --- a/src/outputtype.h +++ b/src/outputtype.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp index 82b767793d..eb0cba5c67 100644 --- a/src/policy/feerate.cpp +++ b/src/policy/feerate.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/feerate.h b/src/policy/feerate.h index a8d4d2fc63..6f859e2d0d 100644 --- a/src/policy/feerate.h +++ b/src/policy/feerate.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 899adc70ca..e4eb932e5c 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +8,7 @@ #include <clientversion.h> #include <consensus/amount.h> #include <fs.h> +#include <kernel/mempool_entry.h> #include <logging.h> #include <policy/feerate.h> #include <primitives/transaction.h> @@ -16,7 +17,6 @@ #include <streams.h> #include <sync.h> #include <tinyformat.h> -#include <txmempool_entry.h> #include <uint256.h> #include <util/serfloat.h> #include <util/system.h> diff --git a/src/policy/fees.h b/src/policy/fees.h index 204c4f2118..dd4f031180 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 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_POLICY_FEES_H diff --git a/src/policy/fees_args.cpp b/src/policy/fees_args.cpp index a3531153b5..1aeb2ab983 100644 --- a/src/policy/fees_args.cpp +++ b/src/policy/fees_args.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2021 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 <policy/fees_args.h> #include <util/system.h> diff --git a/src/policy/packages.cpp b/src/policy/packages.cpp index 67918c9dec..6e70a94088 100644 --- a/src/policy/packages.cpp +++ b/src/policy/packages.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/packages.h b/src/policy/packages.h index 36c70e9e66..0a0e7cf6bb 100644 --- a/src/policy/packages.h +++ b/src/policy/packages.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 5086542865..41b5b2d0f1 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/policy.h b/src/policy/policy.h index 29764ea2d9..394fb34230 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -25,8 +25,8 @@ static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000}; static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000}; /** The maximum weight for transactions we're willing to relay/mine */ static constexpr unsigned int MAX_STANDARD_TX_WEIGHT{400000}; -/** The minimum non-witness size for transactions we're willing to relay/mine (1 segwit input + 1 P2WPKH output = 82 bytes) */ -static constexpr unsigned int MIN_STANDARD_TX_NONWITNESS_SIZE{82}; +/** The minimum non-witness size for transactions we're willing to relay/mine: one larger than 64 */ +static constexpr unsigned int MIN_STANDARD_TX_NONWITNESS_SIZE{65}; /** Maximum number of signature check operations in an IsStandard() P2SH script */ static constexpr unsigned int MAX_P2SH_SIGOPS{15}; /** The maximum number of sigops we're willing to relay/mine in a single tx */ diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp index 994e13dd56..d032b74008 100644 --- a/src/policy/rbf.cpp +++ b/src/policy/rbf.cpp @@ -1,16 +1,16 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 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 <policy/rbf.h> #include <consensus/amount.h> +#include <kernel/mempool_entry.h> #include <policy/feerate.h> #include <primitives/transaction.h> #include <sync.h> #include <tinyformat.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <uint256.h> #include <util/moneystr.h> #include <util/rbf.h> @@ -22,8 +22,6 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) { AssertLockHeld(pool.cs); - CTxMemPool::setEntries ancestors; - // First check the transaction itself. if (SignalsOptInRBF(tx)) { return RBFTransactionState::REPLACEABLE_BIP125; @@ -37,9 +35,9 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) // If all the inputs have nSequence >= maxint-1, it still might be // signaled for RBF if any unconfirmed parents have signaled. - std::string dummy; - CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash()); - pool.CalculateMemPoolAncestors(entry, ancestors, CTxMemPool::Limits::NoLimits(), dummy, false); + const CTxMemPoolEntry entry{*pool.mapTx.find(tx.GetHash())}; + auto ancestors{pool.AssumeCalculateMemPoolAncestors(__func__, entry, CTxMemPool::Limits::NoLimits(), + /*fSearchForParents=*/false)}; for (CTxMemPool::txiter it : ancestors) { if (SignalsOptInRBF(it->GetTx())) { diff --git a/src/policy/rbf.h b/src/policy/rbf.h index 28c4e4bf9b..fff9828482 100644 --- a/src/policy/rbf.h +++ b/src/policy/rbf.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/settings.cpp b/src/policy/settings.cpp index 39e00f1111..722b12acf5 100644 --- a/src/policy/settings.cpp +++ b/src/policy/settings.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/settings.h b/src/policy/settings.h index f0d6f779ae..145454b0dd 100644 --- a/src/policy/settings.h +++ b/src/policy/settings.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/pow.cpp b/src/pow.cpp index c0449cac74..1e8d53de8b 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/prevector.h b/src/prevector.h index 7df5a067a2..f36cfe4ff6 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/block.h b/src/primitives/block.h index 2e26e6c426..bd11279a6e 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index ec48194ee9..3060746909 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index f496ea022e..bd7eb16bec 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,6 +17,7 @@ #include <ios> #include <limits> #include <memory> +#include <numeric> #include <string> #include <tuple> #include <utility> @@ -280,6 +281,12 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) { s << tx.nLockTime; } +template<typename TxType> +inline CAmount CalculateOutputValue(const TxType& tx) +{ + return std::accumulate(tx.vout.cbegin(), tx.vout.cend(), CAmount{0}, [](CAmount sum, const auto& txout) { return sum + txout.nValue; }); +} + /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. diff --git a/src/protocol.cpp b/src/protocol.cpp index 23c68b335b..aa59bae6ff 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/protocol.h b/src/protocol.h index 17a363b1d3..cbcd400fef 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -259,9 +259,7 @@ extern const char* CFCHECKPT; */ extern const char* WTXIDRELAY; /** - * Contains 2 1-byte bools, a 4-byte version number and an 8-byte salt. - * The 2 booleans indicate that a node is willing to participate in transaction - * reconciliation, respectively as an initiator or as a receiver. + * Contains a 4-byte version number and an 8-byte salt. * The salt is used to compute short txids needed for efficient * txreconciliation, as described by BIP 330. */ diff --git a/src/psbt.cpp b/src/psbt.cpp index 461987c503..50ccd9e2c0 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/psbt.h b/src/psbt.h index da75a60412..8fafadcea9 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -178,7 +178,7 @@ void SerializeHDKeypath(Stream& s, KeyOriginInfo hd_keypath) template<typename Stream> void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, CompactSizeWriter type) { - for (auto keypath_pair : hd_keypaths) { + for (const auto& keypath_pair : hd_keypaths) { if (!keypath_pair.first.IsValid()) { throw std::ios_base::failure("Invalid CPubKey being serialized"); } @@ -875,7 +875,7 @@ struct PSBTOutput throw std::ios_base::failure("Output Taproot tree has a leaf with an invalid leaf version"); } m_tap_tree.push_back(std::make_tuple(depth, leaf_ver, script)); - builder.Add((int)depth, script, (int)leaf_ver, true /* track */); + builder.Add((int)depth, script, (int)leaf_ver, /*track=*/true); } if (!builder.IsComplete()) { throw std::ios_base::failure("Output Taproot tree is malformed"); diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 2e37e16690..ae5dccfb5a 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,10 +16,16 @@ #include <algorithm> #include <cassert> -namespace +namespace { + +struct Secp256k1SelfTester { -/* Global secp256k1_context object used for verification. */ -secp256k1_context* secp256k1_context_verify = nullptr; + Secp256k1SelfTester() { + /* Run libsecp256k1 self-test before using the secp256k1_context_static. */ + secp256k1_selftest(); + } +} SECP256K1_SELFTESTER; + } // namespace /** This function is taken from the libsecp256k1 distribution and implements @@ -32,7 +38,7 @@ secp256k1_context* secp256k1_context_verify = nullptr; * strict DER before being passed to this module, and we know it supports all * violations present in the blockchain before that point. */ -int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { +int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { size_t rpos, rlen, spos, slen; size_t pos = 0; size_t lenbyte; @@ -40,7 +46,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ int overflow = 0; /* Hack to initialize sig with a correctly-parsed but invalid signature. */ - secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig); /* Sequence tag byte */ if (pos == inputlen || input[pos] != 0x30) { @@ -163,13 +169,13 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ } if (!overflow) { - overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + overflow = !secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig); } if (overflow) { /* Overwrite the result again with a correctly-parsed but invalid signature if parsing failed. */ memset(tmpsig, 0, 64); - secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig); } return 1; } @@ -200,15 +206,15 @@ std::vector<CKeyID> XOnlyPubKey::GetKeyIDs() const bool XOnlyPubKey::IsFullyValid() const { secp256k1_xonly_pubkey pubkey; - return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data()); + return secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data()); } bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const { assert(sigbytes.size() == 64); secp256k1_xonly_pubkey pubkey; - if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data())) return false; - return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), 32, &pubkey); + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data())) return false; + return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.begin(), 32, &pubkey); } static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")}; @@ -227,23 +233,23 @@ uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const { secp256k1_xonly_pubkey internal_key; - if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &internal_key, internal.data())) return false; uint256 tweak = internal.ComputeTapTweakHash(&merkle_root); - return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin()); + return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_static, m_keydata.begin(), parity, &internal_key, tweak.begin()); } std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const { secp256k1_xonly_pubkey base_point; - if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &base_point, data())) return std::nullopt; secp256k1_pubkey out; uint256 tweak = ComputeTapTweakHash(merkle_root); - if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt; + if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_static, &out, &base_point, tweak.data())) return std::nullopt; int parity = -1; std::pair<XOnlyPubKey, bool> ret; secp256k1_xonly_pubkey out_xonly; - if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt; - secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly); + if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static, &out_xonly, &parity, &out)) return std::nullopt; + secp256k1_xonly_pubkey_serialize(secp256k1_context_static, ret.first.begin(), &out_xonly); assert(parity == 0 || parity == 1); ret.second = parity; return ret; @@ -255,17 +261,16 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS return false; secp256k1_pubkey pubkey; secp256k1_ecdsa_signature sig; - assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey."); - if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) { + if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) { return false; } - if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) { + if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) { return false; } /* libsecp256k1's ECDSA verification requires lower-S signatures, which have * not historically been enforced in Bitcoin, so normalize them first. */ - secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig); - return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); + secp256k1_ecdsa_signature_normalize(secp256k1_context_static, &sig, &sig); + return secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pubkey); } bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) { @@ -275,16 +280,15 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha bool fComp = ((vchSig[0] - 27) & 4) != 0; secp256k1_pubkey pubkey; secp256k1_ecdsa_recoverable_signature sig; - assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey."); - if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) { + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_static, &sig, &vchSig[1], recid)) { return false; } - if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) { + if (!secp256k1_ecdsa_recover(secp256k1_context_static, &pubkey, &sig, hash.begin())) { return false; } unsigned char pub[SIZE]; size_t publen = SIZE; - secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); + secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); Set(pub, pub + publen); return true; } @@ -293,21 +297,19 @@ bool CPubKey::IsFullyValid() const { if (!IsValid()) return false; secp256k1_pubkey pubkey; - assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey."); - return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size()); + return secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size()); } bool CPubKey::Decompress() { if (!IsValid()) return false; secp256k1_pubkey pubkey; - assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey."); - if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) { + if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) { return false; } unsigned char pub[SIZE]; size_t publen = SIZE; - secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); Set(pub, pub + publen); return true; } @@ -320,16 +322,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi BIP32Hash(cc, nChild, *begin(), begin()+1, out); memcpy(ccChild.begin(), out+32, 32); secp256k1_pubkey pubkey; - assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey."); - if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) { + if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) { return false; } - if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) { + if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_static, &pubkey, out)) { return false; } unsigned char pub[COMPRESSED_SIZE]; size_t publen = COMPRESSED_SIZE; - secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); + secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); pubkeyChild.Set(pub, pub + publen); return true; } @@ -375,35 +376,8 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { /* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) { secp256k1_ecdsa_signature sig; - assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey."); - if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) { + if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) { return false; } - return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, nullptr, &sig)); -} - -/* static */ int ECCVerifyHandle::refcount = 0; - -ECCVerifyHandle::ECCVerifyHandle() -{ - if (refcount == 0) { - assert(secp256k1_context_verify == nullptr); - secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - assert(secp256k1_context_verify != nullptr); - } - refcount++; -} - -ECCVerifyHandle::~ECCVerifyHandle() -{ - refcount--; - if (refcount == 0) { - assert(secp256k1_context_verify != nullptr); - secp256k1_context_destroy(secp256k1_context_verify); - secp256k1_context_verify = nullptr; - } -} - -const secp256k1_context* GetVerifyContext() { - return secp256k1_context_verify; + return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_static, nullptr, &sig)); } diff --git a/src/pubkey.h b/src/pubkey.h index 0485a38f72..b3edafea7f 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -330,21 +330,4 @@ struct CExtPubKey { [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const; }; -/** Users of this module must hold an ECCVerifyHandle. The constructor and - * destructor of these are not allowed to run in parallel, though. */ -class ECCVerifyHandle -{ - static int refcount; - -public: - ECCVerifyHandle(); - ~ECCVerifyHandle(); -}; - -typedef struct secp256k1_context_struct secp256k1_context; - -/** Access to the internal secp256k1 context used for verification. Only intended to be used - * by key.cpp. */ -const secp256k1_context* GetVerifyContext(); - #endif // BITCOIN_PUBKEY_H diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index a82bd5f73e..b888fc43e2 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -64,7 +64,6 @@ protected: AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) : QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::AddressBookPage), - model(nullptr), mode(_mode), tab(_tab) { diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 144990f419..283209d00c 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -49,7 +49,7 @@ public Q_SLOTS: private: Ui::AddressBookPage *ui; - AddressTableModel *model; + AddressTableModel* model{nullptr}; Mode mode; Tabs tab; QString returnValue; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 8b5da7f9f0..e402c51ac4 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index f16700bfd9..d15aba5cdd 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -23,8 +23,6 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::AskPassphraseDialog), mode(_mode), - model(nullptr), - fCapsLock(false), m_passphrase_out(passphrase_out) { ui->setupUi(this); diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index 66031b08d3..370ea1de7e 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -38,8 +38,8 @@ public: private: Ui::AskPassphraseDialog *ui; Mode mode; - WalletModel *model; - bool fCapsLock; + WalletModel* model{nullptr}; + bool fCapsLock{false}; SecureString* m_passphrase_out; private Q_SLOTS: diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 3d0be69302..4f57cd4457 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index cc01e4d54a..59f433749d 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -228,14 +228,8 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons static int qt_argc = 1; static const char* qt_argv = "bitcoin-qt"; -BitcoinApplication::BitcoinApplication(): - QApplication(qt_argc, const_cast<char **>(&qt_argv)), - optionsModel(nullptr), - clientModel(nullptr), - window(nullptr), - pollShutdownTimer(nullptr), - returnValue(0), - platformStyle(nullptr) +BitcoinApplication::BitcoinApplication() + : QApplication(qt_argc, const_cast<char**>(&qt_argv)) { // Qt runs setlocale(LC_ALL, "") on initialization. RegisterMetaTypes(); @@ -311,11 +305,7 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { assert(!m_splash); m_splash = new SplashScreen(networkStyle); - // We don't hold a direct pointer to the splash screen after creation, but the splash - // screen will take care of deleting itself when finish() happens. m_splash->show(); - connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish); - connect(this, &BitcoinApplication::requestedShutdown, m_splash, &QWidget::close); } void BitcoinApplication::createNode(interfaces::Init& init) @@ -373,6 +363,9 @@ void BitcoinApplication::requestShutdown() w->hide(); } + delete m_splash; + m_splash = nullptr; + // Show a simple window indicating shutdown status // Do this first as some of the steps may take some time below, // for example the RPC console may still be executing a command. @@ -412,10 +405,13 @@ void BitcoinApplication::requestShutdown() void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info) { qDebug() << __func__ << ": Initialization result: " << success; + // Set exit result. returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE; - if(success) - { + if(success) { + delete m_splash; + m_splash = nullptr; + // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete qInfo() << "Platform customization:" << platformStyle->getName(); clientModel = new ClientModel(node(), optionsModel); @@ -438,7 +434,6 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead } else { window->showMinimized(); } - Q_EMIT splashFinished(); Q_EMIT windowShown(window); #ifdef ENABLE_WALLET @@ -455,7 +450,6 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead #endif pollShutdownTimer->start(SHUTDOWN_POLLING_DELAY); } else { - Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown requestShutdown(); } } @@ -592,29 +586,30 @@ int GuiMain(int argc, char* argv[]) // Gracefully exit if the user cancels if (!Intro::showIfNeeded(did_show_intro, prune_MiB)) return EXIT_SUCCESS; - /// 6. Determine availability of data directory and parse bitcoin.conf - /// - Do not call gArgs.GetDataDirNet() before this step finishes + /// 6a. Determine availability of data directory if (!CheckDataDirOption()) { InitError(strprintf(Untranslated("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", "")))); return EXIT_FAILURE; } - if (!gArgs.ReadConfigFiles(error, true)) { - InitError(strprintf(Untranslated("Error reading configuration file: %s\n"), error)); - QMessageBox::critical(nullptr, PACKAGE_NAME, - QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error))); - return EXIT_FAILURE; - } + try { + /// 6b. Parse bitcoin.conf + /// - Do not call gArgs.GetDataDirNet() before this step finishes + if (!gArgs.ReadConfigFiles(error, true)) { + InitError(strprintf(Untranslated("Error reading configuration file: %s\n"), error)); + QMessageBox::critical(nullptr, PACKAGE_NAME, + QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error))); + return EXIT_FAILURE; + } - /// 7. Determine network (and switch to network specific options) - // - Do not call Params() before this step - // - Do this after parsing the configuration file, as the network can be switched there - // - QSettings() will use the new application name after this, resulting in network-specific settings - // - Needs to be done before createOptionsModel + /// 7. Determine network (and switch to network specific options) + // - Do not call Params() before this step + // - Do this after parsing the configuration file, as the network can be switched there + // - QSettings() will use the new application name after this, resulting in network-specific settings + // - Needs to be done before createOptionsModel - // Check for chain settings (Params() calls are only valid after this clause) - try { + // Check for chain settings (Params() calls are only valid after this clause) SelectParams(gArgs.GetChainName()); } catch(std::exception &e) { InitError(Untranslated(strprintf("%s\n", e.what()))); diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 9ad37ca6c9..9174e23de6 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -89,7 +89,6 @@ public Q_SLOTS: Q_SIGNALS: void requestedInitialize(); void requestedShutdown(); - void splashFinished(); void windowShown(BitcoinGUI* window); protected: @@ -97,16 +96,16 @@ protected: private: std::optional<InitExecutor> m_executor; - OptionsModel *optionsModel; - ClientModel *clientModel; - BitcoinGUI *window; - QTimer *pollShutdownTimer; + OptionsModel* optionsModel{nullptr}; + ClientModel* clientModel{nullptr}; + BitcoinGUI* window{nullptr}; + QTimer* pollShutdownTimer{nullptr}; #ifdef ENABLE_WALLET PaymentServer* paymentServer{nullptr}; WalletController* m_wallet_controller{nullptr}; #endif - int returnValue; - const PlatformStyle *platformStyle; + int returnValue{0}; + const PlatformStyle* platformStyle{nullptr}; std::unique_ptr<QWidget> shutdownWindow; SplashScreen* m_splash = nullptr; std::unique_ptr<interfaces::Node> m_node; diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index c92aecd095..a7e2d22488 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -217,9 +217,8 @@ Q_SIGNALS: #include <qt/bitcoinamountfield.moc> -BitcoinAmountField::BitcoinAmountField(QWidget *parent) : - QWidget(parent), - amount(nullptr) +BitcoinAmountField::BitcoinAmountField(QWidget* parent) + : QWidget(parent) { amount = new AmountSpinBox(this); amount->setLocale(QLocale::c()); diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index a40cd38332..f710915a49 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -74,7 +74,7 @@ protected: bool eventFilter(QObject *object, QEvent *event) override; private: - AmountSpinBox *amount; + AmountSpinBox* amount{nullptr}; QValueComboBox *unit; private Q_SLOTS: diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 2bd38103ed..a7ffd367d7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1541,10 +1541,8 @@ bool BitcoinGUI::isPrivacyModeActivated() const return m_mask_values_action->isChecked(); } -UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) - : optionsModel(nullptr), - menu(nullptr), - m_platform_style{platformStyle} +UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle* platformStyle) + : m_platform_style{platformStyle} { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 912e9b95aa..1a83057146 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -333,8 +333,8 @@ protected: void changeEvent(QEvent* e) override; private: - OptionsModel *optionsModel; - QMenu* menu; + OptionsModel* optionsModel{nullptr}; + QMenu* menu{nullptr}; const PlatformStyle* m_platform_style; /** Shows context menu with Display Unit options by the mouse coordinates */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 092ffe7e5b..c0d1a0e226 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,8 +34,6 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO QObject(parent), m_node(node), optionsModel(_optionsModel), - peerTableModel(nullptr), - banTableModel(nullptr), m_thread(new QThread(this)) { cachedBestHeaderHeight = -1; diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 4a6abd6a76..9ff64fe772 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -104,9 +104,9 @@ private: std::unique_ptr<interfaces::Handler> m_handler_notify_block_tip; std::unique_ptr<interfaces::Handler> m_handler_notify_header_tip; OptionsModel *optionsModel; - PeerTableModel *peerTableModel; + PeerTableModel* peerTableModel{nullptr}; PeerTableSortProxy* m_peer_table_sort_proxy{nullptr}; - BanTableModel *banTableModel; + BanTableModel* banTableModel{nullptr}; //! A thread to interact with m_node asynchronously QThread* const m_thread; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index bd9a90a890..e1b1ae12e9 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -477,7 +477,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel * nBytes -= 34; // Fee - nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */); + nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, /*returned_target=*/nullptr, /*reason=*/nullptr); if (nPayAmount > 0) { diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index 656afb6e87..445ea41475 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -8,9 +8,9 @@ #include <QFile> #include <QTextStream> -CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) : - QObject(parent), - filename(_filename), model(nullptr) +CSVModelWriter::CSVModelWriter(const QString& _filename, QObject* parent) + : QObject(parent), + filename(_filename) { } diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h index ad247b6859..a1e77826a8 100644 --- a/src/qt/csvmodelwriter.h +++ b/src/qt/csvmodelwriter.h @@ -32,7 +32,7 @@ public: private: QString filename; - const QAbstractItemModel *model; + const QAbstractItemModel* model{nullptr}; struct Column { diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index fa27635981..9b3319415d 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -12,12 +12,10 @@ #include <QMessageBox> -EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : - QDialog(parent, GUIUtil::dialog_flags), - ui(new Ui::EditAddressDialog), - mapper(nullptr), - mode(_mode), - model(nullptr) +EditAddressDialog::EditAddressDialog(Mode _mode, QWidget* parent) + : QDialog(parent, GUIUtil::dialog_flags), + ui(new Ui::EditAddressDialog), + mode(_mode) { ui->setupUi(this); diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index f7ad80bb2d..7bfadcfbcc 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -49,9 +49,9 @@ private: QString getDuplicateAddressWarning() const; Ui::EditAddressDialog *ui; - QDataWidgetMapper *mapper; + QDataWidgetMapper* mapper{nullptr}; Mode mode; - AddressTableModel *model; + AddressTableModel* model{nullptr}; QString address; }; diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index fcdf6056c9..0f76770772 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 6e88b57e08..bedf367f05 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index acbe415a91..87a323bde9 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/initexecutor.cpp b/src/qt/initexecutor.cpp index d269dfec71..b63e7ec01c 100644 --- a/src/qt/initexecutor.cpp +++ b/src/qt/initexecutor.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2021 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 4c8b33bf28..12aa02340a 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -122,8 +122,6 @@ int GetPruneTargetGB() Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_size_gb) : QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::Intro), - thread(nullptr), - signalled(false), m_blockchain_size_gb(blockchain_size_gb), m_chain_state_size_gb(chain_state_size_gb), m_prune_target_gb{GetPruneTargetGB()} diff --git a/src/qt/intro.h b/src/qt/intro.h index d9c45007e1..900c657b27 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -64,9 +64,9 @@ private Q_SLOTS: private: Ui::Intro *ui; - QThread *thread; + QThread* thread{nullptr}; QMutex mutex; - bool signalled; + bool signalled{false}; QString pathToCheck; const int64_t m_blockchain_size_gb; const int64_t m_chain_state_size_gb; diff --git a/src/qt/main.cpp b/src/qt/main.cpp index 45131a1cf5..c84dd78b44 100644 --- a/src/qt/main.cpp +++ b/src/qt/main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index dfa33764f6..b09e230bce 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,13 +12,10 @@ #include <QPropertyAnimation> #include <QResizeEvent> -ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) : -QWidget(parent), -ui(new Ui::ModalOverlay), -bestHeaderHeight(0), -bestHeaderDate(QDateTime()), -layerIsVisible(false), -userClosed(false) +ModalOverlay::ModalOverlay(bool enable_wallet, QWidget* parent) + : QWidget(parent), + ui(new Ui::ModalOverlay), + bestHeaderDate(QDateTime()) { ui->setupUi(this); connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked); diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h index 682c94cd01..40e487b249 100644 --- a/src/qt/modaloverlay.h +++ b/src/qt/modaloverlay.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -45,11 +45,11 @@ protected: private: Ui::ModalOverlay *ui; - int bestHeaderHeight; //best known height (based on the headers) + int bestHeaderHeight{0}; // best known height (based on the headers) QDateTime bestHeaderDate; QVector<QPair<qint64, double> > blockProcessTime; - bool layerIsVisible; - bool userClosed; + bool layerIsVisible{false}; + bool userClosed{false}; QPropertyAnimation m_animation; void UpdateHeaderSyncLabel(); void UpdateHeaderPresyncLabel(int height, const QDateTime& blockDate); diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index b2dc7fd65a..b789e6a958 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index b311a9f32e..88bc33098a 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -32,11 +32,7 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon QObject(_parent), parent(_parent), programName(_programName), - mode(None), trayIcon(_trayIcon) -#ifdef USE_DBUS - ,interface(nullptr) -#endif { if(_trayIcon && _trayIcon->supportsMessages()) { diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 642d2b29ae..1fd8181a22 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -61,10 +61,10 @@ private: UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; - Mode mode; + Mode mode{None}; QSystemTrayIcon *trayIcon; #ifdef USE_DBUS - QDBusInterface *interface; + QDBusInterface* interface{nullptr}; void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 7c91eac37e..53b0c3832b 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,11 +31,9 @@ #include <QSystemTrayIcon> #include <QTimer> -OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : - QDialog(parent, GUIUtil::dialog_flags), - ui(new Ui::OptionsDialog), - model(nullptr), - mapper(nullptr) +OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) + : QDialog(parent, GUIUtil::dialog_flags), + ui(new Ui::OptionsDialog) { ui->setupUi(this); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e5a19d5025..031e4d3163 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -75,8 +75,8 @@ Q_SIGNALS: private: Ui::OptionsDialog *ui; ClientModel* m_client_model{nullptr}; - OptionsModel *model; - QDataWidgetMapper *mapper; + OptionsModel* model{nullptr}; + QDataWidgetMapper* mapper{nullptr}; }; #endif // BITCOIN_QT_OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 0b4359a917..cd0a1a19ee 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 42b89c5029..e36fbc5b31 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 85a3c36f39..c9caec39cf 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -140,8 +140,6 @@ private: OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::OverviewPage), - clientModel(nullptr), - walletModel(nullptr), m_platform_style{platformStyle}, txdelegate(new TxViewDelegate(platformStyle, this)) { diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 56f45907db..2ca38b78dd 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -50,8 +50,8 @@ protected: private: Ui::OverviewPage *ui; - ClientModel *clientModel; - WalletModel *walletModel; + ClientModel* clientModel{nullptr}; + WalletModel* walletModel{nullptr}; bool m_privacy{false}; const PlatformStyle* m_platform_style; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 9f87c15c94..3f9d1b040b 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -126,11 +126,8 @@ bool PaymentServer::ipcSendCommandLine() return fResult; } -PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : - QObject(parent), - saveURIs(true), - uriServer(nullptr), - optionsModel(nullptr) +PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) + : QObject(parent) { // Install global event filter to catch QFileOpenEvents // on Mac: sent when you click bitcoin: links diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 08b83244ab..63f4faa772 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -101,9 +101,9 @@ protected: bool eventFilter(QObject *object, QEvent *event) override; private: - bool saveURIs; // true during startup - QLocalServer* uriServer; - OptionsModel *optionsModel; + bool saveURIs{true}; // true during startup + QLocalServer* uriServer{nullptr}; + OptionsModel* optionsModel{nullptr}; }; #endif // BITCOIN_QT_PAYMENTSERVER_H diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index b7de88225e..9f47213ed9 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,10 +14,9 @@ #include <QList> #include <QTimer> -PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) : - QAbstractTableModel(parent), - m_node(node), - timer(nullptr) +PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) + : QAbstractTableModel(parent), + m_node(node) { // set up timer for auto refresh timer = new QTimer(this); diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index e2515de775..a0174c3af4 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -110,7 +110,7 @@ private: /*: Title of Peers Table column which contains the peer's User Agent string. */ tr("User Agent")}; - QTimer *timer; + QTimer* timer{nullptr}; }; #endif // BITCOIN_QT_PEERTABLEMODEL_H diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp index d87f10c365..a70b5d4e29 100644 --- a/src/qt/peertablesortproxy.cpp +++ b/src/qt/peertablesortproxy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index 89e022a067..a430650096 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -83,8 +83,8 @@ QColor PlatformStyle::TextColor() const QColor PlatformStyle::SingleColor() const { if (colorizeIcons) { - const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight)); - const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText)); + QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight)); + QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText)); const QColor colorText(QApplication::palette().color(QPalette::WindowText)); const int colorTextLightness = colorText.lightness(); if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness)) { diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 333766ce21..17a65be0fe 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -56,7 +56,7 @@ void PSBTOperationsDialog::openWithPSBT(PartiallySignedTransaction psbtx) bool complete = FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness. if (m_wallet_model) { size_t n_could_sign; - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, &n_could_sign, m_transaction_data, complete); + TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete); if (err != TransactionError::OK) { showStatus(tr("Failed to load transaction: %1") .arg(QString::fromStdString(TransactionErrorString(err).translated)), @@ -80,7 +80,7 @@ void PSBTOperationsDialog::signTransaction() WalletModel::UnlockContext ctx(m_wallet_model->requestUnlock()); - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, true /* sign */, true /* bip32derivs */, &n_signed, m_transaction_data, complete); + TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete); if (err != TransactionError::OK) { showStatus(tr("Failed to sign transaction: %1") @@ -245,7 +245,7 @@ size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &p size_t n_signed; bool complete; - TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, false /* bip32derivs */, &n_signed, m_transaction_data, complete); + TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete); if (err != TransactionError::OK) { return 0; diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index 05a67117b6..00f928b355 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -23,8 +23,8 @@ #include <qrencode.h> #endif -QRImageWidget::QRImageWidget(QWidget *parent): - QLabel(parent), contextMenu(nullptr) +QRImageWidget::QRImageWidget(QWidget* parent) + : QLabel(parent) { contextMenu = new QMenu(this); contextMenu->addAction(tr("&Save Image…"), this, &QRImageWidget::saveImage); diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h index 5dbba074a1..d9ca2b899f 100644 --- a/src/qt/qrimagewidget.h +++ b/src/qt/qrimagewidget.h @@ -41,7 +41,7 @@ protected: virtual void contextMenuEvent(QContextMenuEvent *event) override; private: - QMenu *contextMenu; + QMenu* contextMenu{nullptr}; }; #endif // BITCOIN_QT_QRIMAGEWIDGET_H diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index bd4df75d23..b646332001 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,10 +7,8 @@ #include <qt/bitcoinaddressvalidator.h> #include <qt/guiconstants.h> -QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : - QLineEdit(parent), - valid(true), - checkValidator(nullptr) +QValidatedLineEdit::QValidatedLineEdit(QWidget* parent) + : QLineEdit(parent) { connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid); } diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index 12d35aa264..b1ae013957 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -25,8 +25,8 @@ protected: void focusOutEvent(QFocusEvent *evt) override; private: - bool valid; - const QValidator *checkValidator; + bool valid{true}; + const QValidator* checkValidator{nullptr}; public Q_SLOTS: void setText(const QString&); diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index f94486a2f3..c163ba56dc 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -4,8 +4,8 @@ #include <qt/qvaluecombobox.h> -QValueComboBox::QValueComboBox(QWidget *parent) : - QComboBox(parent), role(Qt::UserRole) +QValueComboBox::QValueComboBox(QWidget* parent) + : QComboBox(parent) { connect(this, qOverload<int>(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged); } diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index bde9c0d1a6..14379dd612 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -28,7 +28,7 @@ Q_SIGNALS: void valueChanged(); private: - int role; + int role{Qt::UserRole}; private Q_SLOTS: void handleSelectionChanged(int idx); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 3c80c01160..22eb642ecd 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -25,7 +25,6 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::ReceiveCoinsDialog), - model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index a089b8aa6a..0bb02ebcf2 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -51,7 +51,7 @@ public Q_SLOTS: private: Ui::ReceiveCoinsDialog *ui; - WalletModel *model; + WalletModel* model{nullptr}; QMenu *contextMenu; QAction* copyLabelAction; QAction* copyMessageAction; diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index c0135283b1..3453857f98 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -18,10 +18,9 @@ #include <config/bitcoin-config.h> /* for USE_QRCODE */ #endif -ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : - QDialog(parent, GUIUtil::dialog_flags), - ui(new Ui::ReceiveRequestDialog), - model(nullptr) +ReceiveRequestDialog::ReceiveRequestDialog(QWidget* parent) + : QDialog(parent, GUIUtil::dialog_flags), + ui(new Ui::ReceiveRequestDialog) { ui->setupUi(this); GUIUtil::handleCloseWindowShortcut(this); diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index c861680761..d64fee3663 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -33,7 +33,7 @@ private Q_SLOTS: private: Ui::ReceiveRequestDialog *ui; - WalletModel *model; + WalletModel* model{nullptr}; SendCoinsRecipient info; }; diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 061513b58f..85ade624cf 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index cf7cd24ce2..151f8322a8 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -18,11 +18,11 @@ class WalletModel; class RecentRequestEntry { public: - RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION), id(0) { } + RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION) {} static const int CURRENT_VERSION = 1; int nVersion; - int64_t id; + int64_t id{0}; QDateTime date; SendCoinsRecipient recipient; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a07686ab2b..843cd46d13 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index a3c713e966..32a7520491 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 57094fc857..1604cad503 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -64,11 +64,7 @@ int getIndexForConfTarget(int target) { SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::SendCoinsDialog), - clientModel(nullptr), - model(nullptr), m_coin_control(new CCoinControl), - fNewRecipientAllowed(true), - fFeeMinimized(true), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index dcdf189532..2fcdf5b32a 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -62,12 +62,12 @@ Q_SIGNALS: private: Ui::SendCoinsDialog *ui; - ClientModel *clientModel; - WalletModel *model; + ClientModel* clientModel{nullptr}; + WalletModel* model{nullptr}; std::unique_ptr<wallet::CCoinControl> m_coin_control; std::unique_ptr<WalletModelTransaction> m_current_transaction; - bool fNewRecipientAllowed; - bool fFeeMinimized; + bool fNewRecipientAllowed{true}; + bool fFeeMinimized{true}; const PlatformStyle *platformStyle; // Copy PSBT to clipboard and offer to save it. diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index af514d5a43..0536635c84 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 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,7 +22,6 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::SendCoinsEntry), - model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index ea9d58fbf8..0edc0d1203 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -73,7 +73,7 @@ protected: private: SendCoinsRecipient recipient; Ui::SendCoinsEntry *ui; - WalletModel *model; + WalletModel* model{nullptr}; const PlatformStyle *platformStyle; bool updateLabel(const QString &address); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 1f4b30534b..0e725acb33 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -21,7 +21,6 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::SignVerifyMessageDialog), - model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index 1a3708bf8f..4072707b61 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -35,7 +35,7 @@ protected: private: Ui::SignVerifyMessageDialog *ui; - WalletModel *model; + WalletModel* model{nullptr}; const PlatformStyle *platformStyle; private Q_SLOTS: diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index bf04a6dd5f..096f8a0ded 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -28,7 +28,7 @@ SplashScreen::SplashScreen(const NetworkStyle* networkStyle) - : QWidget(), curAlignment(0) + : QWidget() { // set reference point, paddings int paddingRight = 50; @@ -161,16 +161,6 @@ bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) { return QObject::eventFilter(obj, ev); } -void SplashScreen::finish() -{ - /* If the window is minimized, hide() will be ignored. */ - /* Make sure we de-minimize the splashscreen window before hiding */ - if (isMinimized()) - showNormal(); - hide(); - deleteLater(); // No more need for this -} - static void InitMessage(SplashScreen *splash, const std::string &message) { bool invoked = QMetaObject::invokeMethod(splash, "showMessage", diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index c14fc521a7..2356bbacd3 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,9 +37,6 @@ protected: void closeEvent(QCloseEvent *event) override; public Q_SLOTS: - /** Hide the splash screen window and schedule the splash screen object for deletion */ - void finish(); - /** Show message and progress */ void showMessage(const QString &message, int alignment, const QColor &color); @@ -60,7 +57,7 @@ private: QPixmap pixmap; QString curMessage; QColor curColor; - int curAlignment; + int curAlignment{0}; interfaces::Node* m_node = nullptr; bool m_shutdown = false; diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 581735263d..049326070e 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 6fc7a52435..000bbe65be 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -72,7 +72,7 @@ void AppTests::appTests() qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo"); m_app.parameterSetup(); - QVERIFY(m_app.createOptionsModel(true /* reset settings */)); + QVERIFY(m_app.createOptionsModel(/*resetSettings=*/true)); QScopedPointer<const NetworkStyle> style(NetworkStyle::instantiate(Params().NetworkIDString())); m_app.setupPlatformStyle(); m_app.createWindow(style.data()); diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp index 17ffeb220b..dc7c8928c5 100644 --- a/src/qt/test/optiontests.cpp +++ b/src/qt/test/optiontests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/optiontests.h b/src/qt/test/optiontests.h index 57ec8bd0f2..0c458c97a6 100644 --- a/src/qt/test/optiontests.h +++ b/src/qt/test/optiontests.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 846fa519ee..2d069f76a0 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -79,8 +79,6 @@ int main(int argc, char* argv[]) setenv("QT_QPA_PLATFORM", "minimal", 0 /* overwrite */); #endif - // Don't remove this, it's needed to access - // QApplication:: and QCoreApplication:: in the tests BitcoinApplication app; app.setApplicationName("Bitcoin-Qt-test"); app.createNode(*init); diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp index 635dbcd1c5..c5ed20d967 100644 --- a/src/qt/test/util.cpp +++ b/src/qt/test/util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/util.h b/src/qt/test/util.h index f50a6b6c61..13170c89ea 100644 --- a/src/qt/test/util.h +++ b/src/qt/test/util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index b71dfb0e9f..59a5934890 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -210,17 +210,17 @@ void TestGUI(interfaces::Node& node) // Send two transactions, and verify they are added to transaction list. TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 105); - uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, false /* rbf */); - uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, true /* rbf */); + uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false); + uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true); QCOMPARE(transactionTableModel->rowCount({}), 107); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); // Call bumpfee. Test disabled, canceled, enabled, then failing cases. - BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */); - BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */); - BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */); - BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */); + BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false); + BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true); + BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false); + BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false); // Check current balance on OverviewPage OverviewPage overviewPage(platformStyle.get()); diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index aebd44d5f7..08789c1048 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,15 +19,10 @@ #define XMARGIN 10 #define YMARGIN 10 -TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) : - QWidget(parent), - timer(nullptr), - fMax(0.0f), - vSamplesIn(), - vSamplesOut(), - nLastBytesIn(0), - nLastBytesOut(0), - clientModel(nullptr) +TrafficGraphWidget::TrafficGraphWidget(QWidget* parent) + : QWidget(parent), + vSamplesIn(), + vSamplesOut() { timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &TrafficGraphWidget::updateRates); diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index a40b734540..5e5557ec82 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,14 +37,14 @@ public Q_SLOTS: private: void paintPath(QPainterPath &path, QQueue<float> &samples); - QTimer *timer; - float fMax; + QTimer* timer{nullptr}; + float fMax{0.0f}; std::chrono::minutes m_range{0}; QQueue<float> vSamplesIn; QQueue<float> vSamplesOut; - quint64 nLastBytesIn; - quint64 nLastBytesOut; - ClientModel *clientModel; + quint64 nLastBytesIn{0}; + quint64 nLastBytesOut{0}; + ClientModel* clientModel{nullptr}; }; #endif // BITCOIN_QT_TRAFFICGRAPHWIDGET_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index a61d5407b3..2ced44241f 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index 803e41b699..e64f2cace1 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 3be7e1a969..3cc0cc839d 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -11,14 +11,10 @@ #include <cstdlib> #include <optional> -TransactionFilterProxy::TransactionFilterProxy(QObject *parent) : - QSortFilterProxyModel(parent), - m_search_string(), - typeFilter(ALL_TYPES), - watchOnlyFilter(WatchOnlyFilter_All), - minAmount(0), - limitRows(-1), - showInactive(true) +TransactionFilterProxy::TransactionFilterProxy(QObject* parent) + : QSortFilterProxyModel(parent), + m_search_string(), + typeFilter(ALL_TYPES) { } diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index fd9be52842..8e5f72d764 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -58,10 +58,10 @@ private: std::optional<QDateTime> dateTo; QString m_search_string; quint32 typeFilter; - WatchOnlyFilter watchOnlyFilter; - CAmount minAmount; - int limitRows; - bool showInactive; + WatchOnlyFilter watchOnlyFilter{WatchOnlyFilter_All}; + CAmount minAmount{0}; + int limitRows{-1}; + bool showInactive{true}; }; #endif // BITCOIN_QT_TRANSACTIONFILTERPROXY_H diff --git a/src/qt/transactionoverviewwidget.cpp b/src/qt/transactionoverviewwidget.cpp index 360a1364fb..24b96c861f 100644 --- a/src/qt/transactionoverviewwidget.cpp +++ b/src/qt/transactionoverviewwidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h index 0572e84090..eb9d661996 100644 --- a/src/qt/transactionoverviewwidget.h +++ b/src/qt/transactionoverviewwidget.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 26144ba197..5f981ea250 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index d8748d7dc9..36cfb422e8 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -76,12 +76,12 @@ public: static const int RecommendedNumConfirmations = 6; TransactionRecord(): - hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0) + hash(), time(0), type(Other), debit(0), credit(0), idx(0) { } TransactionRecord(uint256 _hash, qint64 _time): - hash(_hash), time(_time), type(Other), address(""), debit(0), + hash(_hash), time(_time), type(Other), debit(0), credit(0), idx(0) { } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 4312b3cd24..3b32137bd4 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -253,7 +253,6 @@ TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle QAbstractTableModel(parent), walletModel(parent), priv(new TransactionTablePriv(this)), - fProcessingQueuedTransactions(false), platformStyle(_platformStyle) { subscribeToCoreSignals(); diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index f8576edd59..92ba9bf894 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -89,7 +89,7 @@ private: std::unique_ptr<interfaces::Handler> m_handler_show_progress; QStringList columns; TransactionTablePriv *priv; - bool fProcessingQueuedTransactions; + bool fProcessingQueuedTransactions{false}; const PlatformStyle *platformStyle; void subscribeToCoreSignals(); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index b7432a0d77..aa5c82ddb1 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -421,9 +421,6 @@ void TransactionView::abandonTx() // Abandon the wallet transaction over the walletModel model->wallet().abandonTransaction(hash); - - // Update the table - model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false); } void TransactionView::bumpFee([[maybe_unused]] bool checked) diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 331487b51d..eb2ab12a66 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 8762ba9ab3..d782838d6f 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 8dc97e66a2..43411370a2 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -212,7 +212,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard) return; } std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary}; - data.assign(std::istream_iterator<unsigned char>{in}, {}); + data.assign(std::istreambuf_iterator<char>{in}, {}); // Some psbt files may be base64 strings in the file rather than binary data std::string b64_str{data.begin(), data.end()}; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index c6f3f5b00c..cb8491e27a 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -46,10 +46,6 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel m_client_model(&client_model), m_node(client_model.node()), optionsModel(client_model.getOptionsModel()), - addressTableModel(nullptr), - transactionTableModel(nullptr), - recentRequestsTableModel(nullptr), - cachedEncryptionStatus(Unencrypted), timer(new QTimer(this)) { fHaveWatchOnly = m_wallet->haveWatchOnly(); @@ -212,12 +208,12 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return AmountExceedsBalance; } - { + try { CAmount nFeeRequired = 0; int nChangePosRet = -1; auto& newTx = transaction.getWtx(); - const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired); + const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired); newTx = res ? *res : nullptr; transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && newTx) @@ -240,6 +236,11 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact if (nFeeRequired > m_wallet->getDefaultMaxTxFee()) { return AbsurdFee; } + } catch (const std::runtime_error& err) { + // Something unexpected happened, instruct user to report this bug. + Q_EMIT message(tr("Send Coins"), QString::fromStdString(err.what()), + CClientUIInterface::MSG_ERROR); + return TransactionCreationFailed; } return SendCoinsReturn(OK); @@ -258,7 +259,7 @@ void WalletModel::sendCoins(WalletModelTransaction& transaction) } auto& newTx = transaction.getWtx(); - wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm)); + wallet().commitTransaction(newTx, /*value_map=*/{}, std::move(vOrderForm)); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << *newTx; @@ -522,7 +523,9 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) questionString.append(tr("Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.")); } - auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString, "", "", SEND_CONFIRM_DELAY, !m_wallet->privateKeysDisabled(), getOptionsModel()->getEnablePSBTControls(), nullptr); + const bool enable_send{!wallet().privateKeysDisabled() || wallet().hasExternalSigner()}; + const bool always_show_unsigned{getOptionsModel()->getEnablePSBTControls()}; + auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString, "", "", SEND_CONFIRM_DELAY, enable_send, always_show_unsigned, nullptr); confirmationDialog->setAttribute(Qt::WA_DeleteOnClose); // TODO: Replace QDialog::exec() with safer QDialog::show(). const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec()); @@ -540,9 +543,10 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) // Short-circuit if we are returning a bumped transaction PSBT to clipboard if (retval == QMessageBox::Save) { + // "Create Unsigned" clicked PartiallySignedTransaction psbtx(mtx); bool complete = false; - const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete); + const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, nullptr, psbtx, complete); if (err != TransactionError::OK || complete) { QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't draft transaction.")); return false; @@ -555,7 +559,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) return true; } - assert(!m_wallet->privateKeysDisabled()); + assert(!m_wallet->privateKeysDisabled() || wallet().hasExternalSigner()); // sign bumped transaction if (!m_wallet->signBumpTransaction(mtx)) { diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 73dfe0386a..604a9e03c8 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -181,13 +181,13 @@ private: // (transaction fee, for example) OptionsModel *optionsModel; - AddressTableModel *addressTableModel; - TransactionTableModel *transactionTableModel; - RecentRequestsTableModel *recentRequestsTableModel; + AddressTableModel* addressTableModel{nullptr}; + TransactionTableModel* transactionTableModel{nullptr}; + RecentRequestsTableModel* recentRequestsTableModel{nullptr}; // Cache some values to be able to detect changes interfaces::WalletBalances m_cached_balances; - EncryptionStatus cachedEncryptionStatus; + EncryptionStatus cachedEncryptionStatus{Unencrypted}; QTimer* timer; // Block hash denoting when the last balance update was done. diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index b5538b644f..61ccd9dd82 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,9 +10,8 @@ #include <policy/policy.h> -WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) : - recipients(_recipients), - fee(0) +WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient>& _recipients) + : recipients(_recipients) { } diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 28fb551364..0e6ed8be49 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -41,7 +41,7 @@ public: private: QList<SendCoinsRecipient> recipients; CTransactionRef wtx; - CAmount fee; + CAmount fee{0}; }; #endif // BITCOIN_QT_WALLETMODELTRANSACTION_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 10fc0fb6d0..e62821d5bd 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,7 +31,6 @@ WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platformStyle, QWidget* parent) : QStackedWidget(parent), - clientModel(nullptr), walletModel(wallet_model), platformStyle(_platformStyle) { diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 301084ffa9..ebceef9cf9 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -50,7 +50,7 @@ public: void showOutOfSyncWarning(bool fShow); private: - ClientModel *clientModel; + ClientModel* clientModel{nullptr}; //! //! The wallet model represents a bitcoin wallet, and offers access to diff --git a/src/random.cpp b/src/random.cpp index eab54630b1..23ea9ba6b7 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -62,7 +62,7 @@ static inline int64_t GetPerformanceCounter() noexcept __asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx. return (r2 << 32) | r1; #else - // Fall back to using C++11 clock (usually microsecond or nanosecond precision) + // Fall back to using standard library clock (usually microsecond or nanosecond precision) return std::chrono::high_resolution_clock::now().time_since_epoch().count(); #endif } @@ -438,7 +438,7 @@ public: RNGState& GetRNGState() noexcept { - // This C++11 idiom relies on the guarantee that static variable are initialized + // This idiom relies on the guarantee that static variable are initialized // on first call, even when multiple parallel calls are permitted. static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1); return g_rng[0]; diff --git a/src/random.h b/src/random.h index 5fe20c5f76..e890e909c7 100644 --- a/src/random.h +++ b/src/random.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -200,7 +200,7 @@ public: return rand64() >> (64 - bits); } else { if (bitbuf_size < bits) FillBitBuffer(); - uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits)); + uint64_t ret = bitbuf & (~uint64_t{0} >> (64 - bits)); bitbuf >>= bits; bitbuf_size -= bits; return ret; @@ -250,7 +250,7 @@ public: /* interval [0..0] */ Dur{0}; }; - // Compatibility with the C++11 UniformRandomBitGenerator concept + // Compatibility with the UniformRandomBitGenerator concept typedef uint64_t result_type; static constexpr uint64_t min() { return 0; } static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); } diff --git a/src/randomenv.cpp b/src/randomenv.cpp index 9e58180b7a..35d090c71d 100644 --- a/src/randomenv.cpp +++ b/src/randomenv.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -250,7 +250,7 @@ void RandAddDynamicEnv(CSHA512& hasher) gettimeofday(&tv, nullptr); hasher << tv; #endif - // Probably redundant, but also use all the clocks C++11 provides: + // Probably redundant, but also use all the standard library clocks: hasher << std::chrono::system_clock::now().time_since_epoch().count(); hasher << std::chrono::steady_clock::now().time_since_epoch().count(); hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count(); diff --git a/src/rest.cpp b/src/rest.cpp index a10d8a433f..add2bb73b0 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -305,8 +305,10 @@ static bool rest_block(const std::any& context, if (chainman.m_blockman.IsBlockPruned(pblockindex)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); - if (!ReadBlockFromDisk(block, pblockindex, chainman.GetParams().GetConsensus())) - return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); + } + + if (!ReadBlockFromDisk(block, pblockindex, chainman.GetParams().GetConsensus())) { + return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } switch (rf) { diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h index 729d8c11cc..4db001c04b 100644 --- a/src/reverse_iterator.h +++ b/src/reverse_iterator.h @@ -4,7 +4,7 @@ #define BITCOIN_REVERSE_ITERATOR_H /** - * Template used for reverse iteration in C++11 range-based for loops. + * Template used for reverse iteration in range-based for loops. * * std::vector<int> v = {1, 2, 3, 4, 5}; * for (auto x : reverse_iterate(v)) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 027a61ff8b..2b39580043 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -25,6 +25,7 @@ #include <net_processing.h> #include <node/blockstorage.h> #include <node/context.h> +#include <node/transaction.h> #include <node/utxo_snapshot.h> #include <primitives/transaction.h> #include <rpc/server.h> @@ -181,7 +182,8 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn case TxVerbosity::SHOW_DETAILS: case TxVerbosity::SHOW_DETAILS_AND_PREVOUT: CBlockUndo blockUndo; - const bool have_undo{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))}; + const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))}; + const bool have_undo{is_not_pruned && UndoReadFromDisk(blockUndo, blockindex)}; for (size_t i = 0; i < block.vtx.size(); ++i) { const CTransactionRef& tx = block.vtx.at(i); @@ -428,7 +430,9 @@ static RPCHelpMan getblockfrompeer() "getblockfrompeer", "Attempt to fetch block from a given peer.\n\n" "We must have the header for this block, e.g. using submitheader.\n" - "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n\n" + "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n" + "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n" + "When a peer does not respond with a block, we will disconnect.\n\n" "Returns an empty JSON object if the request was successfully scheduled.", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"}, @@ -441,11 +445,6 @@ static RPCHelpMan getblockfrompeer() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValue::VSTR, // blockhash - UniValue::VNUM, // peer_id - }); - const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); PeerManager& peerman = EnsurePeerman(node); @@ -577,30 +576,38 @@ static RPCHelpMan getblockheader() }; } -static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) +static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) { - AssertLockHeld(::cs_main); CBlock block; - if (blockman.IsBlockPruned(pblockindex)) { - throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); + { + LOCK(cs_main); + if (blockman.IsBlockPruned(pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); + } } if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) { // Block not found on disk. This could be because we have the block // header in our index but not yet have the block or did not accept the - // block. + // block. Or if the block was pruned right after we released the lock above. throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); } return block; } -static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) { - AssertLockHeld(::cs_main); CBlockUndo blockUndo; - if (blockman.IsBlockPruned(pblockindex)) { - throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); + + // The Genesis block does not have undo data + if (pblockindex->nHeight == 0) return blockUndo; + + { + LOCK(cs_main); + if (blockman.IsBlockPruned(pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); + } } if (!UndoReadFromDisk(blockUndo, pblockindex)) { @@ -643,7 +650,8 @@ static RPCHelpMan getblock() "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, - {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs"}, + {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs", + RPCArgOptions{.skip_type_check = true}}, }, { RPCResult{"for verbosity = 0", @@ -715,7 +723,6 @@ static RPCHelpMan getblock() } } - CBlock block; const CBlockIndex* pblockindex; const CBlockIndex* tip; ChainstateManager& chainman = EnsureAnyChainman(request.context); @@ -727,10 +734,10 @@ static RPCHelpMan getblock() if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - - block = GetBlockChecked(chainman.m_blockman, pblockindex); } + const CBlock block{GetBlockChecked(chainman.m_blockman, pblockindex)}; + if (verbosity <= 0) { CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); @@ -862,7 +869,11 @@ static RPCHelpMan gettxoutsetinfo() "Note this call may take some time if you are not using coinstatsindex.\n", { {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."}, - {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).", RPCArgOptions{.type_str={"", "string or numeric"}}}, + {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).", + RPCArgOptions{ + .skip_type_check = true, + .type_str = {"", "string or numeric"}, + }}, {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."}, }, RPCResult{ @@ -1732,7 +1743,11 @@ static RPCHelpMan getblockstats() "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" "It won't work for some heights with pruning.\n", { - {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", RPCArgOptions{.type_str={"", "string or numeric"}}}, + {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", + RPCArgOptions{ + .skip_type_check = true, + .type_str = {"", "string or numeric"}, + }}, {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)", { {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"}, @@ -1777,8 +1792,10 @@ static RPCHelpMan getblockstats() {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"}, {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"}, {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"}, - {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs"}, + {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"}, {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"}, + {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"}, + {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"}, }}, RPCExamples{ HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") + @@ -1789,7 +1806,6 @@ static RPCHelpMan getblockstats() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { ChainstateManager& chainman = EnsureAnyChainman(request.context); - LOCK(cs_main); const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))}; std::set<std::string> stats; @@ -1809,7 +1825,7 @@ static RPCHelpMan getblockstats() const bool do_medianfee = do_all || stats.count("medianfee") != 0; const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0; const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles || - SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate"); + SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate"); const bool loop_outputs = do_all || loop_inputs || stats.count("total_out"); const bool do_calculate_size = do_mediantxsize || SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size"); @@ -1831,7 +1847,9 @@ static RPCHelpMan getblockstats() int64_t swtxs = 0; int64_t total_size = 0; int64_t total_weight = 0; + int64_t utxos = 0; int64_t utxo_size_inc = 0; + int64_t utxo_size_inc_actual = 0; std::vector<CAmount> fee_array; std::vector<std::pair<CAmount, int64_t>> feerate_array; std::vector<int64_t> txsize_array; @@ -1844,7 +1862,18 @@ static RPCHelpMan getblockstats() if (loop_outputs) { for (const CTxOut& out : tx->vout) { tx_total_out += out.nValue; - utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + + size_t out_size = GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + utxo_size_inc += out_size; + + // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO + // set counts, so they have to be excluded from the statistics + if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue; + // Skip unspendable outputs since they are not included in the UTXO set + if (out.scriptPubKey.IsUnspendable()) continue; + + ++utxos; + utxo_size_inc_actual += out_size; } } @@ -1886,7 +1915,9 @@ static RPCHelpMan getblockstats() const CTxOut& prevoutput = coin.out; tx_total_in += prevoutput.nValue; - utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + size_t prevout_size = GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + utxo_size_inc -= prevout_size; + utxo_size_inc_actual -= prevout_size; } CAmount txfee = tx_total_in - tx_total_out; @@ -1946,6 +1977,8 @@ static RPCHelpMan getblockstats() ret_all.pushKV("txs", (int64_t)block.vtx.size()); ret_all.pushKV("utxo_increase", outputs - inputs); ret_all.pushKV("utxo_size_inc", utxo_size_inc); + ret_all.pushKV("utxo_increase_actual", utxos - inputs); + ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual); if (do_all) { return ret_all; @@ -2116,8 +2149,6 @@ static RPCHelpMan scantxoutset() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}); - UniValue result(UniValue::VOBJ); if (request.params[0].get_str() == "status") { CoinsViewScanReserver reserver; @@ -2240,17 +2271,47 @@ public: } }; +static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles) +{ + const CBlock block{GetBlockChecked(blockman, &blockindex)}; + const CBlockUndo block_undo{GetUndoChecked(blockman, &blockindex)}; + + // Check if any of the outputs match the scriptPubKey + for (const auto& tx : block.vtx) { + if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) { + return needles.count(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end())) != 0; + })) { + return true; + } + } + // Check if any of the inputs match the scriptPubKey + for (const auto& txundo : block_undo.vtxundo) { + if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) { + return needles.count(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end())) != 0; + })) { + return true; + } + } + + return false; +} + static RPCHelpMan scanblocks() { return RPCHelpMan{"scanblocks", - "\nReturn relevant blockhashes for given descriptors.\n" + "\nReturn relevant blockhashes for given descriptors (requires blockfilterindex).\n" "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", { scan_action_arg_desc, scan_objects_arg_desc, RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"}, RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"}, - RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"} + RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"}, + RPCArg{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", + { + {"filter_false_positives", RPCArg::Type::BOOL, RPCArg::Default{false}, "Filter false positives (slower and may fail on pruned nodes). Otherwise they may occur at a rate of 1/M"}, + }, + RPCArgOptions{.oneline_description="\"options\""}}, }, { scan_result_status_none, @@ -2310,6 +2371,9 @@ static RPCHelpMan scanblocks() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype"); } + UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]}; + bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false}; + BlockFilterIndex* index = GetBlockFilterIndex(filtertype); if (!index) { throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name); @@ -2380,6 +2444,15 @@ static RPCHelpMan scanblocks() for (const BlockFilter& filter : filters) { // compare the elements-set with each filter if (filter.GetFilter().MatchAny(needle_set)) { + if (filter_false_positives) { + // Double check the filter matches by scanning the block + const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash()))); + + if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) { + continue; + } + } + blocks.push_back(filter.GetBlockHash().GetHex()); LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex()); } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 6cdb5fa48b..9ccb87b78a 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,8 +16,6 @@ #include <stdint.h> #include <vector> -extern RecursiveMutex cs_main; - class CBlock; class CBlockIndex; class Chainstate; diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 8688263ef5..5fe914f0a1 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -86,6 +86,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "scanblocks", 1, "scanobjects" }, { "scanblocks", 2, "start_height" }, { "scanblocks", 3, "stop_height" }, + { "scanblocks", 5, "options" }, { "scantxoutset", 1, "scanobjects" }, { "addmultisigaddress", 0, "nrequired" }, { "addmultisigaddress", 1, "keys" }, @@ -102,6 +103,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getchaintxstats", 0, "nblocks" }, { "gettransaction", 1, "include_watchonly" }, { "gettransaction", 2, "verbose" }, + { "getrawtransaction", 1, "verbosity" }, { "getrawtransaction", 1, "verbose" }, { "createrawtransaction", 0, "inputs" }, { "createrawtransaction", 1, "outputs" }, @@ -225,11 +227,16 @@ private: public: CRPCConvertTable(); - bool convert(const std::string& method, int idx) { - return (members.count(std::make_pair(method, idx)) > 0); + /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ + UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, int param_idx) + { + return members.count(std::make_pair(method, param_idx)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; } - bool convert(const std::string& method, const std::string& name) { - return (membersByName.count(std::make_pair(method, name)) > 0); + + /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ + UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, const std::string& param_name) + { + return membersByName.count(std::make_pair(method, param_name)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; } }; @@ -261,14 +268,7 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s for (unsigned int idx = 0; idx < strParams.size(); idx++) { const std::string& strVal = strParams[idx]; - - if (!rpcCvtTable.convert(strMethod, idx)) { - // insert string value directly - params.push_back(strVal); - } else { - // parse string as JSON, insert bool/number/object/etc. value - params.push_back(ParseNonRFCJSONValue(strVal)); - } + params.push_back(rpcCvtTable.ArgToUniValue(strVal, strMethod, idx)); } return params; @@ -277,23 +277,29 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams) { UniValue params(UniValue::VOBJ); + UniValue positional_args{UniValue::VARR}; for (const std::string &s: strParams) { size_t pos = s.find('='); if (pos == std::string::npos) { - throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)")); + positional_args.push_back(rpcCvtTable.ArgToUniValue(s, strMethod, positional_args.size())); + continue; } std::string name = s.substr(0, pos); std::string value = s.substr(pos+1); - if (!rpcCvtTable.convert(strMethod, name)) { - // insert string value directly - params.pushKV(name, value); - } else { - // parse string as JSON, insert bool/number/object/etc. value - params.pushKV(name, ParseNonRFCJSONValue(value)); - } + // Intentionally overwrite earlier named values with later ones as a + // convenience for scripts and command line users that want to merge + // options. + params.pushKV(name, rpcCvtTable.ArgToUniValue(value, strMethod, name)); + } + + if (!positional_args.empty()) { + // Use __pushKV instead of pushKV to avoid overwriting an explicit + // "args" value with an implicit one. Let the RPC server handle the + // request as given. + params.__pushKV("args", positional_args); } return params; diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp index 4de7fc4205..f5a6913572 100644 --- a/src/rpc/external_signer.cpp +++ b/src/rpc/external_signer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index e50bf00473..62396d4c58 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -63,8 +63,6 @@ static RPCHelpMan estimatesmartfee() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR}); - CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context); const NodeContext& node = EnsureAnyNodeContext(request.context); const CTxMemPool& mempool = EnsureMemPool(node); @@ -155,8 +153,6 @@ static RPCHelpMan estimaterawfee() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true); - CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context); unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 039a4328e3..44f7435a26 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -10,6 +10,7 @@ #include <chainparams.h> #include <core_io.h> #include <fs.h> +#include <kernel/mempool_entry.h> #include <node/mempool_persist_args.h> #include <policy/rbf.h> #include <policy/settings.h> @@ -18,11 +19,12 @@ #include <rpc/server_util.h> #include <rpc/util.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <univalue.h> #include <util/moneystr.h> #include <util/time.h> +#include <utility> + using kernel::DumpMempool; using node::DEFAULT_MAX_RAW_TX_FEE_RATE; @@ -59,11 +61,6 @@ static RPCHelpMan sendrawtransaction() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValue::VSTR, - UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() - }); - CMutableTransaction mtx; if (!DecodeHexTx(mtx, request.params[0].get_str())) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); @@ -124,6 +121,10 @@ static RPCHelpMan testmempoolaccept() {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)", { {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, + {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/false, "the effective feerate in " + CURRENCY_UNIT + " per KvB. May differ from the base feerate if, for example, there are modified fees from prioritisetransaction or a package feerate was used."}, + {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.", + {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"}, + }}, }}, {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"}, }}, @@ -141,10 +142,6 @@ static RPCHelpMan testmempoolaccept() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValue::VARR, - UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() - }); const UniValue raw_transactions = request.params[0].get_array(); if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) { throw JSONRPCError(RPC_INVALID_PARAMETER, @@ -215,6 +212,12 @@ static RPCHelpMan testmempoolaccept() result_inner.pushKV("vsize", virtual_size); UniValue fees(UniValue::VOBJ); fees.pushKV("base", ValueFromAmount(fee)); + fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK())); + UniValue effective_includes_res(UniValue::VARR); + for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) { + effective_includes_res.push_back(wtxid.ToString()); + } + fees.pushKV("effective-includes", effective_includes_res); result_inner.pushKV("fees", fees); } } else { @@ -449,19 +452,17 @@ static RPCHelpMan getmempoolancestors() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); } - CTxMemPool::setEntries setAncestors; - std::string dummy; - mempool.CalculateMemPoolAncestors(*it, setAncestors, CTxMemPool::Limits::NoLimits(), dummy, false); + auto ancestors{mempool.AssumeCalculateMemPoolAncestors(__func__, *it, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)}; if (!fVerbose) { UniValue o(UniValue::VARR); - for (CTxMemPool::txiter ancestorIt : setAncestors) { + for (CTxMemPool::txiter ancestorIt : ancestors) { o.push_back(ancestorIt->GetTx().GetHash().ToString()); } return o; } else { UniValue o(UniValue::VOBJ); - for (CTxMemPool::txiter ancestorIt : setAncestors) { + for (CTxMemPool::txiter ancestorIt : ancestors) { const CTxMemPoolEntry &e = *ancestorIt; const uint256& _hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); @@ -768,10 +769,13 @@ static RPCHelpMan submitpackage() {RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141."}, {RPCResult::Type::OBJ, "fees", "Transaction fees", { {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, + {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/true, "if the transaction was not already in the mempool, the effective feerate in " + CURRENCY_UNIT + " per KvB. For example, the package feerate and/or feerate with modified fees from prioritisetransaction."}, + {RPCResult::Type::ARR, "effective-includes", /*optional=*/true, "if effective-feerate is provided, the wtxids of the transactions whose fees and vsizes are included in effective-feerate.", + {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"}, + }}, }}, }} }}, - {RPCResult::Type::STR_AMOUNT, "package-feerate", /*optional=*/true, "package feerate used for feerate checks in " + CURRENCY_UNIT + " per KvB. Excludes transactions which were deduplicated or accepted individually."}, {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions", { {RPCResult::Type::STR_HEX, "", "The transaction id"}, @@ -787,9 +791,6 @@ static RPCHelpMan submitpackage() if (!Params().IsMockableChain()) { throw std::runtime_error("submitpackage is for regression testing (-regtest mode) only"); } - RPCTypeCheck(request.params, { - UniValue::VARR, - }); const UniValue raw_transactions = request.params[0].get_array(); if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) { throw JSONRPCError(RPC_INVALID_PARAMETER, @@ -856,6 +857,7 @@ static RPCHelpMan submitpackage() CHECK_NONFATAL(it != package_result.m_tx_results.end()); UniValue result_inner{UniValue::VOBJ}; result_inner.pushKV("txid", tx->GetHash().GetHex()); + const auto& tx_result = it->second; if (it->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS) { result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex()); } @@ -864,6 +866,17 @@ static RPCHelpMan submitpackage() result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()}); UniValue fees(UniValue::VOBJ); fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value())); + if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) { + // Effective feerate is not provided for MEMPOOL_ENTRY transactions even + // though modified fees is known, because it is unknown whether package + // feerate was used when it was originally submitted. + fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK())); + UniValue effective_includes_res(UniValue::VARR); + for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) { + effective_includes_res.push_back(wtxid.ToString()); + } + fees.pushKV("effective-includes", effective_includes_res); + } result_inner.pushKV("fees", fees); if (it->second.m_replaced_transactions.has_value()) { for (const auto& ptx : it->second.m_replaced_transactions.value()) { @@ -874,9 +887,6 @@ static RPCHelpMan submitpackage() tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), result_inner); } rpc_result.pushKV("tx-results", tx_result_map); - if (package_result.m_package_feerate.has_value()) { - rpc_result.pushKV("package-feerate", ValueFromAmount(package_result.m_package_feerate.value().GetFeePerK())); - } UniValue replaced_list(UniValue::VARR); for (const uint256& hash : replaced_txids) replaced_list.push_back(hash.ToString()); rpc_result.pushKV("replaced-transactions", replaced_list); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 98383fdaca..764c4c675b 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 8d7f4e7f5b..f0e5b90509 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -114,7 +114,7 @@ static RPCHelpMan getpeerinfo() { {RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"} }}, - {RPCResult::Type::BOOL, "relaytxes", /*optional=*/true, "Whether we relay transactions to this peer"}, + {RPCResult::Type::BOOL, "relaytxes", "Whether we relay transactions to this peer"}, {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"}, {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"}, {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"}, @@ -131,17 +131,17 @@ static RPCHelpMan getpeerinfo() {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"}, {RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"}, {RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"}, - {RPCResult::Type::NUM, "startingheight", /*optional=*/true, "The starting height (block) of the peer"}, - {RPCResult::Type::NUM, "presynced_headers", /*optional=*/true, "The current height of header pre-synchronization with this peer, or -1 if no low-work sync is in progress"}, - {RPCResult::Type::NUM, "synced_headers", /*optional=*/true, "The last header we have in common with this peer"}, - {RPCResult::Type::NUM, "synced_blocks", /*optional=*/true, "The last block we have in common with this peer"}, - {RPCResult::Type::ARR, "inflight", /*optional=*/true, "", + {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"}, + {RPCResult::Type::NUM, "presynced_headers", "The current height of header pre-synchronization with this peer, or -1 if no low-work sync is in progress"}, + {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"}, + {RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"}, + {RPCResult::Type::ARR, "inflight", "", { {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"}, }}, - {RPCResult::Type::BOOL, "addr_relay_enabled", /*optional=*/true, "Whether we participate in address relay with this peer"}, - {RPCResult::Type::NUM, "addr_processed", /*optional=*/true, "The total number of addresses processed, excluding those dropped due to rate limiting"}, - {RPCResult::Type::NUM, "addr_rate_limited", /*optional=*/true, "The total number of addresses dropped due to rate limiting"}, + {RPCResult::Type::BOOL, "addr_relay_enabled", "Whether we participate in address relay with this peer"}, + {RPCResult::Type::NUM, "addr_processed", "The total number of addresses processed, excluding those dropped due to rate limiting"}, + {RPCResult::Type::NUM, "addr_rate_limited", "The total number of addresses dropped due to rate limiting"}, {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer", { {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"}, @@ -185,6 +185,14 @@ static RPCHelpMan getpeerinfo() UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; bool fStateStats = peerman.GetNodeStateStats(stats.nodeid, statestats); + // GetNodeStateStats() requires the existence of a CNodeState and a Peer object + // to succeed for this peer. These are created at connection initialisation and + // exist for the duration of the connection - except if there is a race where the + // peer got disconnected in between the GetNodeStats() and the GetNodeStateStats() + // calls. In this case, the peer doesn't need to be reported here. + if (!fStateStats) { + continue; + } obj.pushKV("id", stats.nodeid); obj.pushKV("addr", stats.m_addr_name); if (stats.addrBind.IsValid()) { @@ -197,12 +205,10 @@ static RPCHelpMan getpeerinfo() if (stats.m_mapped_as != 0) { obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); } - ServiceFlags services{fStateStats ? statestats.their_services : ServiceFlags::NODE_NONE}; + ServiceFlags services{statestats.their_services}; obj.pushKV("services", strprintf("%016x", services)); obj.pushKV("servicesnames", GetServicesNames(services)); - if (fStateStats) { - obj.pushKV("relaytxes", statestats.m_relay_txs); - } + obj.pushKV("relaytxes", statestats.m_relay_txs); obj.pushKV("lastsend", count_seconds(stats.m_last_send)); obj.pushKV("lastrecv", count_seconds(stats.m_last_recv)); obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time)); @@ -217,7 +223,7 @@ static RPCHelpMan getpeerinfo() if (stats.m_min_ping_time < std::chrono::microseconds::max()) { obj.pushKV("minping", Ticks<SecondsDouble>(stats.m_min_ping_time)); } - if (fStateStats && statestats.m_ping_wait > 0s) { + if (statestats.m_ping_wait > 0s) { obj.pushKV("pingwait", Ticks<SecondsDouble>(statestats.m_ping_wait)); } obj.pushKV("version", stats.nVersion); @@ -228,26 +234,24 @@ static RPCHelpMan getpeerinfo() obj.pushKV("inbound", stats.fInbound); obj.pushKV("bip152_hb_to", stats.m_bip152_highbandwidth_to); obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from); - if (fStateStats) { - obj.pushKV("startingheight", statestats.m_starting_height); - obj.pushKV("presynced_headers", statestats.presync_height); - obj.pushKV("synced_headers", statestats.nSyncHeight); - obj.pushKV("synced_blocks", statestats.nCommonHeight); - UniValue heights(UniValue::VARR); - for (const int height : statestats.vHeightInFlight) { - heights.push_back(height); - } - obj.pushKV("inflight", heights); - obj.pushKV("addr_relay_enabled", statestats.m_addr_relay_enabled); - obj.pushKV("addr_processed", statestats.m_addr_processed); - obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited); + obj.pushKV("startingheight", statestats.m_starting_height); + obj.pushKV("presynced_headers", statestats.presync_height); + obj.pushKV("synced_headers", statestats.nSyncHeight); + obj.pushKV("synced_blocks", statestats.nCommonHeight); + UniValue heights(UniValue::VARR); + for (const int height : statestats.vHeightInFlight) { + heights.push_back(height); } + obj.pushKV("inflight", heights); + obj.pushKV("addr_relay_enabled", statestats.m_addr_relay_enabled); + obj.pushKV("addr_processed", statestats.m_addr_processed); + obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited); UniValue permissions(UniValue::VARR); for (const auto& permission : NetPermissions::ToStrings(stats.m_permission_flags)) { permissions.push_back(permission); } obj.pushKV("permissions", permissions); - obj.pushKV("minfeefilter", fStateStats ? ValueFromAmount(statestats.m_fee_filter_received) : 0); + obj.pushKV("minfeefilter", ValueFromAmount(statestats.m_fee_filter_received)); UniValue sendPerMsgType(UniValue::VOBJ); for (const auto& i : stats.mapSendBytesPerMsgType) { @@ -354,7 +358,6 @@ static RPCHelpMan addconnection() throw std::runtime_error("addconnection is for regression testing (-regtest mode) only."); } - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR}); const std::string address = request.params[0].get_str(); const std::string conn_type_in{TrimString(request.params[1].get_str())}; ConnectionType conn_type{}; @@ -731,9 +734,11 @@ static RPCHelpMan setban() if (!request.params[2].isNull()) banTime = request.params[2].getInt<int64_t>(); - bool absolute = false; - if (request.params[3].isTrue()) - absolute = true; + const bool absolute{request.params[3].isNull() ? false : request.params[3].get_bool()}; + + if (absolute && banTime < GetTime()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Absolute timestamp is in the past"); + } if (isSubnet) { node.banman->Ban(subNet, banTime, absolute); @@ -942,7 +947,7 @@ static RPCHelpMan addpeeraddress() const std::string& addr_string{request.params[0].get_str()}; const auto port{request.params[1].getInt<uint16_t>()}; - const bool tried{request.params[2].isTrue()}; + const bool tried{request.params[2].isNull() ? false : request.params[2].get_bool()}; UniValue obj(UniValue::VOBJ); CNetAddr net_addr; diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 605ebc15a7..79b8277968 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,7 @@ #include <interfaces/echo.h> #include <interfaces/init.h> #include <interfaces/ipc.h> +#include <kernel/cs_main.h> #include <node/context.h> #include <rpc/server.h> #include <rpc/server_util.h> @@ -52,7 +53,6 @@ static RPCHelpMan setmocktime() // ensure all call sites of GetTime() are accessing this safely. LOCK(cs_main); - RPCTypeCheck(request.params, {UniValue::VNUM}); const int64_t time{request.params[0].getInt<int64_t>()}; if (time < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime cannot be negative: %s.", time)); @@ -106,8 +106,6 @@ static RPCHelpMan mockscheduler() throw std::runtime_error("mockscheduler is for regression testing (-regtest mode) only"); } - // check params are valid values - RPCTypeCheck(request.params, {UniValue::VNUM}); int64_t delta_seconds = request.params[0].getInt<int64_t>(); if (delta_seconds <= 0 || delta_seconds > 3600) { throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)"); @@ -295,18 +293,18 @@ static RPCHelpMan echo(const std::string& name) "\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\n" "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in " "bitcoin-cli and the GUI. There is no server-side difference.", - { - {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, - }, + { + {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "", RPCArgOptions{.skip_type_check = true}}, + }, RPCResult{RPCResult::Type::ANY, "", "Returns whatever was passed in"}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp index a980c609e8..911c769e61 100644 --- a/src/rpc/output_script.cpp +++ b/src/rpc/output_script.cpp @@ -195,8 +195,6 @@ static RPCHelpMan getdescriptorinfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR}); - FlatSigningProvider provider; std::string error; auto desc = Parse(request.params[0].get_str(), provider, error); @@ -222,10 +220,11 @@ static RPCHelpMan deriveaddresses() return RPCHelpMan{"deriveaddresses", {"\nDerives one or more addresses corresponding to an output descriptor.\n" "Examples of output descriptors are:\n" - " pkh(<pubkey>) P2PKH outputs for the given pubkey\n" - " wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n" - " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n" - " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n" + " pkh(<pubkey>) P2PKH outputs for the given pubkey\n" + " wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n" + " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n" + " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n" + " tr(<pubkey>,multi_a(<n>,<pubkey>,<pubkey>,...)) P2TR-multisig outputs for the given threshold and pubkeys\n" "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n" "or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n" "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"}, @@ -246,7 +245,6 @@ static RPCHelpMan deriveaddresses() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later const std::string desc_str = request.params[0].get_str(); int64_t range_begin = 0; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d654de1862..981dead3b8 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -32,6 +32,7 @@ #include <script/signingprovider.h> #include <script/standard.h> #include <uint256.h> +#include <undo.h> #include <util/bip32.h> #include <util/check.h> #include <util/strencodings.h> @@ -50,15 +51,17 @@ using node::FindCoins; using node::GetTransaction; using node::NodeContext; using node::PSBTAnalysis; +using node::ReadBlockFromDisk; +using node::UndoReadFromDisk; -static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, Chainstate& active_chainstate) +static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, Chainstate& active_chainstate, const CTxUndo* txundo = nullptr, TxVerbosity verbosity = TxVerbosity::SHOW_TXID) { // Call into TxToUniv() in bitcoin-common to decode the transaction hex. // // Blockchain contextual information (confirmations and blocktime) is not // available to code in bitcoin-common, so we query them here and push the // data into the returned UniValue. - TxToUniv(tx, /*block_hash=*/uint256(), entry, /*include_hex=*/true, RPCSerializationFlags()); + TxToUniv(tx, /*block_hash=*/uint256(), entry, /*include_hex=*/true, RPCSerializationFlags(), txundo, verbosity); if (!hashBlock.IsNull()) { LOCK(cs_main); @@ -77,6 +80,17 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& } } +static std::vector<RPCResult> ScriptPubKeyDoc() { + return + { + {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, + {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, + {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, + {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"}, + }; +} + static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc) { return { @@ -112,14 +126,7 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc) { {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT}, {RPCResult::Type::NUM, "n", "index"}, - {RPCResult::Type::OBJ, "scriptPubKey", "", - { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, - {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, - {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"}, - {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, - {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, - }}, + {RPCResult::Type::OBJ, "scriptPubKey", "", ScriptPubKeyDoc()}, }}, }}, }; @@ -155,7 +162,7 @@ static std::vector<RPCArg> CreateTxDoc() }, }, }, - }, + RPCArgOptions{.skip_type_check = true}}, {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Marks this transaction as BIP125-replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, @@ -166,26 +173,27 @@ static RPCHelpMan getrawtransaction() { return RPCHelpMan{ "getrawtransaction", - "Return the raw transaction data.\n" - "\nBy default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n" + "By default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n" "and no blockhash argument is passed, it will return the transaction if it is in the mempool or any block.\n" "If a blockhash argument is passed, it will return the transaction if\n" - "the specified block is available and the transaction is in that block.\n" - "\nHint: Use gettransaction for wallet transactions.\n" + "the specified block is available and the transaction is in that block.\n\n" + "Hint: Use gettransaction for wallet transactions.\n\n" - "\nIf verbose is 'true', returns an Object with information about 'txid'.\n" - "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.", + "If verbosity is 0 or omitted, returns the serialized transaction as a hex-encoded string.\n" + "If verbosity is 1, returns a JSON Object with information about the transaction.\n" + "If verbosity is 2, returns a JSON Object with information about the transaction, including fee and prevout information.", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, - {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If false, return a string, otherwise return a json object"}, + {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for hex-encoded data, 1 for a JSON object, and 2 for JSON object with fee and prevout", + RPCArgOptions{.skip_type_check = true}}, {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"}, }, { - RPCResult{"if verbose is not set or set to false", - RPCResult::Type::STR, "data", "The serialized, hex-encoded data for 'txid'" + RPCResult{"if verbosity is not set or set to 0", + RPCResult::Type::STR, "data", "The serialized transaction as a hex-encoded string for 'txid'" }, - RPCResult{"if verbose is set to true", + RPCResult{"if verbosity is set to 1", RPCResult::Type::OBJ, "", "", Cat<std::vector<RPCResult>>( { @@ -198,20 +206,40 @@ static RPCHelpMan getrawtransaction() }, DecodeTxDoc(/*txid_field_doc=*/"The transaction id (same as provided)")), }, + RPCResult{"for verbosity = 2", + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"}, + {RPCResult::Type::NUM, "fee", /*optional=*/true, "transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"}, + {RPCResult::Type::ARR, "vin", "", + { + {RPCResult::Type::OBJ, "", "utxo being spent, omitted if block undo data is not available", + { + {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"}, + {RPCResult::Type::OBJ, "prevout", /*optional=*/true, "Only if undo information is available)", + { + {RPCResult::Type::BOOL, "generated", "Coinbase or not"}, + {RPCResult::Type::NUM, "height", "The height of the prevout"}, + {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT}, + {RPCResult::Type::OBJ, "scriptPubKey", "", ScriptPubKeyDoc()}, + }}, + }}, + }}, + }}, }, RPCExamples{ HelpExampleCli("getrawtransaction", "\"mytxid\"") - + HelpExampleCli("getrawtransaction", "\"mytxid\" true") - + HelpExampleRpc("getrawtransaction", "\"mytxid\", true") - + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"") - + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"") + + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") + + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") + + HelpExampleCli("getrawtransaction", "\"mytxid\" 0 \"myblockhash\"") + + HelpExampleCli("getrawtransaction", "\"mytxid\" 1 \"myblockhash\"") + + HelpExampleCli("getrawtransaction", "\"mytxid\" 2 \"myblockhash\"") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); - bool in_active_chain = true; uint256 hash = ParseHashV(request.params[0], "parameter 1"); const CBlockIndex* blockindex = nullptr; @@ -220,10 +248,14 @@ static RPCHelpMan getrawtransaction() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved"); } - // Accept either a bool (true) or a num (>=1) to indicate verbose output. - bool fVerbose = false; + // Accept either a bool (true) or a num (>=0) to indicate verbosity. + int verbosity{0}; if (!request.params[1].isNull()) { - fVerbose = request.params[1].isNum() ? (request.params[1].getInt<int>() != 0) : request.params[1].get_bool(); + if (request.params[1].isBool()) { + verbosity = request.params[1].get_bool(); + } else { + verbosity = request.params[1].getInt<int>(); + } } if (!request.params[2].isNull()) { @@ -234,7 +266,6 @@ static RPCHelpMan getrawtransaction() if (!blockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); } - in_active_chain = chainman.ActiveChain().Contains(blockindex); } bool f_txindex_ready = false; @@ -262,13 +293,43 @@ static RPCHelpMan getrawtransaction() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions."); } - if (!fVerbose) { + if (verbosity <= 0) { return EncodeHexTx(*tx, RPCSerializationFlags()); } UniValue result(UniValue::VOBJ); - if (blockindex) result.pushKV("in_active_chain", in_active_chain); - TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); + if (blockindex) { + LOCK(cs_main); + result.pushKV("in_active_chain", chainman.ActiveChain().Contains(blockindex)); + } + // If request is verbosity >= 1 but no blockhash was given, then look up the blockindex + if (request.params[2].isNull()) { + LOCK(cs_main); + blockindex = chainman.m_blockman.LookupBlockIndex(hash_block); + } + if (verbosity == 1) { + TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); + return result; + } + + CBlockUndo blockUndo; + CBlock block; + const bool is_block_pruned{WITH_LOCK(cs_main, return chainman.m_blockman.IsBlockPruned(blockindex))}; + + if (tx->IsCoinBase() || + !blockindex || is_block_pruned || + !(UndoReadFromDisk(blockUndo, blockindex) && ReadBlockFromDisk(block, blockindex, Params().GetConsensus()))) { + TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); + return result; + } + + CTxUndo* undoTX {nullptr}; + auto it = std::find_if(block.vtx.begin(), block.vtx.end(), [tx](CTransactionRef t){ return *t == *tx; }); + if (it != block.vtx.end()) { + // -1 as blockundo does not have coinbase tx + undoTX = &blockUndo.vtxundo.at(it - block.vtx.begin() - 1); + } + TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate(), undoTX, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); return result; }, }; @@ -294,17 +355,9 @@ static RPCHelpMan createrawtransaction() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValue::VARR, - UniValueType(), // ARR or OBJ, checked later - UniValue::VNUM, - UniValue::VBOOL - }, true - ); - std::optional<bool> rbf; if (!request.params[3].isNull()) { - rbf = request.params[3].isTrue(); + rbf = request.params[3].get_bool(); } CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf); @@ -337,8 +390,6 @@ static RPCHelpMan decoderawtransaction() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); - CMutableTransaction mtx; bool try_witness = request.params[1].isNull() ? true : request.params[1].get_bool(); @@ -391,8 +442,6 @@ static RPCHelpMan decodescript() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR}); - UniValue r(UniValue::VOBJ); CScript script; if (request.params[0].get_str().size() > 0){ @@ -642,8 +691,6 @@ static RPCHelpMan signrawtransactionwithkey() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); - CMutableTransaction mtx; if (!DecodeHexTx(mtx, request.params[0].get_str())) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); @@ -921,8 +968,6 @@ static RPCHelpMan decodepsbt() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR}); - // Unserialize the transactions PartiallySignedTransaction psbtx; std::string error; @@ -1335,8 +1380,6 @@ static RPCHelpMan combinepsbt() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VARR}, true); - // Unserialize the transactions std::vector<PartiallySignedTransaction> psbtxs; UniValue txs = request.params[0].get_array(); @@ -1390,8 +1433,6 @@ static RPCHelpMan finalizepsbt() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); - // Unserialize the transactions PartiallySignedTransaction psbtx; std::string error; @@ -1439,17 +1480,9 @@ static RPCHelpMan createpsbt() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValue::VARR, - UniValueType(), // ARR or OBJ, checked later - UniValue::VNUM, - UniValue::VBOOL, - }, true - ); - std::optional<bool> rbf; if (!request.params[3].isNull()) { - rbf = request.params[3].isTrue(); + rbf = request.params[3].get_bool(); } CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf); @@ -1500,8 +1533,6 @@ static RPCHelpMan converttopsbt() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true); - // parse hex string from parameter CMutableTransaction tx; bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool(); @@ -1563,8 +1594,6 @@ static RPCHelpMan utxoupdatepsbt() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true); - // Unserialize the transactions PartiallySignedTransaction psbtx; std::string error; @@ -1654,8 +1683,6 @@ static RPCHelpMan joinpsbts() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VARR}, true); - // Unserialize the transactions std::vector<PartiallySignedTransaction> psbtxs; UniValue txs = request.params[0].get_array(); @@ -1782,8 +1809,6 @@ static RPCHelpMan analyzepsbt() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, {UniValue::VSTR}); - // Unserialize the transaction PartiallySignedTransaction psbtx; std::string error; diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index b078ee8b29..15b8e1dcd0 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h index 9b5c9f08d4..0c3823bc1e 100644 --- a/src/rpc/rawtransaction_util.h +++ b/src/rpc/rawtransaction_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/register.h b/src/rpc/register.h index 301f410da3..c88f49ecf0 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index 8595fa78bb..0bb5533d71 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 1d7bd2eb94..9f57a56297 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -103,7 +103,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& { UniValue unused_result; if (setDone.insert(pcmd->unique_id).second) - pcmd->actor(jreq, unused_result, true /* last_handler */); + pcmd->actor(jreq, unused_result, /*last_handler=*/true); } catch (const std::exception& e) { @@ -399,10 +399,21 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c const std::vector<UniValue>& values = in.params.getValues(); std::unordered_map<std::string, const UniValue*> argsIn; for (size_t i=0; i<keys.size(); ++i) { - argsIn[keys[i]] = &values[i]; + auto [_, inserted] = argsIn.emplace(keys[i], &values[i]); + if (!inserted) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times"); + } } - // Process expected parameters. + // Process expected parameters. If any parameters were left unspecified in + // the request before a parameter that was specified, null values need to be + // inserted at the unspecifed parameter positions, and the "hole" variable + // below tracks the number of null values that need to be inserted. + // The "initial_hole_size" variable stores the size of the initial hole, + // i.e. how many initial positional arguments were left unspecified. This is + // used after the for-loop to add initial positional arguments from the + // "args" parameter, if present. int hole = 0; + int initial_hole_size = 0; for (const std::string &argNamePattern: argNames) { std::vector<std::string> vargNames = SplitString(argNamePattern, '|'); auto fr = argsIn.end(); @@ -424,6 +435,24 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c argsIn.erase(fr); } else { hole += 1; + if (out.params.empty()) initial_hole_size = hole; + } + } + // If leftover "args" param was found, use it as a source of positional + // arguments and add named arguments after. This is a convenience for + // clients that want to pass a combination of named and positional + // arguments as described in doc/JSON-RPC-interface.md#parameter-passing + auto positional_args{argsIn.extract("args")}; + if (positional_args && positional_args.mapped()->isArray()) { + const bool has_named_arguments{initial_hole_size < (int)argNames.size()}; + if (initial_hole_size < (int)positional_args.mapped()->size() && has_named_arguments) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + argNames[initial_hole_size] + " specified twice both as positional and named argument"); + } + // Assign positional_args to out.params and append named_args after. + UniValue named_args{std::move(out.params)}; + out.params = *positional_args.mapped(); + for (size_t i{out.params.size()}; i < named_args.size(); ++i) { + out.params.push_back(named_args[i]); } } // If there are still arguments in the argsIn map, this is an error. diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp index 6a1b41f066..50f9ce7b3c 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h index 2cc710a803..fa008a8155 100644 --- a/src/rpc/server_util.h +++ b/src/rpc/server_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index cd8b49bfe1..8c5468634d 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -84,13 +84,13 @@ static RPCHelpMan gettxoutproof() g_txindex->BlockUntilSyncedToCurrentChain(); } - LOCK(cs_main); - if (pblockindex == nullptr) { const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), chainman.GetConsensus(), hashBlock); if (!tx || hashBlock.IsNull()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); } + + LOCK(cs_main); pblockindex = chainman.m_blockman.LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index dd5739faf7..9619c3df99 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -30,23 +30,6 @@ std::string GetAllOutputTypes() return Join(ret, ", "); } -void RPCTypeCheck(const UniValue& params, - const std::list<UniValueType>& typesExpected, - bool fAllowNull) -{ - unsigned int i = 0; - for (const UniValueType& t : typesExpected) { - if (params.size() <= i) - break; - - const UniValue& v = params[i]; - if (!(fAllowNull && v.isNull())) { - RPCTypeCheckArgument(v, t); - } - i++; - } -} - void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected) { if (!typeExpected.typeAny && value.type() != typeExpected.type) { @@ -405,6 +388,7 @@ struct Sections { const auto indent = std::string(current_indent, ' '); const auto indent_next = std::string(current_indent + 2, ' '); const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name + const bool is_top_level_arg{outer_type == OuterType::NONE}; // True on the first recursion switch (arg.m_type) { case RPCArg::Type::STR_HEX: @@ -413,7 +397,7 @@ struct Sections { case RPCArg::Type::AMOUNT: case RPCArg::Type::RANGE: case RPCArg::Type::BOOL: { - if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion + if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion auto left = indent; if (arg.m_opts.type_str.size() != 0 && push_name) { left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0); @@ -421,12 +405,12 @@ struct Sections { left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false); } left += ","; - PushSection({left, arg.ToDescriptionString()}); + PushSection({left, arg.ToDescriptionString(/*is_named_arg=*/push_name)}); break; } case RPCArg::Type::OBJ: case RPCArg::Type::OBJ_USER_KEYS: { - const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString(); + const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name); PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right}); for (const auto& arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::OBJ); @@ -434,20 +418,20 @@ struct Sections { if (arg.m_type != RPCArg::Type::OBJ) { PushSection({indent_next + "...", ""}); } - PushSection({indent + "}" + (outer_type != OuterType::NONE ? "," : ""), ""}); + PushSection({indent + "}" + (is_top_level_arg ? "" : ","), ""}); break; } case RPCArg::Type::ARR: { auto left = indent; left += push_name ? "\"" + arg.GetName() + "\": " : ""; left += "["; - const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString(); + const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name); PushSection({left, right}); for (const auto& arg_inner : arg.m_inner) { Push(arg_inner, current_indent + 2, OuterType::ARR); } PushSection({indent_next + "...", ""}); - PushSection({indent + "]" + (outer_type != OuterType::NONE ? "," : ""), ""}); + PushSection({indent + "]" + (is_top_level_arg ? "" : ","), ""}); break; } } // no default case, so the compiler can warn about missing cases @@ -579,7 +563,10 @@ UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) { throw std::runtime_error(ToString()); } - const UniValue ret = m_fun(*this, request); + for (size_t i{0}; i < m_args.size(); ++i) { + m_args.at(i).MatchesType(request.params[i]); + } + UniValue ret = m_fun(*this, request); if (gArgs.GetBoolArg("-rpcdoccheck", DEFAULT_RPC_DOC_CHECK)) { CHECK_NONFATAL(std::any_of(m_results.m_results.begin(), m_results.m_results.end(), [&ret](const RPCResult& res) { return res.MatchesType(ret); })); } @@ -641,7 +628,7 @@ std::string RPCHelpMan::ToString() const if (i == 0) ret += "\nArguments:\n"; // Push named argument name and description - sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString()); + sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true)); sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size()); // Recursively push nested args @@ -677,6 +664,44 @@ UniValue RPCHelpMan::GetArgMap() const return arr; } +void RPCArg::MatchesType(const UniValue& request) const +{ + if (m_opts.skip_type_check) return; + if (IsOptional() && request.isNull()) return; + switch (m_type) { + case Type::STR_HEX: + case Type::STR: { + RPCTypeCheckArgument(request, UniValue::VSTR); + return; + } + case Type::NUM: { + RPCTypeCheckArgument(request, UniValue::VNUM); + return; + } + case Type::AMOUNT: { + // VNUM or VSTR, checked inside AmountFromValue() + return; + } + case Type::RANGE: { + // VNUM or VARR, checked inside ParseRange() + return; + } + case Type::BOOL: { + RPCTypeCheckArgument(request, UniValue::VBOOL); + return; + } + case Type::OBJ: + case Type::OBJ_USER_KEYS: { + RPCTypeCheckArgument(request, UniValue::VOBJ); + return; + } + case Type::ARR: { + RPCTypeCheckArgument(request, UniValue::VARR); + return; + } + } // no default case, so the compiler can warn about missing cases +} + std::string RPCArg::GetFirstName() const { return m_names.substr(0, m_names.find("|")); @@ -697,7 +722,7 @@ bool RPCArg::IsOptional() const } } -std::string RPCArg::ToDescriptionString() const +std::string RPCArg::ToDescriptionString(bool is_named_arg) const { std::string ret; ret += "("; @@ -743,14 +768,12 @@ std::string RPCArg::ToDescriptionString() const ret += ", optional, default=" + std::get<RPCArg::Default>(m_fallback).write(); } else { switch (std::get<RPCArg::Optional>(m_fallback)) { + case RPCArg::Optional::OMITTED_NAMED_ARG: // Deprecated alias for OMITTED, can be removed case RPCArg::Optional::OMITTED: { + if (is_named_arg) ret += ", optional"; // Default value is "null" in dicts. Otherwise, // nothing to do. Element is treated as if not present and has no default value break; } - case RPCArg::Optional::OMITTED_NAMED_ARG: { - ret += ", optional"; // Default value is "null" - break; - } case RPCArg::Optional::NO: { ret += ", required"; break; diff --git a/src/rpc/util.h b/src/rpc/util.h index 9aa5df00b1..30c46bfdcd 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -63,13 +63,6 @@ struct UniValueType { }; /** - * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that - * the right number of arguments are passed, just that any passed are the correct type. - */ -void RPCTypeCheck(const UniValue& params, - const std::list<UniValueType>& typesExpected, bool fAllowNull=false); - -/** * Type-check one argument; throws JSONRPCError if wrong type given. */ void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected); @@ -138,6 +131,7 @@ enum class OuterType { }; struct RPCArgOptions { + bool skip_type_check{false}; std::string oneline_description{}; //!< Should be empty unless it is supposed to override the auto-generated summary line std::vector<std::string> type_str{}; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_opts.type_str.at(0) will override the type of the value in a key-value pair, m_opts.type_str.at(1) will override the type in the argument description. bool hidden{false}; //!< For testing only @@ -160,21 +154,24 @@ struct RPCArg { /** Required arg */ NO, /** + * The arg is optional for one of two reasons: + * * Optional arg that is a named argument and has a default value of - * `null`. When possible, the default value should be specified. - */ - OMITTED_NAMED_ARG, - /** + * `null`. + * * Optional argument with default value omitted because they are - * implicitly clear. That is, elements in an array or object may not + * implicitly clear. That is, elements in an array may not * exist by default. * When possible, the default value should be specified. */ OMITTED, + OMITTED_NAMED_ARG, // Deprecated alias for OMITTED, can be removed }; + /** Hint for default value */ using DefaultHint = std::string; + /** Default constant value */ using Default = UniValue; - using Fallback = std::variant<Optional, /* hint for default value */ DefaultHint, /* default constant value */ Default>; + using Fallback = std::variant<Optional, DefaultHint, Default>; const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments) const Type m_type; @@ -184,10 +181,10 @@ struct RPCArg { const RPCArgOptions m_opts; RPCArg( - const std::string name, - const Type type, - const Fallback fallback, - const std::string description, + std::string name, + Type type, + Fallback fallback, + std::string description, RPCArgOptions opts = {}) : m_names{std::move(name)}, m_type{std::move(type)}, @@ -199,11 +196,11 @@ struct RPCArg { } RPCArg( - const std::string name, - const Type type, - const Fallback fallback, - const std::string description, - const std::vector<RPCArg> inner, + std::string name, + Type type, + Fallback fallback, + std::string description, + std::vector<RPCArg> inner, RPCArgOptions opts = {}) : m_names{std::move(name)}, m_type{std::move(type)}, @@ -217,6 +214,9 @@ struct RPCArg { bool IsOptional() const; + /** Check whether the request JSON type matches. */ + void MatchesType(const UniValue& request) const; + /** Return the first of all aliases */ std::string GetFirstName() const; @@ -237,7 +237,7 @@ struct RPCArg { * Return the description string, including the argument type and whether * the argument is required. */ - std::string ToDescriptionString() const; + std::string ToDescriptionString(bool is_named_arg) const; }; struct RPCResult { @@ -266,12 +266,12 @@ struct RPCResult { const std::string m_cond; RPCResult( - const std::string cond, - const Type type, - const std::string m_key_name, - const bool optional, - const std::string description, - const std::vector<RPCResult> inner = {}) + std::string cond, + Type type, + std::string m_key_name, + bool optional, + std::string description, + std::vector<RPCResult> inner = {}) : m_type{std::move(type)}, m_key_name{std::move(m_key_name)}, m_inner{std::move(inner)}, @@ -285,19 +285,19 @@ struct RPCResult { } RPCResult( - const std::string cond, - const Type type, - const std::string m_key_name, - const std::string description, - const std::vector<RPCResult> inner = {}) - : RPCResult{cond, type, m_key_name, false, description, inner} {} + std::string cond, + Type type, + std::string m_key_name, + std::string description, + std::vector<RPCResult> inner = {}) + : RPCResult{std::move(cond), type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner)} {} RPCResult( - const Type type, - const std::string m_key_name, - const bool optional, - const std::string description, - const std::vector<RPCResult> inner = {}, + Type type, + std::string m_key_name, + bool optional, + std::string description, + std::vector<RPCResult> inner = {}, bool skip_type_check = false) : m_type{std::move(type)}, m_key_name{std::move(m_key_name)}, @@ -311,12 +311,12 @@ struct RPCResult { } RPCResult( - const Type type, - const std::string m_key_name, - const std::string description, - const std::vector<RPCResult> inner = {}, + Type type, + std::string m_key_name, + std::string description, + std::vector<RPCResult> inner = {}, bool skip_type_check = false) - : RPCResult{type, m_key_name, false, description, inner, skip_type_check} {} + : RPCResult{type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner), skip_type_check} {} /** Append the sections of the result. */ void ToSections(Sections& sections, OuterType outer_type = OuterType::NONE, const int current_indent = 0) const; diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 3df1d48b3c..1c9aedc10b 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/scheduler.h b/src/scheduler.h index 749e5442b0..9212582b97 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index f7f9dfc262..4fab481b39 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -62,12 +62,6 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror) return 0; } -struct ECCryptoClosure -{ - ECCVerifyHandle handle; -}; - -ECCryptoClosure instance_of_eccryptoclosure; } // namespace /** Check that all specified flags are part of the libconsensus interface. */ diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index 8fea42e4b9..f2f2ff8686 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index c06d0370c9..03b157a847 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1303,7 +1303,7 @@ public: // Serialize the nSequence if (nInput != nIn && (fHashSingle || fHashNone)) // let the others update at will - ::Serialize(s, (int)0); + ::Serialize(s, int{0}); else ::Serialize(s, txTo.vin[nInput].nSequence); } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 790098f9df..ac1013302d 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/miniscript.cpp b/src/script/miniscript.cpp index cb4d4cb783..5e471cbe89 100644 --- a/src/script/miniscript.cpp +++ b/src/script/miniscript.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/miniscript.h b/src/script/miniscript.h index 6faf2624fd..fa3b0350e9 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/script.cpp b/src/script/script.cpp index 88b4bc2f44..79d19b9085 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/script.h b/src/script/script.h index 1e5f694d52..374ae1642e 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index e507ec7528..fef3601887 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 290955090d..d33d60d5bc 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 53377560e8..d369d4960d 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/sign.h b/src/script/sign.h index 813dfe04e3..b32bb55dd3 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index a82a8b252a..5123dd81ac 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h index 2d4234ea0b..a5bbcff6a0 100644 --- a/src/script/signingprovider.h +++ b/src/script/signingprovider.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 2b7c120eaf..7c4a05b6e6 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/standard.h b/src/script/standard.h index 60b5bd38e7..18cf5c8c88 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml index a2e7f36d1f..51e3bc9484 100644 --- a/src/secp256k1/.cirrus.yml +++ b/src/secp256k1/.cirrus.yml @@ -26,6 +26,11 @@ env: # Compile and run the tests EXAMPLES: yes +# https://cirrus-ci.org/pricing/#compute-credits +credits_snippet: &CREDITS + # Don't use any credits for now. + use_compute_credits: false + cat_logs_snippet: &CAT_LOGS always: cat_tests_log_script: @@ -36,7 +41,6 @@ cat_logs_snippet: &CAT_LOGS - cat valgrind_ctime_test.log || true cat_bench_log_script: - cat bench.log || true - on_failure: cat_config_log_script: - cat config.log || true cat_test_env_script: @@ -69,6 +73,7 @@ task: - env: {WIDEMUL: int64, RECOVERY: yes} - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes} - env: {WIDEMUL: int128} + - env: {WIDEMUL: int128_struct} - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes} - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes} - env: {WIDEMUL: int128, ASM: x86_64} @@ -107,65 +112,32 @@ task: << : *CAT_LOGS task: - name: "x86_64: macOS Catalina" + name: "arm64: macOS Ventura" macos_instance: - image: catalina-base + image: ghcr.io/cirruslabs/macos-ventura-base:latest env: HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 - # Cirrus gives us a fixed number of 12 virtual CPUs. Not that we even have that many jobs at the moment... - MAKEFLAGS: -j13 + # Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment... + MAKEFLAGS: -j5 matrix: << : *ENV_MATRIX + env: + ASM: no + WITH_VALGRIND: no + CTIMETEST: no matrix: - env: - CC: gcc-9 + CC: gcc - env: CC: clang - # Update Command Line Tools - # Uncomment this if the Command Line Tools on the CirrusCI macOS image are too old to brew valgrind. - # See https://apple.stackexchange.com/a/195963 for the implementation. - ## update_clt_script: - ## - system_profiler SPSoftwareDataType - ## - touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress - ## - |- - ## PROD=$(softwareupdate -l | grep "*.*Command Line" | tail -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | sed 's/Label: //g' | tr -d '\n') - ## # For debugging - ## - softwareupdate -l && echo "PROD: $PROD" - ## - softwareupdate -i "$PROD" --verbose - ## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress - ## - brew_valgrind_pre_script: - # Retry a few times because this tends to fail randomly. - - for i in {1..5}; do brew update && break || sleep 15; done - - brew config - - brew tap LouisBrunner/valgrind - # Fetch valgrind source but don't build it yet. - - brew fetch --HEAD LouisBrunner/valgrind/valgrind - brew_valgrind_cache: - # This is $(brew --cellar valgrind) but command substition does not work here. - folder: /usr/local/Cellar/valgrind - # Rebuild cache if ... - fingerprint_script: - # ... macOS version changes: - - sw_vers - # ... brew changes: - - brew config - # ... valgrind changes: - - git -C "$(brew --cache)/valgrind--git" rev-parse HEAD - populate_script: - # If there's no hit in the cache, build and install valgrind. - - brew install --HEAD LouisBrunner/valgrind/valgrind - brew_valgrind_post_script: - # If we have restored valgrind from the cache, tell brew to create symlink to the PATH. - # If we haven't restored from cached (and just run brew install), this is a no-op. - - brew link valgrind brew_script: - - brew install automake libtool gcc@9 + - brew install automake libtool gcc << : *MERGE_BASE test_script: - ./ci/cirrus.sh << : *CAT_LOGS + << : *CREDITS task: name: "s390x (big-endian): Linux (Debian stable, QEMU)" @@ -241,17 +213,63 @@ task: << : *CAT_LOGS task: - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" << : *LINUX_CONTAINER env: - WRAPPER_CMD: wine64-stable - SECP256K1_TEST_ITERS: 16 - HOST: x86_64-w64-mingw32 + WRAPPER_CMD: wine WITH_VALGRIND: no ECDH: yes RECOVERY: yes SCHNORRSIG: yes CTIMETEST: no + matrix: + - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" + env: + HOST: x86_64-w64-mingw32 + - name: "i686 (mingw32-w64): Windows (Debian stable, Wine)" + env: + HOST: i686-w64-mingw32 + << : *MERGE_BASE + test_script: + - ./ci/cirrus.sh + << : *CAT_LOGS + +task: + << : *LINUX_CONTAINER + env: + WRAPPER_CMD: wine + WERROR_CFLAGS: -WX + WITH_VALGRIND: no + ECDH: yes + RECOVERY: yes + EXPERIMENTAL: yes + SCHNORRSIG: yes + CTIMETEST: no + # Use a MinGW-w64 host to tell ./configure we're building for Windows. + # This will detect some MinGW-w64 tools but then make will need only + # the MSVC tools CC, AR and NM as specified below. + HOST: x86_64-w64-mingw32 + CC: /opt/msvc/bin/x64/cl + AR: /opt/msvc/bin/x64/lib + NM: /opt/msvc/bin/x64/dumpbin -symbols -headers + # Set non-essential options that affect the CLI messages here. + # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.) + CFLAGS: -nologo -diagnostics:caret + LDFLAGS: -XCClinker -nologo -XCClinker -diagnostics:caret + matrix: + - name: "x86_64 (MSVC): Windows (Debian stable, Wine)" + - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)" + env: + WIDEMUL: int128_struct + - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)" + env: + WIDEMUL: int128_struct + CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE + - name: "i686 (MSVC): Windows (Debian stable, Wine)" + env: + HOST: i686-w64-mingw32 + CC: /opt/msvc/bin/x86/cl + AR: /opt/msvc/bin/x86/lib + NM: /opt/msvc/bin/x86/dumpbin -symbols -headers << : *MERGE_BASE test_script: - ./ci/cirrus.sh @@ -301,14 +319,39 @@ task: - ./ci/cirrus.sh << : *CAT_LOGS +# Memory sanitizers task: - name: "C++ -fpermissive" << : *LINUX_CONTAINER + name: "MSan" env: - # ./configure correctly errors out when given CC=g++. - # We hack around this by passing CC=g++ only to make. - CC: gcc - MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g + ECDH: yes + RECOVERY: yes + SCHNORRSIG: yes + CTIMETEST: no + CC: clang + SECP256K1_TEST_ITERS: 32 + ASM: no + container: + memory: 2G + matrix: + - env: + CFLAGS: "-fsanitize=memory -g" + - env: + ECMULTGENPRECISION: 2 + ECMULTWINDOW: 2 + CFLAGS: "-fsanitize=memory -g -O3" + << : *MERGE_BASE + test_script: + - ./ci/cirrus.sh + << : *CAT_LOGS + +task: + name: "C++ -fpermissive (entire project)" + << : *LINUX_CONTAINER + env: + CC: g++ + CFLAGS: -fpermissive -g + CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE WERROR_CFLAGS: ECDH: yes RECOVERY: yes @@ -319,6 +362,14 @@ task: << : *CAT_LOGS task: + name: "C++ (public headers)" + << : *LINUX_CONTAINER + test_script: + - g++ -Werror include/*.h + - clang -Werror -x c++-header include/*.h + - /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h + +task: name: "sage prover" << : *LINUX_CONTAINER test_script: diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index d88627d72e..80c646b771 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -13,9 +13,9 @@ schnorr_example *.so *.a *.csv -!.gitignore *.log *.trs +*.sage.py Makefile configure @@ -34,8 +34,6 @@ libtool *.lo *.o *~ -*.log -*.trs coverage/ coverage.html diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md new file mode 100644 index 0000000000..7443483423 --- /dev/null +++ b/src/secp256k1/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Unreleased] + +## [0.2.0] - 2022-12-12 + +### Added + - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`. + +### Changed + - Enabled modules schnorrsig, extrakeys and ECDH by default in `./configure`. + +### Deprecated + - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. + - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. + +### ABI Compatibility + +Since this is the first release, we do not compare application binary interfaces. +However, there are unreleased versions of libsecp256k1 that are *not* ABI compatible with this version. + +## [0.1.0] - 2013-03-05 to 2021-12-25 + +This version was in fact never released. +The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). +Therefore, this version number does not uniquely identify a set of source files. diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index 51c5960301..ad50504f7e 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -48,6 +48,12 @@ noinst_HEADERS += src/precomputed_ecmult.h noinst_HEADERS += src/precomputed_ecmult_gen.h noinst_HEADERS += src/assumptions.h noinst_HEADERS += src/util.h +noinst_HEADERS += src/int128.h +noinst_HEADERS += src/int128_impl.h +noinst_HEADERS += src/int128_native.h +noinst_HEADERS += src/int128_native_impl.h +noinst_HEADERS += src/int128_struct.h +noinst_HEADERS += src/int128_struct_impl.h noinst_HEADERS += src/scratch.h noinst_HEADERS += src/scratch_impl.h noinst_HEADERS += src/selftest.h @@ -58,7 +64,6 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h -noinst_HEADERS += src/basic-config.h noinst_HEADERS += contrib/lax_der_parsing.h noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h @@ -87,7 +92,7 @@ endif endif libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES) libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) @@ -112,7 +117,7 @@ TESTS = if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) if VALGRIND_ENABLED tests_CPPFLAGS += -DVALGRIND noinst_PROGRAMS += valgrind_ctime_test @@ -211,7 +216,15 @@ maintainer-clean-local: clean-precomp clean-precomp: rm -f $(PRECOMP) -EXTRA_DIST = autogen.sh SECURITY.md +EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md +EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md +EXTRA_DIST += examples/EXAMPLES_COPYING +EXTRA_DIST += sage/gen_exhaustive_groups.sage +EXTRA_DIST += sage/gen_split_lambda_constants.sage +EXTRA_DIST += sage/group_prover.sage +EXTRA_DIST += sage/prove_group_implementations.sage +EXTRA_DIST += sage/secp256k1_params.sage +EXTRA_DIST += sage/weierstrass_prover.sage if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index f5db915e83..ffdc9aeaee 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -2,6 +2,8 @@ libsecp256k1 ============ [![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1) +![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) +[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1) Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1. @@ -15,6 +17,7 @@ Features: * Derandomized ECDSA (via RFC6979 or with a caller provided function.) * Very efficient implementation. * Suitable for embedded systems. +* No runtime dependencies. * Optional module for public key recovery. * Optional module for ECDH key exchange. * Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki). @@ -72,11 +75,12 @@ To compile optional modules (such as Schnorr signatures), you need to run `./con Usage examples ----------- - Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. +Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. * [ECDSA example](examples/ecdsa.c) * [Schnorr signatures example](examples/schnorr.c) * [Deriving a shared secret (ECDH) example](examples/ecdh.c) - To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. + +To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. Test coverage ----------- diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 index 9cb54de098..98be915b67 100644 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -10,6 +10,7 @@ AC_MSG_RESULT([$has_64bit_asm]) ]) AC_DEFUN([SECP_VALGRIND_CHECK],[ +AC_MSG_CHECKING([for valgrind support]) if test x"$has_valgrind" != x"yes"; then CPPFLAGS_TEMP="$CPPFLAGS" CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS" @@ -21,6 +22,7 @@ if test x"$has_valgrind" != x"yes"; then #endif ]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])]) fi +AC_MSG_RESULT($has_valgrind) ]) dnl SECP_TRY_APPEND_CFLAGS(flags, VAR) diff --git a/src/secp256k1/ci/cirrus.sh b/src/secp256k1/ci/cirrus.sh index b85f012d3f..fb5854a777 100755 --- a/src/secp256k1/ci/cirrus.sh +++ b/src/secp256k1/ci/cirrus.sh @@ -5,10 +5,47 @@ set -x export LC_ALL=C +# Print relevant CI environment to allow reproducing the job outside of CI. +print_environment() { + # Turn off -x because it messes up the output + set +x + # There are many ways to print variable names and their content. This one + # does not rely on bash. + for i in WERROR_CFLAGS MAKEFLAGS BUILD \ + ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ + EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETEST\ + EXAMPLES \ + WRAPPER_CMD CC AR NM HOST + do + eval 'printf "%s %s " "$i=\"${'"$i"'}\""' + done + echo "$0" + set -x +} +print_environment + +# Start persistent wineserver if necessary. +# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously. +case "$WRAPPER_CMD" in + *wine*) + # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards. + wineserver -p && wine hh.exe + ;; +esac + env >> test_env.log -$CC -v || true -valgrind --version || true +if [ -n "$CC" ]; then + # The MSVC compiler "cl" doesn't understand "-v" + $CC -v || true +fi +if [ "$WITH_VALGRIND" = "yes" ]; then + valgrind --version +fi +if [ -n "$WRAPPER_CMD" ]; then + $WRAPPER_CMD --version +fi ./autogen.sh @@ -63,6 +100,9 @@ then make precomp fi +# Shutdown wineserver again +wineserver -k || true + # Check that no repo files have been modified by the build. # (This fails for example if the precomp files need to be updated in the repo.) git diff --exit-code diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile index 5cccbb5565..a83a4e36db 100644 --- a/src/secp256k1/ci/linux-debian.Dockerfile +++ b/src/secp256k1/ci/linux-debian.Dockerfile @@ -1,15 +1,14 @@ FROM debian:stable -RUN dpkg --add-architecture i386 -RUN dpkg --add-architecture s390x -RUN dpkg --add-architecture armhf -RUN dpkg --add-architecture arm64 -RUN dpkg --add-architecture ppc64el -RUN apt-get update +RUN dpkg --add-architecture i386 && \ + dpkg --add-architecture s390x && \ + dpkg --add-architecture armhf && \ + dpkg --add-architecture arm64 && \ + dpkg --add-architecture ppc64el # dkpg-dev: to make pkg-config work in cross-builds # llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces -RUN apt-get install --no-install-recommends --no-upgrade -y \ +RUN apt-get update && apt-get install --no-install-recommends -y \ git ca-certificates \ make automake libtool pkg-config dpkg-dev valgrind qemu-user \ gcc clang llvm libc6-dbg \ @@ -19,8 +18,20 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ - wine gcc-mingw-w64-x86-64 \ + gcc-mingw-w64-x86-64-win32 wine64 wine \ + gcc-mingw-w64-i686-win32 wine32 \ sagemath -# Run a dummy command in wine to make it set up configuration -RUN wine64-stable xcopy || true +WORKDIR /root +# The "wine" package provides a convience wrapper that we need +RUN apt-get update && apt-get install --no-install-recommends -y \ + git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \ + git clone https://github.com/mstorsjo/msvc-wine && \ + mkdir /opt/msvc && \ + python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \ + msvc-wine/install.sh /opt/msvc + +# Initialize the wine environment. Wait until the wineserver process has +# exited before closing the session, to avoid corrupting the wine prefix. +RUN wine64 wineboot --init && \ + while (ps -A | grep wineserver) > /dev/null; do sleep 1; done diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 2db59a8ff3..68f279b17b 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -4,20 +4,20 @@ AC_PREREQ([2.60]) # the API. All changes in experimental modules are treated as # backwards-compatible and therefore at most increase the minor version. define(_PKG_VERSION_MAJOR, 0) -define(_PKG_VERSION_MINOR, 1) -define(_PKG_VERSION_BUILD, 0) -define(_PKG_VERSION_IS_RELEASE, false) +define(_PKG_VERSION_MINOR, 2) +define(_PKG_VERSION_PATCH, 0) +define(_PKG_VERSION_IS_RELEASE, true) # The library version is based on libtool versioning of the ABI. The set of # rules for updating the version can be found here: # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. -define(_LIB_VERSION_CURRENT, 0) +define(_LIB_VERSION_CURRENT, 1) define(_LIB_VERSION_REVISION, 0) define(_LIB_VERSION_AGE, 0) -AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_BUILD)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-pre]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) +AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) @@ -33,12 +33,14 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_PROG_CC -if test x"$ac_cv_prog_cc_c89" = x"no"; then - AC_MSG_ERROR([c89 compiler support required]) -fi AM_PROG_AS AM_PROG_AR +# Clear some cache variables as a workaround for a bug that appears due to a bad +# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe. +# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421 +AS_UNSET(ac_cv_prog_AR) +AS_UNSET(ac_cv_prog_ac_ct_AR) LT_INIT([win32-dll]) build_windows=no @@ -87,23 +89,35 @@ esac # # TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues. AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ - # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will - # not error out if it gets unknown warning flags and the checks here will always succeed - # no matter if clang knows the flag or not. - SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" - SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS) - - SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. - SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. - SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers - SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. - SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. - SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 - SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 - SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only - SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 - - CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" + # GCC and compatible (incl. clang) + if test "x$GCC" = "xyes"; then + # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will + # not error out if it gets unknown warning flags and the checks here will always succeed + # no matter if clang knows the flag or not. + SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS" + SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS) + + SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers + SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall. + SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 + SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 + SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only + SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 + + CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" + fi + + # MSVC + # Assume MSVC if we're building for Windows but not with GCC or compatible; + # libtool makes the same assumption internally. + # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path. + if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then + SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned" + SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files + fi ]) SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) @@ -141,27 +155,31 @@ AC_ARG_ENABLE(examples, [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])]) + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])]) AC_ARG_ENABLE(module_recovery, AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) AC_ARG_ENABLE(module_extrakeys, - AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])]) + AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) AC_ARG_ENABLE(module_schnorrsig, - AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [], - [SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])]) + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) AC_ARG_ENABLE(external_default_callbacks, AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) # Test-only override of the (autodetected by the C code) "widemul" setting. -# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default). +# Legal values are: +# * int64 (for [u]int64_t), +# * int128 (for [unsigned] __int128), +# * int128_struct (for int128 implemented as a structure), +# * and auto (the default). AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], @@ -271,6 +289,9 @@ fi # Select wide multiplication implementation case $set_widemul in +int128_struct) + AC_DEFINE(USE_FORCE_WIDEMUL_INT128_STRUCT, 1, [Define this symbol to force the use of the structure for simulating (unsigned) int128 based wide multiplication]) + ;; int128) AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation]) ;; @@ -326,7 +347,9 @@ if test x"$enable_valgrind" = x"yes"; then SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS" fi -# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI) +# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). +# We don't want to set the user variable CFLAGS in CI because this would disable +# autoconf's logic for setting default CFLAGS, which we would like to test in CI. SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" ### diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h index 1a8ad8ae0c..3749e418fe 100644 --- a/src/secp256k1/contrib/lax_der_privatekey_parsing.h +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -43,8 +43,7 @@ extern "C" { /** Export a private key in DER format. * * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: privkey: pointer to an array for storing the private key in BER. * Should have space for 279 bytes, and cannot be NULL. * privkeylen: Pointer to an int where the length of the private key in diff --git a/src/secp256k1/doc/CHANGELOG.md b/src/secp256k1/doc/CHANGELOG.md deleted file mode 100644 index 3c4c2e4583..0000000000 --- a/src/secp256k1/doc/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -# Changelog - -This file is currently only a template for future use. - -Each change falls into one of the following categories: Added, Changed, Deprecated, Removed, Fixed or Security. - -## [Unreleased] - -## [MAJOR.MINOR.PATCH] - YYYY-MM-DD - -### Added/Changed/Deprecated/Removed/Fixed/Security -- [Title with link to Pull Request](https://link-to-pr) diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md index a35b8a9db3..91e3616915 100644 --- a/src/secp256k1/doc/release-process.md +++ b/src/secp256k1/doc/release-process.md @@ -1,14 +1,52 @@ # Release Process -1. Open PR to master that - 1. adds release notes to `doc/CHANGELOG.md` and - 2. if this is **not** a patch release, updates `_PKG_VERSION_{MAJOR,MINOR}` and `_LIB_VERSIONS_*` in `configure.ac` -2. After the PR is merged, - * if this is **not** a patch release, create a release branch with name `MAJOR.MINOR`. - Make sure that the branch contains the right commits. - Create commit on the release branch that sets `_PKG_VERSION_IS_RELEASE` in `configure.ac` to `true`. - * if this **is** a patch release, open a pull request with the bugfixes to the `MAJOR.MINOR` branch. - Also include the release note commit bump `_PKG_VERSION_BUILD` and `_LIB_VERSIONS_*` in `configure.ac`. -4. Tag the commit with `git tag -s vMAJOR.MINOR.PATCH`. -5. Push branch and tag with `git push origin --tags`. -6. Create a new GitHub release with a link to the corresponding entry in `doc/CHANGELOG.md`. +This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`. + +We distinguish between two types of releases: *regular* and *maintenance* releases. +Regular releases are releases of a new major or minor version as well as patches of the most recent release. +Maintenance releases, on the other hand, are required for patches of older releases. + +You should coordinate with the other maintainers on the release date, if possible. +This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release). +It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3. + +This process also assumes that there will be no minor releases for old major releases. + +## Regular release + +1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that + * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`) and + * updates `_PKG_VERSION_*`, `_LIB_VERSION_*`, and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`. +2. After the PR is merged, tag the commit and push it: + ``` + RELEASE_COMMIT=<merge commit of step 1> + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +3. Open a PR to the master branch with a commit (using message `"release: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that sets `_PKG_VERSION_IS_RELEASE` to `false` and `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs. +4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). + +## Maintenance release + +Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists. + +1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`: + ``` + git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0 + git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR + ``` +2. Open a pull request to the `$MAJOR.$MINOR` branch that + * includes the bugfixes, + * finalizes the release notes, + * bumps `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` (with commit message `"release: update PKG_ and LIB_VERSION for $MAJOR.$MINOR.$PATCH"`, for example). +3. After the PRs are merged, update the release branch and tag the commit: + ``` + git checkout $MAJOR.$MINOR && git pull + git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" + ``` +4. Push tag: + ``` + git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH + ``` +5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). diff --git a/src/secp256k1/examples/ecdh.c b/src/secp256k1/examples/ecdh.c index d7e8add361..027d52fd5f 100644 --- a/src/secp256k1/examples/ecdh.c +++ b/src/secp256k1/examples/ecdh.c @@ -30,12 +30,8 @@ int main(void) { secp256k1_pubkey pubkey1; secp256k1_pubkey pubkey2; - /* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` - * needs a context object initialized for signing, which is why we create - * a context with the SECP256K1_CONTEXT_SIGN flag. - * (The docs for `secp256k1_ecdh` don't require any special context, just - * some initialized context) */ - secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); if (!fill_random(randomize, sizeof(randomize))) { printf("Failed to generate randomness\n"); return 1; diff --git a/src/secp256k1/examples/ecdsa.c b/src/secp256k1/examples/ecdsa.c index 434c856ba0..7e4f1b13ac 100644 --- a/src/secp256k1/examples/ecdsa.c +++ b/src/secp256k1/examples/ecdsa.c @@ -38,12 +38,8 @@ int main(void) { int return_val; secp256k1_pubkey pubkey; secp256k1_ecdsa_signature sig; - /* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs - * a context object initialized for signing and `secp256k1_ecdsa_verify` needs - * a context initialized for verification, which is why we create a context - * for both signing and verification with the SECP256K1_CONTEXT_SIGN and - * SECP256K1_CONTEXT_VERIFY flags. */ - secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); if (!fill_random(randomize, sizeof(randomize))) { printf("Failed to generate randomness\n"); return 1; diff --git a/src/secp256k1/examples/schnorr.c b/src/secp256k1/examples/schnorr.c index 82eb07d5d7..207c45c422 100644 --- a/src/secp256k1/examples/schnorr.c +++ b/src/secp256k1/examples/schnorr.c @@ -30,12 +30,8 @@ int main(void) { int return_val; secp256k1_xonly_pubkey pubkey; secp256k1_keypair keypair; - /* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create` - * needs a context object initialized for signing. And in secp256k1_schnorrsig.h - * they state that `secp256k1_schnorrsig_verify` needs a context initialized for - * verification, which is why we create a context for both signing and verification - * with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */ - secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + /* Before we can call actual API functions, we need to create a "context". */ + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); if (!fill_random(randomize, sizeof(randomize))) { printf("Failed to generate randomness\n"); return 1; diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index dddab346ae..826ab75850 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -7,7 +7,7 @@ extern "C" { #include <stddef.h> -/* Unless explicitly stated all pointer arguments must not be NULL. +/** Unless explicitly stated all pointer arguments must not be NULL. * * The following rules specify the order of arguments in API calls: * @@ -24,15 +24,19 @@ extern "C" { * 5. Opaque data pointers follow the function pointer they are to be passed to. */ -/** Opaque data structure that holds context information (precomputed tables etc.). +/** Opaque data structure that holds context information * - * The purpose of context structures is to cache large precomputed data tables - * that are expensive to construct, and also to maintain the randomization data - * for blinding. + * The primary purpose of context objects is to store randomization data for + * enhanced protection against side-channel leakage. This protection is only + * effective if the context is randomized after its creation. See + * secp256k1_context_create for creation of contexts and + * secp256k1_context_randomize for randomization. * - * Do not create a new context object for each operation, as construction is - * far slower than all other API calls (~100 times slower than an ECDSA - * verification). + * A secondary purpose of context objects is to store pointers to callback + * functions that the library will call when certain error states arise. See + * secp256k1_context_set_error_callback as well as + * secp256k1_context_set_illegal_callback for details. Future library versions + * may use context objects for additional purposes. * * A constructed context can safely be used from multiple threads * simultaneously, but API calls that take a non-const pointer to a context @@ -45,7 +49,7 @@ extern "C" { */ typedef struct secp256k1_context_struct secp256k1_context; -/** Opaque data structure that holds rewriteable "scratch space" +/** Opaque data structure that holds rewritable "scratch space" * * The purpose of this structure is to replace dynamic memory allocations, * because we target architectures where this may not be available. It is @@ -130,7 +134,7 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_INLINE inline # endif -/** When this header is used at build-time the SECP256K1_BUILD define needs to be set +/* When this header is used at build-time the SECP256K1_BUILD define needs to be set * to correctly setup export attributes and nullness checks. This is normally done * by secp256k1.c but to guard against this header being included before secp256k1.c * has had a chance to set the define (e.g. via test harnesses that just includes @@ -159,9 +163,9 @@ typedef int (*secp256k1_nonce_function)( # endif #endif -/**Warning attributes - * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out - * some paranoid null checks. */ +/* Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ # if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) # define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) # else @@ -173,7 +177,7 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_ARG_NONNULL(_x) # endif -/** Attribute for marking functions, types, and variables as deprecated */ +/* Attribute for marking functions, types, and variables as deprecated */ #if !defined(SECP256K1_BUILD) && defined(__has_attribute) # if __has_attribute(__deprecated__) # define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg))) @@ -184,22 +188,26 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_DEPRECATED(_msg) #endif -/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +/* All flags' lower 8 bits indicate what they're for. Do not use directly. */ #define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) #define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) -/** The higher bits contain the actual data. Do not use directly. */ +/* The higher bits contain the actual data. Do not use directly. */ #define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) #define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) #define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10) #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) -/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and +/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and * secp256k1_context_preallocated_create. */ +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */ #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) + +/* Testing flag. Do not use. */ #define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY) -#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) /** Flag to pass to secp256k1_ec_pubkey_serialize. */ #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) @@ -212,23 +220,66 @@ typedef int (*secp256k1_nonce_function)( #define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 #define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 -/** A simple secp256k1 context object with no precomputed tables. These are useful for - * type serialization/parsing functions which require a context object to maintain - * API consistency, but currently do not require expensive precomputations or dynamic - * allocations. +/** A built-in constant secp256k1 context object with static storage duration, to be + * used in conjunction with secp256k1_selftest. + * + * This context object offers *only limited functionality* , i.e., it cannot be used + * for API functions that perform computations involving secret keys, e.g., signing + * and public key generation. If this restriction applies to a specific API function, + * it is mentioned in its documentation. See secp256k1_context_create if you need a + * full context object that supports all functionality offered by the library. + * + * It is highly recommended to call secp256k1_selftest before using this context. + */ +SECP256K1_API extern const secp256k1_context *secp256k1_context_static; + +/** Deprecated alias for secp256k1_context_static. */ +SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp +SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); + +/** Perform basic self tests (to be used in conjunction with secp256k1_context_static) + * + * This function performs self tests that detect some serious usage errors and + * similar conditions, e.g., when the library is compiled for the wrong endianness. + * This is a last resort measure to be used in production. The performed tests are + * very rudimentary and are not intended as a replacement for running the test + * binaries. + * + * It is highly recommended to call this before using secp256k1_context_static. + * It is not necessary to call this function before using a context created with + * secp256k1_context_create (or secp256k1_context_preallocated_create), which will + * take care of performing the self tests. + * + * If the tests fail, this function will call the default error handler to abort the + * program (see secp256k1_context_set_error_callback). */ -SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp; +SECP256K1_API void secp256k1_selftest(void); + /** Create a secp256k1 context object (in dynamically allocated memory). * * This function uses malloc to allocate memory. It is guaranteed that malloc is * called at most once for every call of this function. If you need to avoid dynamic - * memory allocation entirely, see the functions in secp256k1_preallocated.h. + * memory allocation entirely, see secp256k1_context_static and the functions in + * secp256k1_preallocated.h. * * Returns: a newly created context object. - * In: flags: which parts of the context to initialize. + * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). + * + * The only valid non-deprecated flag in recent library versions is + * SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality + * offered by the library. All other (deprecated) flags will be treated as equivalent + * to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for + * historical reasons, future versions of the library may introduce new flags. * - * See also secp256k1_context_randomize. + * If the context is intended to be used for API functions that perform computations + * involving secret keys, e.g., signing and public key generation, then it is highly + * recommended to call secp256k1_context_randomize on the context before calling + * those API functions. This will provide enhanced protection against side-channel + * leakage, see secp256k1_context_randomize for details. + * + * Do not create a new context object for each operation, as construction and + * randomization can take non-negligible time. */ SECP256K1_API secp256k1_context* secp256k1_context_create( unsigned int flags @@ -308,7 +359,10 @@ SECP256K1_API void secp256k1_context_set_illegal_callback( ) SECP256K1_ARG_NONNULL(1); /** Set a callback function to be called when an internal consistency check - * fails. The default is crashing. + * fails. + * + * The default callback writes an error message to stderr and calls abort + * to abort the program. * * This can only trigger in case of a hardware failure, miscompilation, * memory corruption, serious bug in the library, or other error would can @@ -426,8 +480,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp( * encoding is invalid. R and S with value 0 are allowed in the encoding. * * After the call, sig will always be initialized. If parsing failed or R or - * S are zero, the resulting sig value is guaranteed to fail validation for any - * message and public key. + * S are zero, the resulting sig value is guaranteed to fail verification for + * any message and public key. */ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( const secp256k1_context* ctx, @@ -447,7 +501,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( * encoded numbers are out of range. * * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is + * encoded numbers are out of range, signature verification with it is * guaranteed to fail for every message and public key. */ SECP256K1_API int secp256k1_ecdsa_signature_parse_der( @@ -494,7 +548,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( * * Returns: 1: correct signature * 0: incorrect or unparseable signature - * Args: ctx: a secp256k1 context object, initialized for verification. + * Args: ctx: a secp256k1 context object. * In: sig: the signature being verified. * msghash32: the 32-byte message hash being verified. * The verifier must make sure to apply a cryptographic @@ -511,7 +565,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( * * If you need to accept ECDSA signatures from sources that do not obey this * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to - * validation, but be aware that doing so results in malleable signatures. + * verification, but be aware that doing so results in malleable signatures. * * For details, see the comments for that function. */ @@ -582,7 +636,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def * * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: sig: pointer to an array where the signature will be placed. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. @@ -626,7 +680,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( * * Returns: 1: secret was valid, public key stores. * 0: secret was invalid, try again. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: pubkey: pointer to the created public key. * In: seckey: pointer to a 32-byte secret key. */ @@ -705,7 +759,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( * Returns: 0 if the arguments are invalid or the resulting public key would be * invalid (only when the tweak is the negation of the corresponding * secret key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation. + * Args: ctx: pointer to a context object. * In/Out: pubkey: pointer to a public key object. pubkey will be set to an * invalid value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to @@ -750,7 +804,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( /** Tweak a public key by multiplying it by a tweak value. * * Returns: 0 if the arguments are invalid. 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation. + * Args: ctx: pointer to a context object. * In/Out: pubkey: pointer to a public key object. pubkey will be set to an * invalid value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to @@ -764,30 +818,41 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Updates the context randomization to protect against side-channel leakage. - * Returns: 1: randomization successfully updated or nothing to randomize +/** Randomizes the context to provide enhanced protection against side-channel leakage. + * + * Returns: 1: randomization successful (or called on copy of secp256k1_context_static) * 0: error * Args: ctx: pointer to a context object. * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) * - * While secp256k1 code is written to be constant-time no matter what secret - * values are, it's possible that a future compiler may output code which isn't, + * While secp256k1 code is written and tested to be constant-time no matter what + * secret values are, it is possible that a compiler may output code which is not, * and also that the CPU may not emit the same radio frequencies or draw the same - * amount power for all values. - * - * This function provides a seed which is combined into the blinding value: that - * blinding value is added before each multiplication (and removed afterwards) so - * that it does not affect function results, but shields against attacks which - * rely on any input-dependent behaviour. - * - * This function has currently an effect only on contexts initialized for signing - * because randomization is currently used only for signing. However, this is not - * guaranteed and may change in the future. It is safe to call this function on - * contexts not initialized for signing; then it will have no effect and return 1. - * - * You should call this after secp256k1_context_create or - * secp256k1_context_clone (and secp256k1_context_preallocated_create or - * secp256k1_context_clone, resp.), and you may call this repeatedly afterwards. + * amount of power for all values. Randomization of the context shields against + * side-channel observations which aim to exploit secret-dependent behaviour in + * certain computations which involve secret keys. + * + * It is highly recommended to call this function on contexts returned from + * secp256k1_context_create or secp256k1_context_clone (or from the corresponding + * functions in secp256k1_preallocated.h) before using these contexts to call API + * functions that perform computations involving secret keys, e.g., signing and + * public key generation. It is possible to call this function more than once on + * the same context, and doing so before every few computations involving secret + * keys is recommended as a defense-in-depth measure. + * + * Currently, the random seed is mainly used for blinding multiplications of a + * secret scalar with the elliptic curve base point. Multiplications of this + * kind are performed by exactly those API functions which are documented to + * require a context that is not the secp256k1_context_static. As a rule of thumb, + * these are all functions which take a secret key (or a keypair) as an input. + * A notable exception to that rule is the ECDH module, which relies on a different + * kind of elliptic curve point multiplication and thus does not benefit from + * enhanced protection against side-channel leakage currently. + * + * It is safe call this function on a copy of secp256k1_context_static in writable + * memory (e.g., obtained via secp256k1_context_clone). In that case, this + * function is guaranteed to return 1, but the call will have no effect because + * the static context (or a copy thereof) is not meant to be randomized. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( secp256k1_context* ctx, diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h index 09cbeaaa80..3591bc0012 100644 --- a/src/secp256k1/include/secp256k1_extrakeys.h +++ b/src/secp256k1/include/secp256k1_extrakeys.h @@ -108,7 +108,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke * invalid (only when the tweak is the negation of the corresponding * secret key). 1 otherwise. * - * Args: ctx: pointer to a context object initialized for verification. + * Args: ctx: pointer to a context object. * Out: output_pubkey: pointer to a public key to store the result. Will be set * to an invalid value if this function returns 0. * In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to. @@ -137,7 +137,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add( * * Returns: 0 if the arguments are invalid or the tweaked pubkey is not the * result of tweaking the internal_pubkey with tweak32. 1 otherwise. - * Args: ctx: pointer to a context object initialized for verification. + * Args: ctx: pointer to a context object. * In: tweaked_pubkey32: pointer to a serialized xonly_pubkey. * tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization * is passed in as tweaked_pubkey32). This must match the @@ -159,7 +159,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_ * * Returns: 1: secret was valid, keypair is ready to use * 0: secret was invalid, try again with a different secret - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: keypair: pointer to the created keypair. * In: seckey: pointer to a 32-byte secret key. */ @@ -228,7 +228,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( * invalid (only when the tweak is the negation of the keypair's * secret key). 1 otherwise. * - * Args: ctx: pointer to a context object initialized for verification. + * Args: ctx: pointer to a context object. * In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to * an invalid value if this function returns 0. * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according diff --git a/src/secp256k1/include/secp256k1_preallocated.h b/src/secp256k1/include/secp256k1_preallocated.h index d2d9014f02..ed846f75f9 100644 --- a/src/secp256k1/include/secp256k1_preallocated.h +++ b/src/secp256k1/include/secp256k1_preallocated.h @@ -58,6 +58,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size( * bytes, as detailed above. * flags: which parts of the context to initialize. * + * See secp256k1_context_create (in secp256k1.h) for further details. + * * See also secp256k1_context_randomize (in secp256k1.h) * and secp256k1_context_preallocated_destroy. */ diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h index 0e2847db96..824c604025 100644 --- a/src/secp256k1/include/secp256k1_recovery.h +++ b/src/secp256k1/include/secp256k1_recovery.h @@ -72,7 +72,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( * * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: sig: pointer to an array where the signature will be placed. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. @@ -94,7 +94,7 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable( * * Returns: 1: public key successfully recovered (which guarantees a correct signature). * 0: otherwise. - * Args: ctx: pointer to a context object, initialized for verification. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to the recovered public key. * In: sig: pointer to initialized signature that supports pubkey recovery. * msghash32: the 32-byte message hash assumed to be signed. diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h index 5fedcb07b0..e579e1b1d8 100644 --- a/src/secp256k1/include/secp256k1_schnorrsig.h +++ b/src/secp256k1/include/secp256k1_schnorrsig.h @@ -106,7 +106,7 @@ typedef struct { * signatures from being valid in multiple contexts by accident. * * Returns 1 on success, 0 on failure. - * Args: ctx: pointer to a context object, initialized for signing. + * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: sig64: pointer to a 64-byte array to store the serialized signature. * In: msg32: the 32-byte message being signed. * keypair: pointer to an initialized keypair. @@ -161,7 +161,7 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom( * * Returns: 1: correct signature * 0: incorrect signature - * Args: ctx: a secp256k1 context object, initialized for verification. + * Args: ctx: a secp256k1 context object. * In: sig64: pointer to the 64-byte signature to verify. * msg: the message being verified. Can only be NULL if msglen is 0. * msglen: length of the message diff --git a/src/secp256k1/src/assumptions.h b/src/secp256k1/src/assumptions.h index 6dc527b288..8ed04209e9 100644 --- a/src/secp256k1/src/assumptions.h +++ b/src/secp256k1/src/assumptions.h @@ -10,6 +10,9 @@ #include <limits.h> #include "util.h" +#if defined(SECP256K1_INT128_NATIVE) +#include "int128_native.h" +#endif /* This library, like most software, relies on a number of compiler implementation defined (but not undefined) behaviours. Although the behaviours we require are essentially universal we test them specifically here to @@ -55,7 +58,7 @@ struct secp256k1_assumption_checker { /* To int64_t. */ ((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) && -#if defined(SECP256K1_WIDEMUL_INT128) +#if defined(SECP256K1_INT128_NATIVE) ((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) && (((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) && (((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) && @@ -71,7 +74,7 @@ struct secp256k1_assumption_checker { ((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) && ((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) && ((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) && -#if defined(SECP256K1_WIDEMUL_INT128) +#if defined(SECP256K1_INT128_NATIVE) ((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) && #endif 1) * 2 - 1]; diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h deleted file mode 100644 index 6f7693cb8f..0000000000 --- a/src/secp256k1/src/basic-config.h +++ /dev/null @@ -1,17 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -#ifndef SECP256K1_BASIC_CONFIG_H -#define SECP256K1_BASIC_CONFIG_H - -#ifdef USE_BASIC_CONFIG - -#define ECMULT_WINDOW_SIZE 15 -#define ECMULT_GEN_PREC_BITS 4 - -#endif /* USE_BASIC_CONFIG */ - -#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/src/secp256k1/src/bench.c b/src/secp256k1/src/bench.c index d5937b763f..e68021aa28 100644 --- a/src/secp256k1/src/bench.c +++ b/src/secp256k1/src/bench.c @@ -164,7 +164,7 @@ int main(int argc, char** argv) { /* Check if the user tries to benchmark optional module without building it */ #ifndef ENABLE_MODULE_ECDH - if (have_flag(argc, argv, "ecdh")) { + if (have_flag(argc, argv, "ecdh")) { fprintf(stderr, "./bench: ECDH module not enabled.\n"); fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n"); return 1; @@ -172,7 +172,7 @@ int main(int argc, char** argv) { #endif #ifndef ENABLE_MODULE_RECOVERY - if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { + if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { fprintf(stderr, "./bench: Public key recovery module not enabled.\n"); fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n"); return 1; @@ -180,15 +180,15 @@ int main(int argc, char** argv) { #endif #ifndef ENABLE_MODULE_SCHNORRSIG - if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { + if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n"); fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n"); return 1; } #endif - /* ECDSA verification benchmark */ - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + /* ECDSA benchmark */ + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); for (i = 0; i < 32; i++) { data.msg[i] = 1 + i; @@ -206,11 +206,6 @@ int main(int argc, char** argv) { print_output_table_header_row(); if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters); - secp256k1_context_destroy(data.ctx); - - /* ECDSA signing benchmark */ - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters); secp256k1_context_destroy(data.ctx); diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h index aa275fe919..611ba11f04 100644 --- a/src/secp256k1/src/bench.h +++ b/src/secp256k1/src/bench.h @@ -7,15 +7,31 @@ #ifndef SECP256K1_BENCH_H #define SECP256K1_BENCH_H +#include <stdlib.h> #include <stdint.h> #include <stdio.h> #include <string.h> -#include "sys/time.h" + +#if (defined(_MSC_VER) && _MSC_VER >= 1900) +# include <time.h> +#else +# include "sys/time.h" +#endif static int64_t gettime_i64(void) { +#if (defined(_MSC_VER) && _MSC_VER >= 1900) + /* C11 way to get wallclock time */ + struct timespec tv; + if (!timespec_get(&tv, TIME_UTC)) { + fputs("timespec_get failed!", stderr); + exit(1); + } + return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL; +#else struct timeval tv; gettimeofday(&tv, NULL); return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL; +#endif } #define FP_EXP (6) diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c index 4030e0263f..9d0db340e1 100644 --- a/src/secp256k1/src/bench_ecmult.c +++ b/src/secp256k1/src/bench_ecmult.c @@ -84,9 +84,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset } } secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); - secp256k1_gej_neg(&tmp, &tmp); - secp256k1_gej_add_var(&tmp, &tmp, &sum_output, NULL); - CHECK(secp256k1_gej_is_infinity(&tmp)); + CHECK(secp256k1_gej_eq_var(&tmp, &sum_output)); } static void bench_ecmult_setup(void* arg) { @@ -308,7 +306,7 @@ int main(int argc, char **argv) { } } - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; if (!have_flag(argc, argv, "simple")) { data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size); diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index 7eb3af28d7..2224058f64 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -343,19 +343,11 @@ void bench_rfc6979_hmac_sha256(void* arg, int iters) { } } -void bench_context_verify(void* arg, int iters) { +void bench_context(void* arg, int iters) { int i; (void)arg; for (i = 0; i < iters; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); - } -} - -void bench_context_sign(void* arg, int iters) { - int i; - (void)arg; - for (i = 0; i < iters; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE)); } } @@ -395,8 +387,7 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000); - if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100); + if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters); return 0; } diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index b47d8f494a..e28c602506 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -11,6 +11,17 @@ #include "scalar.h" #include "scratch.h" +#ifndef ECMULT_WINDOW_SIZE +# define ECMULT_WINDOW_SIZE 15 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value") +# endif +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE) +#endif + /* Noone will ever need more than a window size of 24. The code might * be correct for larger values of ECMULT_WINDOW_SIZE but this is not * tested. diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index f48f266461..a430e8d5d9 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -10,9 +10,21 @@ #include "scalar.h" #include "group.h" +#ifndef ECMULT_GEN_PREC_BITS +# define ECMULT_GEN_PREC_BITS 4 +# ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value") +# endif +#endif + +#ifdef DEBUG_CONFIG +# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS) +#endif + #if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8 # error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8." #endif + #define ECMULT_GEN_PREC_G(bits) (1 << bits) #define ECMULT_GEN_PREC_N(bits) (256 / bits) diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 2c8a503acc..4f5ea9f3c0 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -88,31 +88,31 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char nonce32[32]; secp256k1_rfc6979_hmac_sha256 rng; int overflow; - unsigned char keydata[64] = {0}; + unsigned char keydata[64]; if (seed32 == NULL) { /* When seed is NULL, reset the initial point and blinding value. */ secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); secp256k1_gej_neg(&ctx->initial, &ctx->initial); secp256k1_scalar_set_int(&ctx->blind, 1); + return; } /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ - secp256k1_scalar_get_b32(nonce32, &ctx->blind); + secp256k1_scalar_get_b32(keydata, &ctx->blind); /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, * and guards against weak or adversarial seeds. This is a simpler and safer interface than * asking the caller for blinding values directly and expecting them to retry on failure. */ - memcpy(keydata, nonce32, 32); - if (seed32 != NULL) { - memcpy(keydata + 32, seed32, 32); - } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); + VERIFY_CHECK(seed32 != NULL); + memcpy(keydata + 32, seed32, 32); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); memset(keydata, 0, sizeof(keydata)); /* Accept unobservably small non-uniformity. */ secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); overflow = !secp256k1_fe_set_b32(&s, nonce32); overflow |= secp256k1_fe_is_zero(&s); secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow); - /* Randomize the projection to defend against multiplier sidechannels. */ + /* Randomize the projection to defend against multiplier sidechannels. + Do this before our own call to secp256k1_ecmult_gen below. */ secp256k1_gej_rescale(&ctx->initial, &s); secp256k1_fe_clear(&s); secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); @@ -121,6 +121,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b)); secp256k1_rfc6979_hmac_sha256_finalize(&rng); memset(nonce32, 0, 32); + /* The random projection in ctx->initial ensures that gb will have a random projection. */ secp256k1_ecmult_gen(ctx, &gb, &b); secp256k1_scalar_negate(&b, &b); ctx->blind = b; diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index bbc820c77c..3776fe73fc 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -200,9 +200,15 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, bit += now; } #ifdef VERIFY - CHECK(carry == 0); - while (bit < 256) { - CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); + { + int verify_bit = bit; + + VERIFY_CHECK(carry == 0); + + while (verify_bit < 256) { + VERIFY_CHECK(secp256k1_scalar_get_bits(&s, verify_bit, 1) == 0); + verify_bit++; + } } #endif return last_set_bit + 1; diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h index 0ed6118cc9..18567b95f3 100644 --- a/src/secp256k1/src/field_5x52_int128_impl.h +++ b/src/secp256k1/src/field_5x52_int128_impl.h @@ -9,14 +9,18 @@ #include <stdint.h> +#include "int128.h" + #ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) #else #define VERIFY_BITS(x, n) do { } while(0) +#define VERIFY_BITS_128(x, n) do { } while(0) #endif SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { - uint128_t c, d; + secp256k1_uint128 c, d; uint64_t t3, t4, tx, u0; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; @@ -40,121 +44,119 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t * Note that [x 0 0 0 0 0] = [x*R]. */ - d = (uint128_t)a0 * b[3] - + (uint128_t)a1 * b[2] - + (uint128_t)a2 * b[1] - + (uint128_t)a3 * b[0]; - VERIFY_BITS(d, 114); + secp256k1_u128_mul(&d, a0, b[3]); + secp256k1_u128_accum_mul(&d, a1, b[2]); + secp256k1_u128_accum_mul(&d, a2, b[1]); + secp256k1_u128_accum_mul(&d, a3, b[0]); + VERIFY_BITS_128(&d, 114); /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * b[4]; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a4, b[4]); + VERIFY_BITS_128(&c, 112); /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (uint128_t)R * (uint64_t)c; c >>= 64; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 48); + secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; + t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); + VERIFY_BITS_128(&d, 63); /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (uint128_t)a0 * b[4] - + (uint128_t)a1 * b[3] - + (uint128_t)a2 * b[2] - + (uint128_t)a3 * b[1] - + (uint128_t)a4 * b[0]; - VERIFY_BITS(d, 115); + secp256k1_u128_accum_mul(&d, a0, b[4]); + secp256k1_u128_accum_mul(&d, a1, b[3]); + secp256k1_u128_accum_mul(&d, a2, b[2]); + secp256k1_u128_accum_mul(&d, a3, b[1]); + secp256k1_u128_accum_mul(&d, a4, b[0]); + VERIFY_BITS_128(&d, 115); /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += (uint128_t)(R << 12) * (uint64_t)c; - VERIFY_BITS(d, 116); + secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; + t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); + VERIFY_BITS_128(&d, 64); /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ tx = (t4 >> 48); t4 &= (M >> 4); VERIFY_BITS(tx, 4); VERIFY_BITS(t4, 48); /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - c = (uint128_t)a0 * b[0]; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a0, b[0]); + VERIFY_BITS_128(&c, 112); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * b[4] - + (uint128_t)a2 * b[3] - + (uint128_t)a3 * b[2] - + (uint128_t)a4 * b[1]; - VERIFY_BITS(d, 115); + secp256k1_u128_accum_mul(&d, a1, b[4]); + secp256k1_u128_accum_mul(&d, a2, b[3]); + secp256k1_u128_accum_mul(&d, a3, b[2]); + secp256k1_u128_accum_mul(&d, a4, b[1]); + VERIFY_BITS_128(&d, 115); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; + u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 63); + VERIFY_BITS_128(&d, 63); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 115); + secp256k1_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 115); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; + r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); + VERIFY_BITS_128(&c, 61); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)a0 * b[1] - + (uint128_t)a1 * b[0]; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, b[1]); + secp256k1_u128_accum_mul(&c, a1, b[0]); + VERIFY_BITS_128(&c, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * b[4] - + (uint128_t)a3 * b[3] - + (uint128_t)a4 * b[2]; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a2, b[4]); + secp256k1_u128_accum_mul(&d, a3, b[3]); + secp256k1_u128_accum_mul(&d, a4, b[2]); + VERIFY_BITS_128(&d, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); + secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; + r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); + VERIFY_BITS_128(&c, 63); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (uint128_t)a0 * b[2] - + (uint128_t)a1 * b[1] - + (uint128_t)a2 * b[0]; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, b[2]); + secp256k1_u128_accum_mul(&c, a1, b[1]); + secp256k1_u128_accum_mul(&c, a2, b[0]); + VERIFY_BITS_128(&c, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * b[4] - + (uint128_t)a4 * b[3]; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a3, b[4]); + secp256k1_u128_accum_mul(&d, a4, b[3]); + VERIFY_BITS_128(&d, 114); /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)R * (uint64_t)d; d >>= 64; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 50); + secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; + r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[2], 52); - VERIFY_BITS(c, 63); + VERIFY_BITS_128(&c, 63); /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)(R << 12) * (uint64_t)d + t3; - VERIFY_BITS(c, 100); + secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); + secp256k1_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; + r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); + VERIFY_BITS_128(&c, 48); /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; + r[4] = secp256k1_u128_to_u64(&c) + t4; VERIFY_BITS(r[4], 49); /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { - uint128_t c, d; + secp256k1_uint128 c, d; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; int64_t t3, t4, tx, u0; const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; @@ -170,107 +172,105 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t * Note that [x 0 0 0 0 0] = [x*R]. */ - d = (uint128_t)(a0*2) * a3 - + (uint128_t)(a1*2) * a2; - VERIFY_BITS(d, 114); + secp256k1_u128_mul(&d, a0*2, a3); + secp256k1_u128_accum_mul(&d, a1*2, a2); + VERIFY_BITS_128(&d, 114); /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * a4; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a4, a4); + VERIFY_BITS_128(&c, 112); /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (uint128_t)R * (uint64_t)c; c >>= 64; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 48); + secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64); + VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&c, 48); /* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; + t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); + VERIFY_BITS_128(&d, 63); /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ a4 *= 2; - d += (uint128_t)a0 * a4 - + (uint128_t)(a1*2) * a3 - + (uint128_t)a2 * a2; - VERIFY_BITS(d, 115); + secp256k1_u128_accum_mul(&d, a0, a4); + secp256k1_u128_accum_mul(&d, a1*2, a3); + secp256k1_u128_accum_mul(&d, a2, a2); + VERIFY_BITS_128(&d, 115); /* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += (uint128_t)(R << 12) * (uint64_t)c; - VERIFY_BITS(d, 116); + secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c)); + VERIFY_BITS_128(&d, 116); /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; + t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); + VERIFY_BITS_128(&d, 64); /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ tx = (t4 >> 48); t4 &= (M >> 4); VERIFY_BITS(tx, 4); VERIFY_BITS(t4, 48); /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - c = (uint128_t)a0 * a0; - VERIFY_BITS(c, 112); + secp256k1_u128_mul(&c, a0, a0); + VERIFY_BITS_128(&c, 112); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * a4 - + (uint128_t)(a2*2) * a3; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a1, a4); + secp256k1_u128_accum_mul(&d, a2*2, a3); + VERIFY_BITS_128(&d, 114); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; + u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 62); + VERIFY_BITS_128(&d, 62); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 113); + secp256k1_u128_accum_mul(&c, u0, R >> 4); + VERIFY_BITS_128(&c, 113); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; + r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); + VERIFY_BITS_128(&c, 61); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ a0 *= 2; - c += (uint128_t)a0 * a1; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, a1); + VERIFY_BITS_128(&c, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * a4 - + (uint128_t)a3 * a3; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a2, a4); + secp256k1_u128_accum_mul(&d, a3, a3); + VERIFY_BITS_128(&d, 114); /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); + secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 62); /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; + r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); + VERIFY_BITS_128(&c, 63); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (uint128_t)a0 * a2 - + (uint128_t)a1 * a1; - VERIFY_BITS(c, 114); + secp256k1_u128_accum_mul(&c, a0, a2); + secp256k1_u128_accum_mul(&c, a1, a1); + VERIFY_BITS_128(&c, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * a4; - VERIFY_BITS(d, 114); + secp256k1_u128_accum_mul(&d, a3, a4); + VERIFY_BITS_128(&d, 114); /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)R * (uint64_t)d; d >>= 64; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 50); + secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64); + VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&d, 50); /* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; + r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[2], 52); - VERIFY_BITS(c, 63); + VERIFY_BITS_128(&c, 63); /* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (uint128_t)(R << 12) * (uint64_t)d + t3; - VERIFY_BITS(c, 100); + secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d)); + secp256k1_u128_accum_u64(&c, t3); + VERIFY_BITS_128(&c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; + r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); + VERIFY_BITS_128(&c, 48); /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; + r[4] = secp256k1_u128_to_u64(&c) + t4; VERIFY_BITS(r[4], 49); /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h index bb7dae1cf7..b79ba597db 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -23,7 +23,7 @@ typedef struct { #define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} /** A group element of the secp256k1 curve, in jacobian coordinates. - * Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve. + * Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve. */ typedef struct { secp256k1_fe x; /* actual X: x/z^2 */ @@ -97,6 +97,9 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r); /** Set a group element (jacobian) equal to another which is given in affine coordinates. */ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); +/** Check two group elements (jacobian) for equality in variable time. */ +static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b); + /** Compare the X coordinate of a group element (jacobian). */ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index 63735ab682..dfe6e32c7f 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -236,6 +236,13 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { secp256k1_fe_set_int(&r->z, 1); } +static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej tmp; + secp256k1_gej_neg(&tmp, a); + secp256k1_gej_add_var(&tmp, &tmp, b, NULL); + return secp256k1_gej_is_infinity(&tmp); +} + static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { secp256k1_fe r, r2; VERIFY_CHECK(!a->infinity); diff --git a/src/secp256k1/src/int128.h b/src/secp256k1/src/int128.h new file mode 100644 index 0000000000..84d969a236 --- /dev/null +++ b/src/secp256k1/src/int128.h @@ -0,0 +1,85 @@ +#ifndef SECP256K1_INT128_H +#define SECP256K1_INT128_H + +#include "util.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct.h" +# else +# error "Please select int128 implementation" +# endif + +/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo); + +/* Multiply two unsigned 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); + +/* Multiply two unsigned 64-bit values a and b and add the result to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b); + +/* Add an unsigned 64-bit value a to r. + * The final result is taken modulo 2^128. + */ +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a); + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n); + +/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a); + +/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */ +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a); + +/* Write an unsigned 64-bit value to r. */ +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a); + +/* Tests if r is strictly less than to 2^n. + * n must be strictly less than 128. + */ +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n); + +/* Construct an signed 128-bit value from a high and a low 64-bit value. */ +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo); + +/* Multiply two signed 64-bit values a and b and write the result to r. */ +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b); + +/* Multiply two signed 64-bit values a and b and add the result to r. + * Overflow or underflow from the addition is undefined behaviour. + */ +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b); + +/* Compute a*d - b*c from signed 64-bit values and write the result to r. */ +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d); + +/* Signed (arithmetic) right shift. + * Non-constant time in b. + */ +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b); + +/* Return the low 64-bits of a 128-bit value interpreted as an signed 64-bit value. */ +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a); + +/* Write a signed 64-bit value to r. */ +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a); + +/* Compare two 128-bit values for equality. */ +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); + +/* Tests if r is equal to 2^n. + * n must be strictly less than 127. + */ +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n); + +#endif + +#endif diff --git a/src/secp256k1/src/int128_impl.h b/src/secp256k1/src/int128_impl.h new file mode 100644 index 0000000000..cfc573408a --- /dev/null +++ b/src/secp256k1/src/int128_impl.h @@ -0,0 +1,18 @@ +#ifndef SECP256K1_INT128_IMPL_H +#define SECP256K1_INT128_IMPL_H + +#include "util.h" + +#include "int128.h" + +#if defined(SECP256K1_WIDEMUL_INT128) +# if defined(SECP256K1_INT128_NATIVE) +# include "int128_native_impl.h" +# elif defined(SECP256K1_INT128_STRUCT) +# include "int128_struct_impl.h" +# else +# error "Please select int128 implementation" +# endif +#endif + +#endif diff --git a/src/secp256k1/src/int128_native.h b/src/secp256k1/src/int128_native.h new file mode 100644 index 0000000000..7c97aafc74 --- /dev/null +++ b/src/secp256k1/src/int128_native.h @@ -0,0 +1,19 @@ +#ifndef SECP256K1_INT128_NATIVE_H +#define SECP256K1_INT128_NATIVE_H + +#include <stdint.h> +#include "util.h" + +#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +SECP256K1_GNUC_EXT typedef __int128 int128_t; +# define UINT128_MAX ((uint128_t)(-1)) +# define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) +# define INT128_MIN (-INT128_MAX - 1) +/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ +#endif + +typedef uint128_t secp256k1_uint128; +typedef int128_t secp256k1_int128; + +#endif diff --git a/src/secp256k1/src/int128_native_impl.h b/src/secp256k1/src/int128_native_impl.h new file mode 100644 index 0000000000..e4b7f4106c --- /dev/null +++ b/src/secp256k1/src/int128_native_impl.h @@ -0,0 +1,87 @@ +#ifndef SECP256K1_INT128_NATIVE_IMPL_H +#define SECP256K1_INT128_NATIVE_IMPL_H + +#include "int128.h" + +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { + *r = (((uint128_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + *r = (uint128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + *r += (uint128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { + *r += a; +} + +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { + return (uint64_t)(*a); +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { + return (uint64_t)(*a >> 64); +} + +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { + *r = a; +} + +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return (*r >> n == 0); +} + +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { + *r = (((uint128_t)(uint64_t)hi) << 64) + lo; +} + +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + *r = (int128_t)a * b; +} + +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int128_t ab = (int128_t)a * b; + VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r); + *r += ab; +} + +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + int128_t ad = (int128_t)a * d; + int128_t bc = (int128_t)b * c; + VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc); + *r = ad - bc; +} + +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + *r >>= n; +} + +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { + return *a; +} + +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { + *r = a; +} + +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { + return *a == *b; +} + +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 127); + return (*r == (int128_t)1 << n); +} + +#endif diff --git a/src/secp256k1/src/int128_struct.h b/src/secp256k1/src/int128_struct.h new file mode 100644 index 0000000000..6156f82cc2 --- /dev/null +++ b/src/secp256k1/src/int128_struct.h @@ -0,0 +1,14 @@ +#ifndef SECP256K1_INT128_STRUCT_H +#define SECP256K1_INT128_STRUCT_H + +#include <stdint.h> +#include "util.h" + +typedef struct { + uint64_t lo; + uint64_t hi; +} secp256k1_uint128; + +typedef secp256k1_uint128 secp256k1_int128; + +#endif diff --git a/src/secp256k1/src/int128_struct_impl.h b/src/secp256k1/src/int128_struct_impl.h new file mode 100644 index 0000000000..b5f8fb7b65 --- /dev/null +++ b/src/secp256k1/src/int128_struct_impl.h @@ -0,0 +1,192 @@ +#ifndef SECP256K1_INT128_STRUCT_IMPL_H +#define SECP256K1_INT128_STRUCT_IMPL_H + +#include "int128.h" + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */ +# include <intrin.h> +# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. + (Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64, + which supports both __(u)mulh and _umul128.) */ +# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE) +# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.") +# endif +static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + *hi = __umulh(a, b); + return a * b; +} + +static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { + *hi = __mulh(a, b); + return (uint64_t)a * (uint64_t)b; +} +# else +/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */ +# define secp256k1_umul128 _umul128 +# define secp256k1_mul128 _mul128 +# endif +#else +/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */ +static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + uint64_t lh = (uint32_t)a * (b >> 32); + uint64_t hl = (a >> 32) * (uint32_t)b; + uint64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} + +static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) { + uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b; + int64_t lh = (uint32_t)a * (b >> 32); + int64_t hl = (a >> 32) * (uint32_t)b; + int64_t hh = (a >> 32) * (b >> 32); + uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl; + *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32); + return (mid34 << 32) + (uint32_t)ll; +} +#endif + +static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + r->lo = secp256k1_umul128(a, b, &r->hi); +} + +static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) { + uint64_t lo, hi; + lo = secp256k1_umul128(a, b, &hi); + r->lo += lo; + r->hi += hi + (r->lo < lo); +} + +static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) { + r->lo += a; + r->hi += r->lo < a; +} + +/* Unsigned (logical) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = r->hi >> (n-64); + r->hi = 0; + } else if (n > 0) { + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; + r->hi >>= n; + } +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) { + return a->lo; +} + +static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) { + return a->hi; +} + +static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) { + r->hi = 0; + r->lo = a; +} + +static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + return n >= 64 ? r->hi >> (n - 64) == 0 + : r->hi == 0 && r->lo >> n == 0; +} + +static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) { + r->hi = hi; + r->lo = lo; +} + +static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + r->lo = (uint64_t)secp256k1_mul128(a, b, &hi); + r->hi = (uint64_t)hi; +} + +static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); + r->lo += lo; + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set), + * then we require that the resulting value also be positive (the sign bit is not set). + * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi += hi; +} + +static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) { + int64_t hi; + uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi); + hi += r->lo < lo; + /* Verify no overflow. + * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set), + * then we require that the resulting value also be positive (the sign bit is not set). + */ + VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu)); + /* Verify no underflow. + * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set), + * then we require that the resulting value also be negative (the sign bit is set). + */ + VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu)); + r->hi -= hi; + r->lo -= lo; +} + +static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) { + secp256k1_i128_mul(r, a, d); + secp256k1_i128_dissip_mul(r, b, c); +} + +/* Signed (arithmetic) right shift. + * Non-constant time in n. + */ +static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 128); + if (n >= 64) { + r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64)); + r->hi = (uint64_t)((int64_t)(r->hi) >> 63); + } else if (n > 0) { + r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n; + r->hi = (uint64_t)((int64_t)(r->hi) >> n); + } +} + +static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { + return (int64_t)a->lo; +} + +static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { + r->hi = (uint64_t)(a >> 63); + r->lo = (uint64_t)a; +} + +static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) { + return a->hi == b->hi && a->lo == b->lo; +} + +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { + VERIFY_CHECK(n < 127); + return n >= 64 ? r->hi == (uint64_t)1 << (n - 64) && r->lo == 0 + : r->hi == 0 && r->lo == (uint64_t)1 << n; +} + +#endif diff --git a/src/secp256k1/src/modinv64_impl.h b/src/secp256k1/src/modinv64_impl.h index 0743a9c821..50be2e5e78 100644 --- a/src/secp256k1/src/modinv64_impl.h +++ b/src/secp256k1/src/modinv64_impl.h @@ -7,10 +7,9 @@ #ifndef SECP256K1_MODINV64_IMPL_H #define SECP256K1_MODINV64_IMPL_H +#include "int128.h" #include "modinv64.h" -#include "util.h" - /* This file implements modular inversion based on the paper "Fast constant-time gcd computation and * modular inversion" by Daniel J. Bernstein and Bo-Yin Yang. * @@ -18,6 +17,15 @@ * implementation for N=62, using 62-bit signed limbs represented as int64_t. */ +/* Data type for transition matrices (see section 3 of explanation). + * + * t = [ u v ] + * [ q r ] + */ +typedef struct { + int64_t u, v, q, r; +} secp256k1_modinv64_trans2x2; + #ifdef VERIFY /* Helper function to compute the absolute value of an int64_t. * (we don't use abs/labs/llabs as it depends on the int sizes). */ @@ -32,15 +40,17 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}}; /* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) { const int64_t M62 = (int64_t)(UINT64_MAX >> 2); - int128_t c = 0; + secp256k1_int128 c, d; int i; + secp256k1_i128_from_i64(&c, 0); for (i = 0; i < 4; ++i) { - if (i < alen) c += (int128_t)a->v[i] * factor; - r->v[i] = (int64_t)c & M62; c >>= 62; + if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor); + r->v[i] = secp256k1_i128_to_i64(&c) & M62; secp256k1_i128_rshift(&c, 62); } - if (4 < alen) c += (int128_t)a->v[4] * factor; - VERIFY_CHECK(c == (int64_t)c); - r->v[4] = (int64_t)c; + if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor); + secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c)); + VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d)); + r->v[4] = secp256k1_i128_to_i64(&c); } /* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A has alen limbs; b has 5. */ @@ -60,6 +70,13 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i } return 0; } + +/* Check if the determinant of t is equal to 1 << n. */ +static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n) { + secp256k1_int128 a; + secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); + return secp256k1_i128_check_pow2(&a, n); +} #endif /* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus @@ -136,15 +153,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6 #endif } -/* Data type for transition matrices (see section 3 of explanation). - * - * t = [ u v ] - * [ q r ] - */ -typedef struct { - int64_t u, v, q, r; -} secp256k1_modinv64_trans2x2; - /* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). * Note that the transformation matrix is scaled by 2^62 and not 2^59. * @@ -203,13 +211,15 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_ t->v = (int64_t)v; t->q = (int64_t)q; t->r = (int64_t)r; +#ifdef VERIFY /* The determinant of t must be a power of two. This guarantees that multiplication with t * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * will be divided out again). As each divstep's individual matrix has determinant 2, the * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial * 8*identity (which has determinant 2^6) means the overall outputs has determinant * 2^65. */ - VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 65); + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65)); +#endif return zeta; } @@ -286,11 +296,13 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint t->v = (int64_t)v; t->q = (int64_t)q; t->r = (int64_t)r; +#ifdef VERIFY /* The determinant of t must be a power of two. This guarantees that multiplication with t * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * will be divided out again). As each divstep's individual matrix has determinant 2, the * aggregate of 62 of them will have determinant 2^62. */ - VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62); + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62)); +#endif return eta; } @@ -307,7 +319,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; const int64_t u = t->u, v = t->v, q = t->q, r = t->r; int64_t md, me, sd, se; - int128_t cd, ce; + secp256k1_int128 cd, ce; #ifdef VERIFY VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ @@ -324,54 +336,64 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp md = (u & sd) + (v & se); me = (q & sd) + (r & se); /* Begin computing t*[d,e]. */ - cd = (int128_t)u * d0 + (int128_t)v * e0; - ce = (int128_t)q * d0 + (int128_t)r * e0; + secp256k1_i128_mul(&cd, u, d0); + secp256k1_i128_accum_mul(&cd, v, e0); + secp256k1_i128_mul(&ce, q, d0); + secp256k1_i128_accum_mul(&ce, r, e0); /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ - md -= (modinfo->modulus_inv62 * (uint64_t)cd + md) & M62; - me -= (modinfo->modulus_inv62 * (uint64_t)ce + me) & M62; + md -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&cd) + md) & M62; + me -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&ce) + me) & M62; /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ - cd += (int128_t)modinfo->modulus.v[0] * md; - ce += (int128_t)modinfo->modulus.v[0] * me; + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me); /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ - VERIFY_CHECK(((int64_t)cd & M62) == 0); cd >>= 62; - VERIFY_CHECK(((int64_t)ce & M62) == 0); ce >>= 62; + VERIFY_CHECK((secp256k1_i128_to_i64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62); + VERIFY_CHECK((secp256k1_i128_to_i64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62); /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ - cd += (int128_t)u * d1 + (int128_t)v * e1; - ce += (int128_t)q * d1 + (int128_t)r * e1; + secp256k1_i128_accum_mul(&cd, u, d1); + secp256k1_i128_accum_mul(&cd, v, e1); + secp256k1_i128_accum_mul(&ce, q, d1); + secp256k1_i128_accum_mul(&ce, r, e1); if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */ - cd += (int128_t)modinfo->modulus.v[1] * md; - ce += (int128_t)modinfo->modulus.v[1] * me; + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me); } - d->v[0] = (int64_t)cd & M62; cd >>= 62; - e->v[0] = (int64_t)ce & M62; ce >>= 62; + d->v[0] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[0] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ - cd += (int128_t)u * d2 + (int128_t)v * e2; - ce += (int128_t)q * d2 + (int128_t)r * e2; + secp256k1_i128_accum_mul(&cd, u, d2); + secp256k1_i128_accum_mul(&cd, v, e2); + secp256k1_i128_accum_mul(&ce, q, d2); + secp256k1_i128_accum_mul(&ce, r, e2); if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */ - cd += (int128_t)modinfo->modulus.v[2] * md; - ce += (int128_t)modinfo->modulus.v[2] * me; + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me); } - d->v[1] = (int64_t)cd & M62; cd >>= 62; - e->v[1] = (int64_t)ce & M62; ce >>= 62; + d->v[1] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[1] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ - cd += (int128_t)u * d3 + (int128_t)v * e3; - ce += (int128_t)q * d3 + (int128_t)r * e3; + secp256k1_i128_accum_mul(&cd, u, d3); + secp256k1_i128_accum_mul(&cd, v, e3); + secp256k1_i128_accum_mul(&ce, q, d3); + secp256k1_i128_accum_mul(&ce, r, e3); if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */ - cd += (int128_t)modinfo->modulus.v[3] * md; - ce += (int128_t)modinfo->modulus.v[3] * me; + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me); } - d->v[2] = (int64_t)cd & M62; cd >>= 62; - e->v[2] = (int64_t)ce & M62; ce >>= 62; + d->v[2] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[2] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ - cd += (int128_t)u * d4 + (int128_t)v * e4; - ce += (int128_t)q * d4 + (int128_t)r * e4; - cd += (int128_t)modinfo->modulus.v[4] * md; - ce += (int128_t)modinfo->modulus.v[4] * me; - d->v[3] = (int64_t)cd & M62; cd >>= 62; - e->v[3] = (int64_t)ce & M62; ce >>= 62; + secp256k1_i128_accum_mul(&cd, u, d4); + secp256k1_i128_accum_mul(&cd, v, e4); + secp256k1_i128_accum_mul(&ce, q, d4); + secp256k1_i128_accum_mul(&ce, r, e4); + secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md); + secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me); + d->v[3] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); + e->v[3] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ - d->v[4] = (int64_t)cd; - e->v[4] = (int64_t)ce; + d->v[4] = secp256k1_i128_to_i64(&cd); + e->v[4] = secp256k1_i128_to_i64(&ce); #ifdef VERIFY VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ @@ -389,36 +411,46 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; const int64_t u = t->u, v = t->v, q = t->q, r = t->r; - int128_t cf, cg; + secp256k1_int128 cf, cg; /* Start computing t*[f,g]. */ - cf = (int128_t)u * f0 + (int128_t)v * g0; - cg = (int128_t)q * f0 + (int128_t)r * g0; + secp256k1_i128_mul(&cf, u, f0); + secp256k1_i128_accum_mul(&cf, v, g0); + secp256k1_i128_mul(&cg, q, f0); + secp256k1_i128_accum_mul(&cg, r, g0); /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62; - VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62; + VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); + VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ - cf += (int128_t)u * f1 + (int128_t)v * g1; - cg += (int128_t)q * f1 + (int128_t)r * g1; - f->v[0] = (int64_t)cf & M62; cf >>= 62; - g->v[0] = (int64_t)cg & M62; cg >>= 62; + secp256k1_i128_accum_mul(&cf, u, f1); + secp256k1_i128_accum_mul(&cf, v, g1); + secp256k1_i128_accum_mul(&cg, q, f1); + secp256k1_i128_accum_mul(&cg, r, g1); + f->v[0] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[0] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); /* Compute limb 2 of t*[f,g], and store it as output limb 1. */ - cf += (int128_t)u * f2 + (int128_t)v * g2; - cg += (int128_t)q * f2 + (int128_t)r * g2; - f->v[1] = (int64_t)cf & M62; cf >>= 62; - g->v[1] = (int64_t)cg & M62; cg >>= 62; + secp256k1_i128_accum_mul(&cf, u, f2); + secp256k1_i128_accum_mul(&cf, v, g2); + secp256k1_i128_accum_mul(&cg, q, f2); + secp256k1_i128_accum_mul(&cg, r, g2); + f->v[1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); /* Compute limb 3 of t*[f,g], and store it as output limb 2. */ - cf += (int128_t)u * f3 + (int128_t)v * g3; - cg += (int128_t)q * f3 + (int128_t)r * g3; - f->v[2] = (int64_t)cf & M62; cf >>= 62; - g->v[2] = (int64_t)cg & M62; cg >>= 62; + secp256k1_i128_accum_mul(&cf, u, f3); + secp256k1_i128_accum_mul(&cf, v, g3); + secp256k1_i128_accum_mul(&cg, q, f3); + secp256k1_i128_accum_mul(&cg, r, g3); + f->v[2] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[2] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); /* Compute limb 4 of t*[f,g], and store it as output limb 3. */ - cf += (int128_t)u * f4 + (int128_t)v * g4; - cg += (int128_t)q * f4 + (int128_t)r * g4; - f->v[3] = (int64_t)cf & M62; cf >>= 62; - g->v[3] = (int64_t)cg & M62; cg >>= 62; + secp256k1_i128_accum_mul(&cf, u, f4); + secp256k1_i128_accum_mul(&cf, v, g4); + secp256k1_i128_accum_mul(&cg, q, f4); + secp256k1_i128_accum_mul(&cg, r, g4); + f->v[3] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[3] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ - f->v[4] = (int64_t)cf; - g->v[4] = (int64_t)cg; + f->v[4] = secp256k1_i128_to_i64(&cf); + g->v[4] = secp256k1_i128_to_i64(&cg); } /* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps. @@ -431,30 +463,34 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign const int64_t M62 = (int64_t)(UINT64_MAX >> 2); const int64_t u = t->u, v = t->v, q = t->q, r = t->r; int64_t fi, gi; - int128_t cf, cg; + secp256k1_int128 cf, cg; int i; VERIFY_CHECK(len > 0); /* Start computing t*[f,g]. */ fi = f->v[0]; gi = g->v[0]; - cf = (int128_t)u * fi + (int128_t)v * gi; - cg = (int128_t)q * fi + (int128_t)r * gi; + secp256k1_i128_mul(&cf, u, fi); + secp256k1_i128_accum_mul(&cf, v, gi); + secp256k1_i128_mul(&cg, q, fi); + secp256k1_i128_accum_mul(&cg, r, gi); /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ - VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62; - VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62; + VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); + VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting * down by 62 bits). */ for (i = 1; i < len; ++i) { fi = f->v[i]; gi = g->v[i]; - cf += (int128_t)u * fi + (int128_t)v * gi; - cg += (int128_t)q * fi + (int128_t)r * gi; - f->v[i - 1] = (int64_t)cf & M62; cf >>= 62; - g->v[i - 1] = (int64_t)cg & M62; cg >>= 62; + secp256k1_i128_accum_mul(&cf, u, fi); + secp256k1_i128_accum_mul(&cf, v, gi); + secp256k1_i128_accum_mul(&cg, q, fi); + secp256k1_i128_accum_mul(&cg, r, gi); + f->v[i - 1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); + g->v[i - 1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); } /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ - f->v[len - 1] = (int64_t)cf; - g->v[len - 1] = (int64_t)cg; + f->v[len - 1] = secp256k1_i128_to_i64(&cf); + g->v[len - 1] = secp256k1_i128_to_i64(&cg); } /* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */ diff --git a/src/secp256k1/src/modules/ecdh/bench_impl.h b/src/secp256k1/src/modules/ecdh/bench_impl.h index 94d833462f..8df15bcf43 100644 --- a/src/secp256k1/src/modules/ecdh/bench_impl.h +++ b/src/secp256k1/src/modules/ecdh/bench_impl.h @@ -7,7 +7,7 @@ #ifndef SECP256K1_MODULE_ECDH_BENCH_H #define SECP256K1_MODULE_ECDH_BENCH_H -#include "../include/secp256k1_ecdh.h" +#include "../../../include/secp256k1_ecdh.h" typedef struct { secp256k1_context *ctx; diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h index 10b7075c38..ce644d572a 100644 --- a/src/secp256k1/src/modules/ecdh/tests_impl.h +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -26,7 +26,7 @@ int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, con void test_ecdh_api(void) { /* Setup context that just counts errors */ - secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_pubkey point; unsigned char res[32]; unsigned char s_one[32] = { 0 }; diff --git a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h index d4a2f5bdf4..5ecc90d50f 100644 --- a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h +++ b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h @@ -7,8 +7,8 @@ #ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H #define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H -#include "src/modules/extrakeys/main_impl.h" #include "../../../include/secp256k1_extrakeys.h" +#include "main_impl.h" static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) { secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h index c8a99f4466..8030aedad6 100644 --- a/src/secp256k1/src/modules/extrakeys/tests_impl.h +++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h @@ -9,11 +9,9 @@ #include "../../../include/secp256k1_extrakeys.h" -static secp256k1_context* api_test_context(int flags, int *ecount) { - secp256k1_context *ctx0 = secp256k1_context_create(flags); +static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) { secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount); secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount); - return ctx0; } void test_xonly_pubkey(void) { @@ -31,28 +29,25 @@ void test_xonly_pubkey(void) { int i; int ecount; - secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); + + set_counting_callbacks(ctx, &ecount); secp256k1_testrand256(sk); memset(ones32, 0xFF, 32); secp256k1_testrand256(xy_sk); - CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); /* Test xonly_pubkey_from_pubkey */ ecount = 0; - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, NULL, &pk_parity, &pk) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, NULL) == 0); CHECK(ecount == 2); memset(&pk, 0, sizeof(pk)); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 0); CHECK(ecount == 3); /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ @@ -78,9 +73,9 @@ void test_xonly_pubkey(void) { /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ ecount = 0; - CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, NULL, &xonly_pk) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, NULL) == 0); CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); CHECK(ecount == 2); { @@ -88,20 +83,20 @@ void test_xonly_pubkey(void) { * special casing. */ secp256k1_xonly_pubkey pk_tmp; memset(&pk_tmp, 0, sizeof(pk_tmp)); - CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &pk_tmp) == 0); } /* pubkey_load called illegal callback */ CHECK(ecount == 3); - CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); ecount = 0; - CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0); + CHECK(secp256k1_xonly_pubkey_parse(ctx, NULL, buf32) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, NULL) == 0); CHECK(ecount == 2); /* Serialization and parse roundtrip */ - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1); CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); @@ -109,11 +104,11 @@ void test_xonly_pubkey(void) { /* Test parsing invalid field elements */ memset(&xonly_pk, 1, sizeof(xonly_pk)); /* Overflowing field element */ - CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, ones32) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); memset(&xonly_pk, 1, sizeof(xonly_pk)); /* There's no point with x-coordinate 0 on secp256k1 */ - CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, zeros64) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); /* If a random 32-byte string can not be parsed with ec_pubkey_parse * (because interpreted as X coordinate it does not correspond to a point on @@ -131,10 +126,6 @@ void test_xonly_pubkey(void) { } } CHECK(ecount == 2); - - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(verify); } void test_xonly_pubkey_comparison(void) { @@ -149,29 +140,28 @@ void test_xonly_pubkey_comparison(void) { secp256k1_xonly_pubkey pk1; secp256k1_xonly_pubkey pk2; int ecount = 0; - secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - CHECK(secp256k1_xonly_pubkey_parse(none, &pk1, pk1_ser) == 1); - CHECK(secp256k1_xonly_pubkey_parse(none, &pk2, pk2_ser) == 1); + set_counting_callbacks(ctx, &ecount); - CHECK(secp256k1_xonly_pubkey_cmp(none, NULL, &pk2) < 0); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk1, pk1_ser) == 1); + CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk2, pk2_ser) == 1); + + CHECK(secp256k1_xonly_pubkey_cmp(ctx, NULL, &pk2) < 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, NULL) > 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, NULL) > 0); CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk2) == 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk2) < 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk1) > 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk1) == 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk2) == 0); CHECK(ecount == 2); memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk2) < 0); CHECK(ecount == 3); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk1) == 0); CHECK(ecount == 5); - CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0); + CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk1) > 0); CHECK(ecount == 6); - - secp256k1_context_destroy(none); } void test_xonly_pubkey_tweak(void) { @@ -186,39 +176,38 @@ void test_xonly_pubkey_tweak(void) { int i; int ecount; - secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); + + set_counting_callbacks(ctx, &ecount); memset(overflows, 0xff, sizeof(overflows)); secp256k1_testrand256(tweak); secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(ecount == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(ecount == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, NULL, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, NULL, tweak) == 0); CHECK(ecount == 2); /* NULL internal_xonly_pk zeroes the output_pk */ CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, NULL) == 0); CHECK(ecount == 3); /* NULL tweak zeroes the output_pk */ CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); /* Invalid tweak zeroes the output_pk */ - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); /* A zero tweak is fine */ - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, zeros64) == 1); /* Fails if the resulting key was infinity */ for (i = 0; i < count; i++) { @@ -228,8 +217,8 @@ void test_xonly_pubkey_tweak(void) { secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); secp256k1_scalar_get_b32(tweak, &scalar_tweak); - CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0) - || (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0)); + CHECK((secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, sk) == 0) + || (secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 0)); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); } @@ -237,13 +226,9 @@ void test_xonly_pubkey_tweak(void) { memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); secp256k1_testrand256(tweak); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(verify); } void test_xonly_pubkey_tweak_check(void) { @@ -260,33 +245,32 @@ void test_xonly_pubkey_tweak_check(void) { unsigned char tweak[32]; int ecount; - secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); + + set_counting_callbacks(ctx, &ecount); memset(overflows, 0xff, sizeof(overflows)); secp256k1_testrand256(tweak); secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(ecount == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(ecount == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, NULL, pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); /* invalid pk_parity value */ - CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, 2, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, NULL, tweak) == 0); CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0); + CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, NULL) == 0); CHECK(ecount == 3); memset(tweak, 1, sizeof(tweak)); @@ -307,10 +291,6 @@ void test_xonly_pubkey_tweak_check(void) { CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(ecount == 3); - - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(verify); } /* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 @@ -356,12 +336,10 @@ void test_keypair(void) { secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; int pk_parity, pk_parity_tmp; int ecount; - secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp); - secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); + secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static); + + set_counting_callbacks(ctx, &ecount); + set_counting_callbacks(sttc, &ecount); CHECK(sizeof(zeros96) == sizeof(keypair)); memset(overflows, 0xFF, sizeof(overflows)); @@ -369,75 +347,75 @@ void test_keypair(void) { /* Test keypair_create */ ecount = 0; secp256k1_testrand256(sk); - CHECK(secp256k1_keypair_create(none, &keypair, sk) == 1); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); CHECK(ecount == 0); - CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 1); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); CHECK(ecount == 0); - CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0); + CHECK(secp256k1_keypair_create(ctx, NULL, sk) == 0); CHECK(ecount == 1); - CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0); + CHECK(secp256k1_keypair_create(ctx, &keypair, NULL) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 2); - CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(ecount == 2); CHECK(secp256k1_keypair_create(sttc, &keypair, sk) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 3); /* Invalid secret key */ - CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0); + CHECK(secp256k1_keypair_create(ctx, &keypair, zeros96) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0); + CHECK(secp256k1_keypair_create(ctx, &keypair, overflows) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); /* Test keypair_pub */ ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); - CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1); - CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0); + CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1); + CHECK(secp256k1_keypair_pub(ctx, NULL, &keypair) == 0); CHECK(ecount == 1); - CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0); + CHECK(secp256k1_keypair_pub(ctx, &pk, NULL) == 0); CHECK(ecount == 2); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* Using an invalid keypair is fine for keypair_pub */ memset(&keypair, 0, sizeof(keypair)); - CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1); + CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* keypair holds the same pubkey as pubkey_create */ - CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); - CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); - CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); + CHECK(secp256k1_keypair_pub(ctx, &pk_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); /** Test keypair_xonly_pub **/ ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); - CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 1); + CHECK(secp256k1_keypair_xonly_pub(ctx, NULL, &pk_parity, &keypair) == 0); CHECK(ecount == 1); - CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1); - CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, NULL, &keypair) == 1); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, NULL) == 0); CHECK(ecount == 2); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); /* Using an invalid keypair will set the xonly_pk to 0 (first reset * xonly_pk). */ - CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 1); memset(&keypair, 0, sizeof(keypair)); - CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 0); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); CHECK(ecount == 3); /** keypair holds the same xonly pubkey as pubkey_create **/ - CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); CHECK(pk_parity == pk_parity_tmp); @@ -445,27 +423,23 @@ void test_keypair(void) { ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); - CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1); - CHECK(secp256k1_keypair_sec(none, NULL, &keypair) == 0); + CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1); + CHECK(secp256k1_keypair_sec(ctx, NULL, &keypair) == 0); CHECK(ecount == 1); - CHECK(secp256k1_keypair_sec(none, sk_tmp, NULL) == 0); + CHECK(secp256k1_keypair_sec(ctx, sk_tmp, NULL) == 0); CHECK(ecount == 2); CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); /* keypair returns the same seckey it got */ - CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); - CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); + CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); /* Using an invalid keypair is fine for keypair_seckey */ memset(&keypair, 0, sizeof(keypair)); - CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1); + CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); - - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(verify); secp256k1_context_destroy(sttc); } @@ -477,9 +451,8 @@ void test_keypair_add(void) { unsigned char tweak[32]; int i; int ecount = 0; - secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount); - secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); - secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); + + set_counting_callbacks(ctx, &ecount); CHECK(sizeof(zeros96) == sizeof(keypair)); secp256k1_testrand256(sk); @@ -487,14 +460,14 @@ void test_keypair_add(void) { memset(overflows, 0xFF, 32); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(ecount == 0); - CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(ecount == 0); - CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, NULL, tweak) == 0); CHECK(ecount == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, NULL) == 0); CHECK(ecount == 2); /* This does not set the keypair to zeroes */ CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); @@ -530,18 +503,18 @@ void test_keypair_add(void) { memset(&keypair, 0, sizeof(keypair)); secp256k1_testrand256(tweak); ecount = 0; - CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0); CHECK(ecount == 1); CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); /* Only seckey part of keypair invalid */ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); memset(&keypair, 0, 32); - CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0); CHECK(ecount == 2); /* Only pubkey part of keypair invalid */ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); memset(&keypair.data[32], 0, 64); - CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); + CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0); CHECK(ecount == 3); /* Check that the keypair_tweak_add implementation is correct */ @@ -570,13 +543,10 @@ void test_keypair_add(void) { CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); /* Check that the secret key in the keypair is tweaked correctly */ - CHECK(secp256k1_keypair_sec(none, sk32, &keypair) == 1); + CHECK(secp256k1_keypair_sec(ctx, sk32, &keypair) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1); CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); } - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(verify); } void run_extrakeys_tests(void) { diff --git a/src/secp256k1/src/modules/recovery/bench_impl.h b/src/secp256k1/src/modules/recovery/bench_impl.h index 4a9e886910..ffa00df479 100644 --- a/src/secp256k1/src/modules/recovery/bench_impl.h +++ b/src/secp256k1/src/modules/recovery/bench_impl.h @@ -7,7 +7,7 @@ #ifndef SECP256K1_MODULE_RECOVERY_BENCH_H #define SECP256K1_MODULE_RECOVERY_BENCH_H -#include "../include/secp256k1_recovery.h" +#include "../../../include/secp256k1_recovery.h" typedef struct { secp256k1_context *ctx; @@ -52,7 +52,7 @@ void run_recovery_bench(int iters, int argc, char** argv) { bench_recover_data data; int d = argc == 1; - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters); diff --git a/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h b/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h index 590a972ed3..ed9386b6f8 100644 --- a/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h +++ b/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h @@ -7,7 +7,7 @@ #ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H #define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H -#include "src/modules/recovery/main_impl.h" +#include "main_impl.h" #include "../../../include/secp256k1_recovery.h" void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h index abf62f7f3a..0ff9294e38 100644 --- a/src/secp256k1/src/modules/recovery/tests_impl.h +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -30,11 +30,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c void test_ecdsa_recovery_api(void) { /* Setup contexts that just count errors */ - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp); + secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static); secp256k1_pubkey pubkey; secp256k1_pubkey recpubkey; secp256k1_ecdsa_signature normal_sig; @@ -50,15 +46,9 @@ void test_ecdsa_recovery_api(void) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); /* Construct and verify corresponding public key. */ @@ -67,89 +57,73 @@ void test_ecdsa_recovery_api(void) { /* Check bad contexts and NULLs for signing */ ecount = 0; - CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1); CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, NULL, message, privkey, NULL, NULL) == 0); CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, NULL, privkey, NULL, NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, NULL, NULL, NULL) == 0); CHECK(ecount == 3); CHECK(secp256k1_ecdsa_sign_recoverable(sttc, &recsig, message, privkey, NULL, NULL) == 0); CHECK(ecount == 4); /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ - secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); + secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, recovery_test_nonce_function, NULL); CHECK(ecount == 4); /* These will all fail, but not in ARG_CHECK way */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, over_privkey, NULL, NULL) == 0); /* This one will succeed. */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1); CHECK(ecount == 4); /* Check signing with a goofy nonce function */ /* Check bad contexts and NULLs for recovery */ ecount = 0; - CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &recsig, message) == 1); CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0); + CHECK(secp256k1_ecdsa_recover(ctx, NULL, &recsig, message) == 0); CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, NULL, message) == 0); CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &recsig, NULL) == 0); CHECK(ecount == 3); /* Check NULLs for conversion */ - CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &normal_sig, message, privkey, NULL, NULL) == 1); ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, NULL, &recsig) == 0); CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &normal_sig, NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &normal_sig, &recsig) == 1); /* Check NULLs for de/serialization */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1); ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, NULL, &recid, &recsig) == 0); CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, NULL, &recsig) == 0); CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, NULL) == 0); CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recsig) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, NULL, sig, recid) == 0); CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, NULL, recid) == 0); CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, -1) == 0); CHECK(ecount == 6); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, 5) == 0); CHECK(ecount == 7); /* overflow in signature will fail but not affect ecount */ memcpy(sig, over_privkey, 32); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, recid) == 0); CHECK(ecount == 7); /* cleanup */ - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); secp256k1_context_destroy(sttc); } diff --git a/src/secp256k1/src/modules/schnorrsig/bench_impl.h b/src/secp256k1/src/modules/schnorrsig/bench_impl.h index 41f393c84d..f0b0d3de75 100644 --- a/src/secp256k1/src/modules/schnorrsig/bench_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/bench_impl.h @@ -50,7 +50,7 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) { bench_schnorrsig_data data; int d = argc == 1; - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *)); data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); @@ -91,10 +91,12 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) { free((void *)data.msgs[i]); free((void *)data.sigs[i]); } - free(data.keypairs); - free(data.pk); - free(data.msgs); - free(data.sigs); + + /* Casting to (void *) avoids a stupid warning in MSVC. */ + free((void *)data.keypairs); + free((void *)data.pk); + free((void *)data.msgs); + free((void *)data.sigs); secp256k1_context_destroy(data.ctx); } diff --git a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h index d8df9dd2df..55f9028a63 100644 --- a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -8,7 +8,7 @@ #define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H #include "../../../include/secp256k1_schnorrsig.h" -#include "src/modules/schnorrsig/main_impl.h" +#include "main_impl.h" static const unsigned char invalid_pubkey_bytes[][32] = { /* 0 */ diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h index 25840b8fa7..06cc097cc1 100644 --- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h @@ -128,22 +128,12 @@ void test_schnorrsig_api(void) { secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; /** setup **/ - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp); + secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static); int ecount; - secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); secp256k1_testrand256(sk1); @@ -160,70 +150,54 @@ void test_schnorrsig_api(void) { /** main test body **/ ecount = 0; - CHECK(secp256k1_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypairs[0], NULL) == 1); CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0); + CHECK(secp256k1_schnorrsig_sign32(ctx, NULL, msg, &keypairs[0], NULL) == 0); CHECK(ecount == 1); - CHECK(secp256k1_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig, NULL, &keypairs[0], NULL) == 0); CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, NULL, NULL) == 0); CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &invalid_keypair, NULL) == 0); CHECK(ecount == 4); CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0); CHECK(ecount == 5); ecount = 0; - CHECK(secp256k1_schnorrsig_sign_custom(none, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign_custom(vrfy, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign_custom(sign, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); CHECK(ecount == 1); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0); CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, 0, &keypairs[0], &extraparams) == 1); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, NULL, 0, &keypairs[0], &extraparams) == 1); CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), NULL, &extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), NULL, &extraparams) == 0); CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0); CHECK(ecount == 4); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); CHECK(ecount == 4); - CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0); CHECK(ecount == 5); CHECK(secp256k1_schnorrsig_sign_custom(sttc, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); CHECK(ecount == 6); ecount = 0; - CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &pk[0]) == 1); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypairs[0], NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk[0]) == 1); CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, sizeof(msg), &pk[0]) == 0); + CHECK(secp256k1_schnorrsig_verify(ctx, NULL, msg, sizeof(msg), &pk[0]) == 0); CHECK(ecount == 1); - CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, sizeof(msg), &pk[0]) == 0); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, NULL, sizeof(msg), &pk[0]) == 0); CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, 0, &pk[0]) == 0); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, NULL, 0, &pk[0]) == 0); CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), NULL) == 0); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), NULL) == 0); CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &zero_pk) == 0); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &zero_pk) == 0); CHECK(ecount == 4); - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); secp256k1_context_destroy(sttc); } diff --git a/src/secp256k1/src/precompute_ecmult.c b/src/secp256k1/src/precompute_ecmult.c index 5ccbcb3c57..2aa37b8fe3 100644 --- a/src/secp256k1/src/precompute_ecmult.c +++ b/src/secp256k1/src/precompute_ecmult.c @@ -14,10 +14,13 @@ #endif #include "../include/secp256k1.h" + #include "assumptions.h" #include "util.h" + #include "field_impl.h" #include "group_impl.h" +#include "int128_impl.h" #include "ecmult.h" #include "ecmult_compute_table_impl.h" diff --git a/src/secp256k1/src/precompute_ecmult_gen.c b/src/secp256k1/src/precompute_ecmult_gen.c index 7c6359c402..a4ec8e0dc6 100644 --- a/src/secp256k1/src/precompute_ecmult_gen.c +++ b/src/secp256k1/src/precompute_ecmult_gen.c @@ -8,9 +8,12 @@ #include <stdio.h> #include "../include/secp256k1.h" + #include "assumptions.h" #include "util.h" + #include "group.h" +#include "int128_impl.h" #include "ecmult_gen.h" #include "ecmult_gen_compute_table_impl.h" diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index a1def26fca..4588219d3a 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include "int128.h" #include "modinv64_impl.h" /* Limbs of the secp256k1 order. */ @@ -69,50 +70,61 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal } SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { - uint128_t t; + secp256k1_uint128 t; VERIFY_CHECK(overflow <= 1); - t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint64_t)r->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + secp256k1_u128_from_u64(&t, r->d[0]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); return overflow; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; - uint128_t t = (uint128_t)a->d[0] + b->d[0]; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - overflow = t + secp256k1_scalar_check_overflow(r); + secp256k1_uint128 t; + secp256k1_u128_from_u64(&t, a->d[0]); + secp256k1_u128_accum_u64(&t, b->d[0]); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[1]); + secp256k1_u128_accum_u64(&t, b->d[1]); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[2]); + secp256k1_u128_accum_u64(&t, b->d[2]); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[3]); + secp256k1_u128_accum_u64(&t, b->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); return overflow; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - uint128_t t; + secp256k1_uint128 t; VERIFY_CHECK(bit < 256); bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ - t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + secp256k1_u128_from_u64(&t, r->d[0]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3]); + secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = secp256k1_u128_to_u64(&t); #ifdef VERIFY - VERIFY_CHECK((t >> 64) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); + VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0); #endif } @@ -141,14 +153,19 @@ SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); - uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; + secp256k1_uint128 t; + secp256k1_u128_from_u64(&t, ~a->d[0]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1); + r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[1]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[2]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[3]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_3); + r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { @@ -172,14 +189,19 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ uint64_t mask = !flag - 1; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; - uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; + secp256k1_uint128 t; + secp256k1_u128_from_u64(&t, r->d[0] ^ mask); + secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); + r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[1] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[3] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask); + r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; return 2 * (mask == 0) - 1; } @@ -189,9 +211,10 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { #define muladd(a,b) { \ uint64_t tl, th; \ { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ + secp256k1_uint128 t; \ + secp256k1_u128_mul(&t, a, b); \ + th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = secp256k1_u128_to_u64(&t); \ } \ c0 += tl; /* overflow is handled on the next line */ \ th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ @@ -204,9 +227,10 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { #define muladd_fast(a,b) { \ uint64_t tl, th; \ { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ + secp256k1_uint128 t; \ + secp256k1_u128_mul(&t, a, b); \ + th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = secp256k1_u128_to_u64(&t); \ } \ c0 += tl; /* overflow is handled on the next line */ \ th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \ @@ -484,8 +508,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); #else - uint128_t c; - uint64_t c0, c1, c2; + secp256k1_uint128 c128; + uint64_t c, c0, c1, c2; uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; uint64_t m0, m1, m2, m3, m4, m5; uint32_t m6; @@ -542,14 +566,18 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) /* Reduce 258 bits into 256. */ /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ - c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; - r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; - r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p2 + (uint128_t)p4; - r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p3; - r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + secp256k1_u128_from_u64(&c128, p0); + secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_0, p4); + r->d[0] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p1); + secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_1, p4); + r->d[1] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p2); + secp256k1_u128_accum_u64(&c128, p4); + r->d[2] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64); + secp256k1_u128_accum_u64(&c128, p3); + r->d[3] = secp256k1_u128_to_u64(&c128); + c = secp256k1_u128_hi_u64(&c128); #endif /* Final reduction of r. */ diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h index 688e18eb66..f71a20b963 100644 --- a/src/secp256k1/src/scratch_impl.h +++ b/src/secp256k1/src/scratch_impl.h @@ -25,11 +25,11 @@ static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* err static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { if (scratch != NULL) { - VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { secp256k1_callback_call(error_callback, "invalid scratch space"); return; } + VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ memset(scratch->magic, 0, sizeof(scratch->magic)); free(scratch); } diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index 8f34c35283..5ed3824161 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -4,6 +4,17 @@ * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ +/* This is a C project. It should not be compiled with a C++ compiler, + * and we error out if we detect one. + * + * We still want to be able to test the project with a C++ compiler + * because it is still good to know if this will lead to real trouble, so + * there is a possibility to override the check. But be warned that + * compiling with a C++ compiler is not supported. */ +#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE) +#error Trying to compile a C project with a C++ compiler. +#endif + #define SECP256K1_BUILD #include "../include/secp256k1.h" @@ -11,6 +22,7 @@ #include "assumptions.h" #include "util.h" + #include "field_impl.h" #include "scalar_impl.h" #include "group_impl.h" @@ -20,6 +32,7 @@ #include "ecdsa_impl.h" #include "eckey_impl.h" #include "hash_impl.h" +#include "int128_impl.h" #include "scratch_impl.h" #include "selftest.h" @@ -44,6 +57,8 @@ } \ } while(0) +/* Note that whenever you change the context struct, you must also change the + * context_eq function. */ struct secp256k1_context_struct { secp256k1_ecmult_gen_context ecmult_gen_ctx; secp256k1_callback illegal_callback; @@ -51,13 +66,20 @@ struct secp256k1_context_struct { int declassify; }; -static const secp256k1_context secp256k1_context_no_precomp_ = { +static const secp256k1_context secp256k1_context_static_ = { { 0 }, { secp256k1_default_illegal_callback_fn, 0 }, { secp256k1_default_error_callback_fn, 0 }, 0 }; -const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_; +const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; +const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; + +void secp256k1_selftest(void) { + if (!secp256k1_selftest_passes()) { + secp256k1_callback_call(&default_error_callback, "self test failed"); + } +} size_t secp256k1_context_preallocated_size(unsigned int flags) { size_t ret = sizeof(secp256k1_context); @@ -83,9 +105,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne size_t prealloc_size; secp256k1_context* ret; - if (!secp256k1_selftest()) { - secp256k1_callback_call(&default_error_callback, "self test failed"); - } + secp256k1_selftest(); prealloc_size = secp256k1_context_preallocated_size(flags); if (prealloc_size == 0) { @@ -137,7 +157,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { } void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { - ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp); + ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static); if (ctx != NULL) { secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); } @@ -151,7 +171,7 @@ void secp256k1_context_destroy(secp256k1_context* ctx) { } void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp); + ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static); if (fun == NULL) { fun = secp256k1_default_illegal_callback_fn; } @@ -160,7 +180,7 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)( } void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp); + ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static); if (fun == NULL) { fun = secp256k1_default_error_callback_fn; } diff --git a/src/secp256k1/src/selftest.h b/src/secp256k1/src/selftest.h index 52f1b8442e..d083ac9524 100644 --- a/src/secp256k1/src/selftest.h +++ b/src/secp256k1/src/selftest.h @@ -25,7 +25,7 @@ static int secp256k1_selftest_sha256(void) { return secp256k1_memcmp_var(out, output32, 32) == 0; } -static int secp256k1_selftest(void) { +static int secp256k1_selftest_passes(void) { return secp256k1_selftest_sha256(); } diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index dd53173930..53613f420a 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -26,6 +26,7 @@ #include "modinv32_impl.h" #ifdef SECP256K1_WIDEMUL_INT128 #include "modinv64_impl.h" +#include "int128_impl.h" #endif #define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else @@ -140,6 +141,43 @@ void random_scalar_order_b32(unsigned char *b32) { secp256k1_scalar_get_b32(b32, &num); } +void run_selftest_tests(void) { + /* Test public API */ + secp256k1_selftest(); +} + +int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) { + return a->built == b->built + && secp256k1_scalar_eq(&a->blind, &b->blind) + && secp256k1_gej_eq_var(&a->initial, &b->initial); +} + +int context_eq(const secp256k1_context *a, const secp256k1_context *b) { + return a->declassify == b->declassify + && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) + && a->illegal_callback.fn == b->illegal_callback.fn + && a->illegal_callback.data == b->illegal_callback. +data + && a->error_callback.fn == b->error_callback.fn + && a->error_callback.data == b->error_callback.data; +} + +void test_deprecated_flags(void) { + unsigned int flags[] = { SECP256K1_CONTEXT_SIGN, + SECP256K1_CONTEXT_VERIFY, + SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY }; + int i; + /* Check that a context created with any of the flags in the flags array is + * identical to the NONE context. */ + for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) { + secp256k1_context *tmp_ctx; + CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i])); + tmp_ctx = secp256k1_context_create(flags[i]); + CHECK(context_eq(ctx, tmp_ctx)); + secp256k1_context_destroy(tmp_ctx); + } +} + void run_context_tests(int use_prealloc) { secp256k1_pubkey pubkey; secp256k1_pubkey zero_pubkey; @@ -147,15 +185,8 @@ void run_context_tests(int use_prealloc) { unsigned char ctmp[32]; int32_t ecount; int32_t ecount2; - secp256k1_context *none; - secp256k1_context *sign; - secp256k1_context *vrfy; - secp256k1_context *both; secp256k1_context *sttc; - void *none_prealloc = NULL; - void *sign_prealloc = NULL; - void *vrfy_prealloc = NULL; - void *both_prealloc = NULL; + void *ctx_prealloc = NULL; void *sttc_prealloc = NULL; secp256k1_gej pubj; @@ -163,46 +194,36 @@ void run_context_tests(int use_prealloc) { secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; + /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */ + CHECK(secp256k1_context_no_precomp == secp256k1_context_static); + if (use_prealloc) { - none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); - vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); - both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); - sttc_prealloc = malloc(secp256k1_context_preallocated_clone_size(secp256k1_context_no_precomp)); - CHECK(none_prealloc != NULL); - CHECK(sign_prealloc != NULL); - CHECK(vrfy_prealloc != NULL); - CHECK(both_prealloc != NULL); + ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(ctx_prealloc != NULL); + ctx = secp256k1_context_preallocated_create(ctx_prealloc, SECP256K1_CONTEXT_NONE); + sttc_prealloc = malloc(secp256k1_context_preallocated_clone_size(secp256k1_context_static)); CHECK(sttc_prealloc != NULL); - none = secp256k1_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE); - sign = secp256k1_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN); - vrfy = secp256k1_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY); - both = secp256k1_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - sttc = secp256k1_context_preallocated_clone(secp256k1_context_no_precomp, sttc_prealloc); + sttc = secp256k1_context_preallocated_clone(secp256k1_context_static, sttc_prealloc); } else { - none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - sttc = secp256k1_context_clone(secp256k1_context_no_precomp); + sttc = secp256k1_context_clone(secp256k1_context_static); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); } + test_deprecated_flags(); + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); ecount = 0; ecount2 = 10; secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount2); /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */ - secp256k1_context_set_error_callback(sign, secp256k1_default_illegal_callback_fn, NULL); - CHECK(sign->error_callback.fn != vrfy->error_callback.fn); - CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn); + secp256k1_context_set_error_callback(ctx, secp256k1_default_illegal_callback_fn, NULL); + CHECK(ctx->error_callback.fn != sttc->error_callback.fn); + CHECK(ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); /* check if sizes for cloning are consistent */ - CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); - CHECK(secp256k1_context_preallocated_clone_size(sign) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); - CHECK(secp256k1_context_preallocated_clone_size(vrfy) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); - CHECK(secp256k1_context_preallocated_clone_size(both) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); + CHECK(secp256k1_context_preallocated_clone_size(ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(secp256k1_context_preallocated_clone_size(sttc) >= sizeof(secp256k1_context)); /*** clone and destroy all of them to make sure cloning was complete ***/ @@ -211,58 +232,31 @@ void run_context_tests(int use_prealloc) { if (use_prealloc) { /* clone into a non-preallocated context and then again into a new preallocated one. */ - ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp); - free(none_prealloc); none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL); - ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, none_prealloc); secp256k1_context_destroy(ctx_tmp); - - ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp); - free(sign_prealloc); sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL); - ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, sign_prealloc); secp256k1_context_destroy(ctx_tmp); - - ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp); - free(vrfy_prealloc); vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL); - ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, vrfy_prealloc); secp256k1_context_destroy(ctx_tmp); - - ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp); - free(both_prealloc); both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL); - ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, both_prealloc); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = ctx; ctx = secp256k1_context_clone(ctx); secp256k1_context_preallocated_destroy(ctx_tmp); + free(ctx_prealloc); ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(ctx_prealloc != NULL); + ctx_tmp = ctx; ctx = secp256k1_context_preallocated_clone(ctx, ctx_prealloc); secp256k1_context_destroy(ctx_tmp); } else { /* clone into a preallocated context and then again into a new non-preallocated one. */ void *prealloc_tmp; prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL); - ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - - prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL); - ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - - prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); - ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp); - free(prealloc_tmp); - - prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); - ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp); + ctx_tmp = ctx; ctx = secp256k1_context_preallocated_clone(ctx, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = ctx; ctx = secp256k1_context_clone(ctx); secp256k1_context_preallocated_destroy(ctx_tmp); free(prealloc_tmp); } } /* Verify that the error callback makes it across the clone. */ - CHECK(sign->error_callback.fn != vrfy->error_callback.fn); - CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(ctx->error_callback.fn != sttc->error_callback.fn); + CHECK(ctx->error_callback.fn == secp256k1_default_illegal_callback_fn); /* And that it resets back to default. */ - secp256k1_context_set_error_callback(sign, NULL, NULL); - CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + secp256k1_context_set_error_callback(ctx, NULL, NULL); + CHECK(ctx->error_callback.fn == sttc->error_callback.fn); /*** attempt to use them ***/ random_scalar_order_test(&msg); random_scalar_order_test(&key); - secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); /* Verify context-type checking illegal-argument errors. */ @@ -270,29 +264,29 @@ void run_context_tests(int use_prealloc) { CHECK(secp256k1_ec_pubkey_create(sttc, &pubkey, ctmp) == 0); CHECK(ecount == 1); VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); VG_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ecdsa_sign(sttc, &sig, ctmp, ctmp, NULL, NULL) == 0); CHECK(ecount == 2); VG_UNDEF(&sig, sizeof(sig)); - CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, ctmp, ctmp, NULL, NULL) == 1); VG_CHECK(&sig, sizeof(sig)); CHECK(ecount2 == 10); - CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, ctmp, &pubkey) == 1); CHECK(ecount2 == 10); CHECK(secp256k1_ecdsa_verify(sttc, &sig, ctmp, &pubkey) == 1); CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp) == 1); CHECK(ecount2 == 10); CHECK(secp256k1_ec_pubkey_tweak_add(sttc, &pubkey, ctmp) == 1); CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp) == 1); CHECK(ecount2 == 10); CHECK(secp256k1_ec_pubkey_negate(sttc, &pubkey) == 1); CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1); + CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey) == 1); CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0); + CHECK(secp256k1_ec_pubkey_negate(ctx, NULL) == 0); CHECK(ecount2 == 11); CHECK(secp256k1_ec_pubkey_negate(sttc, &zero_pubkey) == 0); CHECK(ecount == 3); @@ -302,49 +296,37 @@ void run_context_tests(int use_prealloc) { CHECK(ecount == 3); CHECK(secp256k1_context_randomize(sttc, NULL) == 1); CHECK(ecount == 3); - CHECK(secp256k1_context_randomize(sign, ctmp) == 1); + CHECK(secp256k1_context_randomize(ctx, ctmp) == 1); CHECK(ecount2 == 11); - CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(secp256k1_context_randomize(ctx, NULL) == 1); CHECK(ecount2 == 11); secp256k1_context_set_illegal_callback(sttc, NULL, NULL); - secp256k1_context_set_illegal_callback(sign, NULL, NULL); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); /* obtain a working nonce */ do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try verifying */ CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); /* cleanup */ if (use_prealloc) { - secp256k1_context_preallocated_destroy(none); - secp256k1_context_preallocated_destroy(sign); - secp256k1_context_preallocated_destroy(vrfy); - secp256k1_context_preallocated_destroy(both); + secp256k1_context_preallocated_destroy(ctx); secp256k1_context_preallocated_destroy(sttc); - free(none_prealloc); - free(sign_prealloc); - free(vrfy_prealloc); - free(both_prealloc); + free(ctx_prealloc); free(sttc_prealloc); } else { - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); + secp256k1_context_destroy(ctx); secp256k1_context_destroy(sttc); } /* Defined as no-op. */ secp256k1_context_destroy(NULL); secp256k1_context_preallocated_destroy(NULL); - } void run_scratch_tests(void) { @@ -353,83 +335,85 @@ void run_scratch_tests(void) { int32_t ecount = 0; size_t checkpoint; size_t checkpoint_2; - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_scratch_space *scratch; secp256k1_scratch_space local_scratch; + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + /* Test public API */ - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount); - scratch = secp256k1_scratch_space_create(none, 1000); + scratch = secp256k1_scratch_space_create(ctx, 1000); CHECK(scratch != NULL); CHECK(ecount == 0); /* Test internal API */ - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000); - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1)); CHECK(scratch->alloc_size == 0); CHECK(scratch->alloc_size % ALIGNMENT == 0); /* Allocating 500 bytes succeeds */ - checkpoint = secp256k1_scratch_checkpoint(&none->error_callback, scratch); - CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL); - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc); - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 500) != NULL); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); CHECK(scratch->alloc_size != 0); CHECK(scratch->alloc_size % ALIGNMENT == 0); /* Allocating another 501 bytes fails */ - CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 501) == NULL); - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc); - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 501) == NULL); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000 - adj_alloc); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1)); CHECK(scratch->alloc_size != 0); CHECK(scratch->alloc_size % ALIGNMENT == 0); /* ...but it succeeds once we apply the checkpoint to undo it */ - secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint); + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint); CHECK(scratch->alloc_size == 0); - CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000); - CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL); + CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000); + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 500) != NULL); CHECK(scratch->alloc_size != 0); /* try to apply a bad checkpoint */ - checkpoint_2 = secp256k1_scratch_checkpoint(&none->error_callback, scratch); - secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint); + checkpoint_2 = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch); + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint); CHECK(ecount == 0); - secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */ + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */ CHECK(ecount == 1); - secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */ + secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */ CHECK(ecount == 2); /* try to use badly initialized scratch space */ - secp256k1_scratch_space_destroy(none, scratch); + secp256k1_scratch_space_destroy(ctx, scratch); memset(&local_scratch, 0, sizeof(local_scratch)); scratch = &local_scratch; - CHECK(!secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0)); + CHECK(!secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0)); CHECK(ecount == 3); - CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL); + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 500) == NULL); CHECK(ecount == 4); - secp256k1_scratch_space_destroy(none, scratch); + secp256k1_scratch_space_destroy(ctx, scratch); CHECK(ecount == 5); /* Test that large integers do not wrap around in a bad way */ - scratch = secp256k1_scratch_space_create(none, 1000); + scratch = secp256k1_scratch_space_create(ctx, 1000); /* Try max allocation with a large number of objects. Only makes sense if * ALIGNMENT is greater than 1 because otherwise the objects take no extra * space. */ - CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); + CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1)); /* Try allocating SIZE_MAX to test wrap around which only happens if * ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch * space is too small. */ - CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL); - secp256k1_scratch_space_destroy(none, scratch); + CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, SIZE_MAX) == NULL); + secp256k1_scratch_space_destroy(ctx, scratch); /* cleanup */ - secp256k1_scratch_space_destroy(none, NULL); /* no-op */ - secp256k1_context_destroy(none); + secp256k1_scratch_space_destroy(ctx, NULL); /* no-op */ + secp256k1_context_destroy(ctx); } + void run_ctz_tests(void) { static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; @@ -697,7 +681,6 @@ void run_rfc6979_hmac_sha256_tests(void) { void run_tagged_sha256_tests(void) { int ecount = 0; - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); unsigned char tag[32] = { 0 }; unsigned char msg[32] = { 0 }; unsigned char hash32[32]; @@ -708,23 +691,22 @@ void run_tagged_sha256_tests(void) { 0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3 }; - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); /* API test */ - CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); - CHECK(secp256k1_tagged_sha256(none, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0); + CHECK(secp256k1_tagged_sha256(ctx, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); + CHECK(secp256k1_tagged_sha256(ctx, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0); CHECK(ecount == 1); - CHECK(secp256k1_tagged_sha256(none, hash32, NULL, 0, msg, sizeof(msg)) == 0); + CHECK(secp256k1_tagged_sha256(ctx, hash32, NULL, 0, msg, sizeof(msg)) == 0); CHECK(ecount == 2); - CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), NULL, 0) == 0); + CHECK(secp256k1_tagged_sha256(ctx, hash32, tag, sizeof(tag), NULL, 0) == 0); CHECK(ecount == 3); /* Static test vector */ memcpy(tag, "tag", 3); memcpy(msg, "msg", 3); - CHECK(secp256k1_tagged_sha256(none, hash32, tag, 3, msg, 3) == 1); + CHECK(secp256k1_tagged_sha256(ctx, hash32, tag, 3, msg, 3) == 1); CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); - secp256k1_context_destroy(none); } /***** RANDOM TESTS *****/ @@ -814,7 +796,8 @@ uint64_t modinv2p64(uint64_t x) { return w; } -/* compute out = (a*b) mod m; if b=NULL, treat b=1. + +/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity. * * Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other * arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */ @@ -856,46 +839,48 @@ void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16 } } - /* Compute the highest set bit in m. */ - for (i = 255; i >= 0; --i) { - if ((m[i >> 4] >> (i & 15)) & 1) { - m_bitlen = i; - break; + if (m) { + /* Compute the highest set bit in m. */ + for (i = 255; i >= 0; --i) { + if ((m[i >> 4] >> (i & 15)) & 1) { + m_bitlen = i; + break; + } } - } - /* Try do mul -= m<<i, for i going down to 0, whenever the result is not negative */ - for (i = mul_bitlen - m_bitlen; i >= 0; --i) { - uint16_t mul2[32]; - int64_t cs; - - /* Compute mul2 = mul - m<<i. */ - cs = 0; /* accumulator */ - for (j = 0; j < 32; ++j) { /* j loops over the output limbs in mul2. */ - /* Compute sub: the 16 bits in m that will be subtracted from mul2[j]. */ - uint16_t sub = 0; - int p; - for (p = 0; p < 16; ++p) { /* p loops over the bit positions in mul2[j]. */ - int bitpos = j * 16 - i + p; /* bitpos is the correspond bit position in m. */ - if (bitpos >= 0 && bitpos < 256) { - sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; + /* Try do mul -= m<<i, for i going down to 0, whenever the result is not negative */ + for (i = mul_bitlen - m_bitlen; i >= 0; --i) { + uint16_t mul2[32]; + int64_t cs; + + /* Compute mul2 = mul - m<<i. */ + cs = 0; /* accumulator */ + for (j = 0; j < 32; ++j) { /* j loops over the output limbs in mul2. */ + /* Compute sub: the 16 bits in m that will be subtracted from mul2[j]. */ + uint16_t sub = 0; + int p; + for (p = 0; p < 16; ++p) { /* p loops over the bit positions in mul2[j]. */ + int bitpos = j * 16 - i + p; /* bitpos is the correspond bit position in m. */ + if (bitpos >= 0 && bitpos < 256) { + sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p; + } } + /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ + cs += mul[j]; + cs -= sub; + mul2[j] = (cs & 0xFFFF); + cs >>= 16; + } + /* If remainder of subtraction is 0, set mul = mul2. */ + if (cs == 0) { + memcpy(mul, mul2, sizeof(mul)); } - /* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */ - cs += mul[j]; - cs -= sub; - mul2[j] = (cs & 0xFFFF); - cs >>= 16; } - /* If remainder of subtraction is 0, set mul = mul2. */ - if (cs == 0) { - memcpy(mul, mul2, sizeof(mul)); + /* Sanity check: test that all limbs higher than m's highest are zero */ + for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { + CHECK(mul[i] == 0); } } - /* Sanity check: test that all limbs higher than m's highest are zero */ - for (i = (m_bitlen >> 4) + 1; i < 32; ++i) { - CHECK(mul[i] == 0); - } memcpy(out, mul, 32); } @@ -1710,8 +1695,305 @@ void run_modinv_tests(void) { } } -/***** SCALAR TESTS *****/ +/***** INT128 TESTS *****/ + +#ifdef SECP256K1_WIDEMUL_INT128 +/* Add two 256-bit numbers (represented as 16 uint16_t's in LE order) together mod 2^256. */ +void add256(uint16_t* out, const uint16_t* a, const uint16_t* b) { + int i; + uint32_t carry = 0; + for (i = 0; i < 16; ++i) { + carry += a[i]; + carry += b[i]; + out[i] = carry; + carry >>= 16; + } +} + +/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */ +void neg256(uint16_t* out, const uint16_t* a) { + int i; + uint32_t carry = 1; + for (i = 0; i < 16; ++i) { + carry += (uint16_t)~a[i]; + out[i] = carry; + carry >>= 16; + } +} + +/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */ +void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { + uint16_t sign = sign_extend && (a[15] >> 15); + int i, j; + for (i = 15; i >= 0; --i) { + uint16_t v = 0; + for (j = 0; j < 16; ++j) { + int frompos = i*16 + j + n; + if (frompos >= 256) { + v |= sign << j; + } else { + v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j; + } + } + out[i] = v; + } +} + +/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +void load256u64(uint16_t* out, uint64_t v, int is_signed) { + int i; + uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = v >> (16 * i); + } + for (i = 4; i < 16; ++i) { + out[i] = sign; + } +} + +/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ +void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { + int i; + uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0; + for (i = 0; i < 4; ++i) { + out[i] = lo >> (16 * i); + } + for (i = 4; i < 8; ++i) { + out[i] = hi >> (16 * (i - 4)); + } + for (i = 8; i < 16; ++i) { + out[i] = sign; + } +} + +/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */ +int int256is127(const uint16_t* v) { + int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000); + int i; + for (i = 8; i < 16; ++i) { + if (v[i] != 0) all_0 = 0; + if (v[i] != 0xffff) all_1 = 0; + } + return all_0 || all_1; +} +void load256u128(uint16_t* out, const secp256k1_uint128* v) { + uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v); + load256two64(out, hi, lo, 0); +} + +void load256i128(uint16_t* out, const secp256k1_int128* v) { + uint64_t lo; + int64_t hi; + secp256k1_int128 c = *v; + lo = secp256k1_i128_to_i64(&c); + secp256k1_i128_rshift(&c, 64); + hi = secp256k1_i128_to_i64(&c); + load256two64(out, hi, lo, 1); +} + +void run_int128_test_case(void) { + unsigned char buf[32]; + uint64_t v[4]; + secp256k1_int128 swa, swz; + secp256k1_uint128 uwa, uwz; + uint64_t ub, uc; + int64_t sb, sc; + uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32]; + uint16_t rub[16], ruc[16], rsb[16], rsc[16]; + int i; + + /* Generate 32-byte random value. */ + secp256k1_testrand256_test(buf); + /* Convert into 4 64-bit integers. */ + for (i = 0; i < 4; ++i) { + uint64_t vi = 0; + int j; + for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j]; + v[i] = vi; + } + /* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */ + secp256k1_u128_load(&uwa, v[1], v[0]); + secp256k1_i128_load(&swa, v[1], v[0]); + ub = v[2]; + sb = v[2]; + uc = v[3]; + sc = v[3]; + /* Load those also into 16-bit array representations. */ + load256u128(ruwa, &uwa); + load256i128(rswa, &swa); + load256u64(rub, ub, 0); + load256u64(rsb, sb, 1); + load256u64(ruc, uc, 0); + load256u64(rsc, sc, 1); + /* test secp256k1_u128_mul */ + mulmod256(ruwr, rub, ruc, NULL); + secp256k1_u128_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_accum_mul */ + mulmod256(ruwr, rub, ruc, NULL); + add256(ruwr, ruwr, ruwa); + uwz = uwa; + secp256k1_u128_accum_mul(&uwz, ub, uc); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_accum_u64 */ + add256(ruwr, rub, ruwa); + uwz = uwa; + secp256k1_u128_accum_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_rshift */ + rshift256(ruwr, ruwa, uc % 128, 0); + uwz = uwa; + secp256k1_u128_rshift(&uwz, uc % 128); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0); + /* test secp256k1_u128_to_u64 */ + CHECK(secp256k1_u128_to_u64(&uwa) == v[0]); + /* test secp256k1_u128_hi_u64 */ + CHECK(secp256k1_u128_hi_u64(&uwa) == v[1]); + /* test secp256k1_u128_from_u64 */ + secp256k1_u128_from_u64(&uwz, ub); + load256u128(ruwz, &uwz); + CHECK(secp256k1_memcmp_var(rub, ruwz, 16) == 0); + /* test secp256k1_u128_check_bits */ + { + int uwa_bits = 0; + int j; + for (j = 0; j < 128; ++j) { + if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j; + } + for (j = 0; j < 128; ++j) { + CHECK(secp256k1_u128_check_bits(&uwa, j) == (uwa_bits <= j)); + } + } + /* test secp256k1_i128_mul */ + mulmod256(rswr, rsb, rsc, NULL); + secp256k1_i128_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + /* test secp256k1_i128_accum_mul */ + mulmod256(rswr, rsb, rsc, NULL); + add256(rswr, rswr, rswa); + if (int256is127(rswr)) { + swz = swa; + secp256k1_i128_accum_mul(&swz, sb, sc); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + } + /* test secp256k1_i128_det */ + { + uint16_t rsd[16], rse[16], rst[32]; + int64_t sd = v[0], se = v[1]; + load256u64(rsd, sd, 1); + load256u64(rse, se, 1); + mulmod256(rst, rsc, rsd, NULL); + neg256(rst, rst); + mulmod256(rswr, rsb, rse, NULL); + add256(rswr, rswr, rst); + secp256k1_i128_det(&swz, sb, sc, sd, se); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + } + /* test secp256k1_i128_rshift */ + rshift256(rswr, rswa, uc % 127, 1); + swz = swa; + secp256k1_i128_rshift(&swz, uc % 127); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0); + /* test secp256k1_i128_to_i64 */ + CHECK((uint64_t)secp256k1_i128_to_i64(&swa) == v[0]); + /* test secp256k1_i128_from_i64 */ + secp256k1_i128_from_i64(&swz, sb); + load256i128(rswz, &swz); + CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0); + /* test secp256k1_i128_eq_var */ + { + int expect = (uc & 1); + swz = swa; + if (!expect) { + /* Make sure swz != swa */ + uint64_t v0c = v[0], v1c = v[1]; + if (ub & 64) { + v1c ^= (((uint64_t)1) << (ub & 63)); + } else { + v0c ^= (((uint64_t)1) << (ub & 63)); + } + secp256k1_i128_load(&swz, v1c, v0c); + } + CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect); + } + /* test secp256k1_i128_check_pow2 */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly (2 << pos). */ + uint64_t hi = 0; + uint64_t lo = 0; + if (pos & 64) { + hi = (((uint64_t)1) << (pos & 63)); + } else { + lo = (((uint64_t)1) << (pos & 63)); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal (2 << pos). */ + if (pos & 64) { + if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos) == expect); + } +} + +void run_int128_tests(void) { + { /* secp256k1_u128_accum_mul */ + secp256k1_uint128 res; + + /* Check secp256k1_u128_accum_mul overflow */ + secp256k1_u128_mul(&res, UINT64_MAX, UINT64_MAX); + secp256k1_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX); + CHECK(secp256k1_u128_to_u64(&res) == 2); + CHECK(secp256k1_u128_hi_u64(&res) == 18446744073709551612U); + } + { /* secp256k1_u128_accum_mul */ + secp256k1_int128 res; + + /* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */ + secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX); + secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX); + CHECK(secp256k1_i128_to_i64(&res) == 2); + secp256k1_i128_accum_mul(&res, 4, 9223372036854775807); + secp256k1_i128_accum_mul(&res, 1, 1); + CHECK((uint64_t)secp256k1_i128_to_i64(&res) == UINT64_MAX); + secp256k1_i128_rshift(&res, 64); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX); + + /* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */ + secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN); + secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN); + CHECK(secp256k1_i128_to_i64(&res) == 0); + secp256k1_i128_accum_mul(&res, 2, INT64_MIN); + CHECK(secp256k1_i128_to_i64(&res) == 0); + secp256k1_i128_rshift(&res, 64); + CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN); + } + { + /* Randomized tests. */ + int i; + for (i = 0; i < 256 * count; ++i) run_int128_test_case(); + } +} +#endif + +/***** SCALAR TESTS *****/ void scalar_test(void) { secp256k1_scalar s; @@ -3562,6 +3844,22 @@ void run_gej(void) { test_gej_cmov(&a, &b); test_gej_cmov(&b, &a); } + + /* Tests for secp256k1_gej_eq_var */ + for (i = 0; i < count; i++) { + secp256k1_fe fe; + random_gej_test(&a); + random_gej_test(&b); + CHECK(!secp256k1_gej_eq_var(&a, &b)); + + b = a; + random_field_element_test(&fe); + if (secp256k1_fe_is_zero(&fe)) { + continue; + } + secp256k1_gej_rescale(&a, &fe); + CHECK(secp256k1_gej_eq_var(&a, &b)); + } } void test_ec_combine(void) { @@ -3767,17 +4065,12 @@ void run_ecmult_chain(void) { 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 ); - - secp256k1_gej_neg(&rp, &rp); - secp256k1_gej_add_var(&rp, &rp, &x, NULL); - CHECK(secp256k1_gej_is_infinity(&rp)); + CHECK(secp256k1_gej_eq_var(&rp, &x)); } } /* redo the computation, but directly with the resulting ae and ge coefficients: */ secp256k1_ecmult(&x2, &a, &ae, &ge); - secp256k1_gej_neg(&x2, &x2); - secp256k1_gej_add_var(&x2, &x2, &x, NULL); - CHECK(secp256k1_gej_is_infinity(&x2)); + CHECK(secp256k1_gej_eq_var(&x, &x2)); } void test_point_times_order(const secp256k1_gej *point) { @@ -4070,16 +4363,12 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e /* only G scalar */ secp256k1_ecmult(&r2, &ptgj, &szero, &sc[0]); CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); - secp256k1_gej_neg(&r2, &r2); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); /* 1-point */ secp256k1_ecmult(&r2, &ptgj, &sc[0], &szero); CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); - secp256k1_gej_neg(&r2, &r2); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); /* Try to multiply 1 point, but callback returns false */ CHECK(!ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); @@ -4087,16 +4376,12 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e /* 2-point */ secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); - secp256k1_gej_neg(&r2, &r2); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); /* 2-point with G scalar */ secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]); CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); - secp256k1_gej_neg(&r2, &r2); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); } /* Check infinite outputs of various forms */ @@ -4181,9 +4466,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_ecmult(&r2, &r, &sc[0], &szero); CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); - secp256k1_gej_neg(&r2, &r2); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); } /* Check random scalars, constant point */ @@ -4204,9 +4487,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_gej_set_ge(&p0j, &pt[0]); secp256k1_ecmult(&r2, &p0j, &rs, &szero); CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); - secp256k1_gej_neg(&r2, &r2); - secp256k1_gej_add_var(&r, &r, &r2, NULL); - CHECK(secp256k1_gej_is_infinity(&r)); + CHECK(secp256k1_gej_eq_var(&r, &r2)); } /* Sanity check that zero scalars don't cause problems */ @@ -4268,9 +4549,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e secp256k1_ecmult(&expected, &ptgj, &tmp1, &szero); CHECK(ecmult_multi(&ctx->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); - secp256k1_gej_neg(&expected, &expected); - secp256k1_gej_add_var(&actual, &actual, &expected, NULL); - CHECK(secp256k1_gej_is_infinity(&actual)); + CHECK(secp256k1_gej_eq_var(&actual, &expected)); } } } @@ -4440,9 +4719,7 @@ int test_ecmult_multi_random(secp256k1_scratch *scratch) { CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled)); mults += num_nonzero + g_nonzero; /* Compare with expected result. */ - secp256k1_gej_neg(&computed, &computed); - secp256k1_gej_add_var(&computed, &computed, &expected, NULL); - CHECK(secp256k1_gej_is_infinity(&computed)); + CHECK(secp256k1_gej_eq_var(&computed, &expected)); return mults; } @@ -5497,7 +5774,7 @@ void run_ec_pubkey_parse_test(void) { ecount = 0; VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); - CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp, &pubkey, pubkeyc, 65) == 1); + CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1); VG_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); VG_UNDEF(&ge, sizeof(ge)); @@ -7083,19 +7360,27 @@ int main(int argc, char **argv) { secp256k1_testrand_init(argc > 2 ? argv[2] : NULL); /* initialize */ + run_selftest_tests(); run_context_tests(0); run_context_tests(1); run_scratch_tests(); - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - if (secp256k1_testrand_bits(1)) { + + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + /* Randomize the context only with probability 15/16 + to make sure we test without context randomization from time to time. + TODO Reconsider this when recalibrating the tests. */ + if (secp256k1_testrand_bits(4)) { unsigned char rand32[32]; secp256k1_testrand256(rand32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_testrand_bits(1) ? rand32 : NULL)); + CHECK(secp256k1_context_randomize(ctx, rand32)); } run_rand_bits(); run_rand_int(); +#ifdef SECP256K1_WIDEMUL_INT128 + run_int128_tests(); +#endif run_ctz_tests(); run_modinv_tests(); run_inverse_tests(); diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c index 6a4e2340f2..c001dcb80b 100644 --- a/src/secp256k1/src/tests_exhaustive.c +++ b/src/secp256k1/src/tests_exhaustive.c @@ -342,15 +342,15 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou } #ifdef ENABLE_MODULE_RECOVERY -#include "src/modules/recovery/tests_exhaustive_impl.h" +#include "modules/recovery/tests_exhaustive_impl.h" #endif #ifdef ENABLE_MODULE_EXTRAKEYS -#include "src/modules/extrakeys/tests_exhaustive_impl.h" +#include "modules/extrakeys/tests_exhaustive_impl.h" #endif #ifdef ENABLE_MODULE_SCHNORRSIG -#include "src/modules/schnorrsig/tests_exhaustive_impl.h" +#include "modules/schnorrsig/tests_exhaustive_impl.h" #endif int main(int argc, char** argv) { @@ -396,7 +396,7 @@ int main(int argc, char** argv) { while (count--) { /* Build context */ - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_testrand256(rand32); CHECK(secp256k1_context_randomize(ctx, rand32)); diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index dac86bd77f..864baaee4d 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -16,6 +16,11 @@ #include <stdio.h> #include <limits.h> +#define STR_(x) #x +#define STR(x) STR_(x) +#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x +#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) + typedef struct { void (*fn)(const char *text, void* data); const void* data; @@ -225,28 +230,36 @@ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) *r = (int)(r_masked | a_masked); } -/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation. - * Otherwise use the presence of __SIZEOF_INT128__ to decide. - */ -#if defined(USE_FORCE_WIDEMUL_INT128) +#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT) +/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */ # define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif defined(USE_FORCE_WIDEMUL_INT128) +/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 #elif defined(USE_FORCE_WIDEMUL_INT64) +/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */ # define SECP256K1_WIDEMUL_INT64 1 #elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__) +/* If a native 128-bit integer type exists, use int128. */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_NATIVE 1 +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) +/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct + * (which has special logic to implement using intrinsics on those systems). */ # define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 +#elif SIZE_MAX > 0xffffffff +/* Systems with 64-bit pointers (and thus registers) very likely benefit from + * using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based + * multiplication logic). */ +# define SECP256K1_WIDEMUL_INT128 1 +# define SECP256K1_INT128_STRUCT 1 #else +/* Lastly, fall back to int64 based arithmetic. */ # define SECP256K1_WIDEMUL_INT64 1 #endif -#if defined(SECP256K1_WIDEMUL_INT128) -# if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__) -SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; -SECP256K1_GNUC_EXT typedef __int128 int128_t; -#define UINT128_MAX ((uint128_t)(-1)) -#define INT128_MAX ((int128_t)(UINT128_MAX >> 1)) -#define INT128_MIN (-INT128_MAX - 1) -/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */ -# endif -#endif #ifndef __has_builtin #define __has_builtin(x) 0 diff --git a/src/secp256k1/src/valgrind_ctime_test.c b/src/secp256k1/src/valgrind_ctime_test.c index 6ff0085d34..a0f888b00f 100644 --- a/src/secp256k1/src/valgrind_ctime_test.c +++ b/src/secp256k1/src/valgrind_ctime_test.c @@ -39,9 +39,7 @@ int main(void) { fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n"); return 1; } - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN - | SECP256K1_CONTEXT_VERIFY - | SECP256K1_CONTEXT_DECLASSIFY); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); /** In theory, testing with a single secret input should be sufficient: * If control flow depended on secrets the tool would generate an error. */ diff --git a/src/serialize.h b/src/serialize.h index 89a9f32240..f1edc54031 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/shutdown.cpp b/src/shutdown.cpp index 1dbc55aeb5..57d6d2325d 100644 --- a/src/shutdown.cpp +++ b/src/shutdown.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/span.h b/src/span.h index 444d63001f..4d00bbc244 100644 --- a/src/span.h +++ b/src/span.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/streams.h b/src/streams.h index 84b12f65aa..4f2c3ffe76 100644 --- a/src/streams.h +++ b/src/streams.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h index 0befe0ffcd..795eea3bc0 100644 --- a/src/support/allocators/zeroafterfree.h +++ b/src/support/allocators/zeroafterfree.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/cleanse.h b/src/support/cleanse.h index b1227770c7..161f3cc388 100644 --- a/src/support/cleanse.h +++ b/src/support/cleanse.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index e48accf0a4..fb59324f7a 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/sync.h b/src/sync.h index 1f4e191214..8ce2e7b124 100644 --- a/src/sync.h +++ b/src/sync.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index b10d32ccec..b15df43e8c 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index a923d38467..6a37b7d83b 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/banman_tests.cpp b/src/test/banman_tests.cpp index ecf60834ce..cebe3629d4 100644 --- a/src/test/banman_tests.cpp +++ b/src/test/banman_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index c6109dfeb0..4617beecd9 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 249f89ae2f..0101bcc372 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index 54a02c6bf8..6462aa82fb 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 75b29ae0aa..fe3d8995e9 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2021 The Bitcoin Core developers +// Copyright (c) 2013-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp index 0157e25071..b590467a43 100644 --- a/src/test/blockchain_tests.cpp +++ b/src/test/blockchain_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 1c13c0a909..e1dafc6bac 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 2798e998af..a572bb02b9 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index 0831188327..43dca57217 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 35c4108caa..3d6e103c9f 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 875522d744..53fbc26e15 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -194,7 +194,7 @@ static void Correct_Queue_range(std::vector<size_t> range) BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) { std::vector<size_t> range; - range.push_back((size_t)0); + range.push_back(size_t{0}); Correct_Queue_range(range); } /** Test that 1 check is correct @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One) { std::vector<size_t> range; - range.push_back((size_t)1); + range.push_back(size_t{1}); Correct_Queue_range(range); } /** Test that MAX check is correct diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index b333a9f72d..b5f961a239 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2021 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index 8a2b0792fd..503a58076b 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 6148edf115..9b369a5c50 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -723,14 +723,14 @@ BOOST_AUTO_TEST_CASE(countbits_tests) // Check handling of zero. BOOST_CHECK_EQUAL(CountBits(0), 0U); } else if (i < 10) { - for (uint64_t j = (uint64_t)1 << (i - 1); (j >> i) == 0; ++j) { + for (uint64_t j = uint64_t{1} << (i - 1); (j >> i) == 0; ++j) { // Exhaustively test up to 10 bits BOOST_CHECK_EQUAL(CountBits(j), i); } } else { for (int k = 0; k < 1000; k++) { // Randomly test 1000 samples of each length above 10 bits. - uint64_t j = ((uint64_t)1) << (i - 1) | ctx.randbits(i - 1); + uint64_t j = (uint64_t{1}) << (i - 1) | ctx.randbits(i - 1); BOOST_CHECK_EQUAL(CountBits(j), i); } } diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index ab4c587c46..2447c882ae 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 7150698e64..aca2b8eff0 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 6b2ef74e19..6e4f6cdbab 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp index 605faa08e4..9931d19c2b 100644 --- a/src/test/flatfile_tests.cpp +++ b/src/test/flatfile_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index d2554483d4..7e7d630daa 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/test/fuzz/addition_overflow.cpp b/src/test/fuzz/addition_overflow.cpp index 372c1a370e..7b84bfda20 100644 --- a/src/test/fuzz/addition_overflow.cpp +++ b/src/test/fuzz/addition_overflow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index f3c29cd6b8..2953cf149d 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp index 1a8957d090..a7b41370a8 100644 --- a/src/test/fuzz/autofile.cpp +++ b/src/test/fuzz/autofile.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index d10f4586b4..273dcfd850 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/base_encode_decode.cpp b/src/test/fuzz/base_encode_decode.cpp index 48356065b0..d322416d34 100644 --- a/src/test/fuzz/base_encode_decode.cpp +++ b/src/test/fuzz/base_encode_decode.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,12 +14,7 @@ #include <string> #include <vector> -void initialize_base_encode_decode() -{ - static const ECCVerifyHandle verify_handle; -} - -FUZZ_TARGET_INIT(base_encode_decode, initialize_base_encode_decode) +FUZZ_TARGET(base_encode_decode) { const std::string random_encoded_string(buffer.begin(), buffer.end()); diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index b7ed2c6abd..c3e17724eb 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -19,7 +19,6 @@ void initialize_block() { - static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp index a8c3318629..67cac8fa4e 100644 --- a/src/test/fuzz/buffered_file.cpp +++ b/src/test/fuzz/buffered_file.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp index 01edb06138..49b9898228 100644 --- a/src/test/fuzz/chain.cpp +++ b/src/test/fuzz/chain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/checkqueue.cpp b/src/test/fuzz/checkqueue.cpp index 7d107995aa..6256aefaa3 100644 --- a/src/test/fuzz/checkqueue.cpp +++ b/src/test/fuzz/checkqueue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 6c96702f1e..46026d8df3 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index e8b10a0ad0..798c14030c 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index f5f86a574a..1f5601ca9f 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -9,7 +9,6 @@ void initialize_descriptor_parse() { - static const ECCVerifyHandle verify_handle; ECC_Start(); SelectParams(CBaseChainParams::MAIN); } diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 0a7d0c55bd..7cd78e0461 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -46,9 +46,6 @@ void initialize_deserialize() { static const auto testing_setup = MakeNoLogFileContext<>(); g_setup = testing_setup.get(); - - // Fuzzers using pubkey must hold an ECCVerifyHandle. - static const ECCVerifyHandle verify_handle; } #define FUZZ_TARGET_DESERIALIZE(name, code) \ diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp index e7c49c2dbc..d762676c3c 100644 --- a/src/test/fuzz/eval_script.cpp +++ b/src/test/fuzz/eval_script.cpp @@ -9,12 +9,7 @@ #include <limits> -void initialize_eval_script() -{ - static const ECCVerifyHandle verify_handle; -} - -FUZZ_TARGET_INIT(eval_script, initialize_eval_script) +FUZZ_TARGET(eval_script) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 24ae34bd9e..9683f32d84 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp index b4bb4c6dc6..1a1225b635 100644 --- a/src/test/fuzz/golomb_rice.cpp +++ b/src/test/fuzz/golomb_rice.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp index e637975b48..f67b820d11 100644 --- a/src/test/fuzz/hex.cpp +++ b/src/test/fuzz/hex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,12 +16,7 @@ #include <string> #include <vector> -void initialize_hex() -{ - static const ECCVerifyHandle verify_handle; -} - -FUZZ_TARGET_INIT(hex, initialize_hex) +FUZZ_TARGET(hex) { const std::string random_hex_string(buffer.begin(), buffer.end()); const std::vector<unsigned char> data = ParseHex(random_hex_string); diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp index 0fe18abaa9..66a1ff945f 100644 --- a/src/test/fuzz/http_request.cpp +++ b/src/test/fuzz/http_request.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp index fb6d23aca5..6c2321cd68 100644 --- a/src/test/fuzz/i2p.cpp +++ b/src/test/fuzz/i2p.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,9 +8,10 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <test/util/setup_common.h> -#include <threadinterrupt.h> #include <util/system.h> +#include <util/threadinterrupt.h> void initialize_i2p() { diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index f05248ab47..7965f90dc7 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp index a76901e473..e83606f032 100644 --- a/src/test/fuzz/key.cpp +++ b/src/test/fuzz/key.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 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,6 @@ void initialize_key() { - static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp index 32a81c2e17..29c6996365 100644 --- a/src/test/fuzz/key_io.cpp +++ b/src/test/fuzz/key_io.cpp @@ -13,7 +13,6 @@ void initialize_key_io() { - static const ECCVerifyHandle verify_handle; ECC_Start(); SelectParams(CBaseChainParams::MAIN); } diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp index 06cd0afe2a..63e24aacdd 100644 --- a/src/test/fuzz/message.cpp +++ b/src/test/fuzz/message.cpp @@ -18,7 +18,6 @@ void initialize_message() { - static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp index 6be75322b4..1d6a8d89e4 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index 741810f6a2..13b4638688 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <test/util/net.h> #include <test/util/setup_common.h> #include <util/asmap.h> diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp index e62fe0328e..ae343602e9 100644 --- a/src/test/fuzz/net_permissions.cpp +++ b/src/test/fuzz/net_permissions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,6 +6,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <util/translation.h> #include <cassert> diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp index 2022f16a48..d61aef6d81 100644 --- a/src/test/fuzz/netaddress.cpp +++ b/src/test/fuzz/netaddress.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp index 39d4935126..81e216b358 100644 --- a/src/test/fuzz/netbase_dns_lookup.cpp +++ b/src/test/fuzz/netbase_dns_lookup.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp index e27b254580..e47432600c 100644 --- a/src/test/fuzz/node_eviction.cpp +++ b/src/test/fuzz/node_eviction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <algorithm> #include <cassert> diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp index 88c22ca305..96254aa222 100644 --- a/src/test/fuzz/p2p_transport_serialization.cpp +++ b/src/test/fuzz/p2p_transport_serialization.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,7 +24,7 @@ void initialize_p2p_transport_serialization() FUZZ_TARGET_INIT(p2p_transport_serialization, initialize_p2p_transport_serialization) { // Construct deserializer, with a dummy NodeId - V1TransportDeserializer deserializer{Params(), (NodeId)0, SER_NETWORK, INIT_PROTO_VERSION}; + V1TransportDeserializer deserializer{Params(), NodeId{0}, SER_NETWORK, INIT_PROTO_VERSION}; V1TransportSerializer serializer{}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index 0cc210f26f..16486f6b96 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,7 +13,6 @@ void initialize_parse_univalue() { - static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index 3788c36455..116fbd9015 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -1,7 +1,8 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 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 <kernel/mempool_entry.h> #include <policy/fees.h> #include <policy/fees_args.h> #include <primitives/transaction.h> @@ -11,7 +12,6 @@ #include <test/fuzz/util/mempool.h> #include <test/util/setup_common.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <cstdint> #include <optional> diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp index 436873c955..7c3289cd26 100644 --- a/src/test/fuzz/policy_estimator_io.cpp +++ b/src/test/fuzz/policy_estimator_io.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index eba03da773..e5a3a6e68a 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <util/check.h> #include <util/overflow.h> #include <cstdint> @@ -25,7 +26,7 @@ FUZZ_TARGET_INIT(pow, initialize_pow) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const Consensus::Params& consensus_params = Params().GetConsensus(); - std::vector<CBlockIndex> blocks; + std::vector<std::unique_ptr<CBlockIndex>> blocks; const uint32_t fixed_time = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); const uint32_t fixed_bits = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 10000) { @@ -33,9 +34,10 @@ FUZZ_TARGET_INIT(pow, initialize_pow) if (!block_header) { continue; } - CBlockIndex current_block{*block_header}; + CBlockIndex& current_block{ + *blocks.emplace_back(std::make_unique<CBlockIndex>(*block_header))}; { - CBlockIndex* previous_block = blocks.empty() ? nullptr : &PickValue(fuzzed_data_provider, blocks); + CBlockIndex* previous_block = blocks.empty() ? nullptr : PickValue(fuzzed_data_provider, blocks).get(); const int current_height = (previous_block != nullptr && previous_block->nHeight != std::numeric_limits<int>::max()) ? previous_block->nHeight + 1 : 0; if (fuzzed_data_provider.ConsumeBool()) { current_block.pprev = previous_block; @@ -57,7 +59,6 @@ FUZZ_TARGET_INIT(pow, initialize_pow) } else { current_block.nChainWork = ConsumeArithUInt256(fuzzed_data_provider); } - blocks.push_back(current_block); } { (void)GetBlockProof(current_block); @@ -67,9 +68,9 @@ FUZZ_TARGET_INIT(pow, initialize_pow) } } { - const CBlockIndex* to = &PickValue(fuzzed_data_provider, blocks); - const CBlockIndex* from = &PickValue(fuzzed_data_provider, blocks); - const CBlockIndex* tip = &PickValue(fuzzed_data_provider, blocks); + const auto& to = PickValue(fuzzed_data_provider, blocks); + const auto& from = PickValue(fuzzed_data_provider, blocks); + const auto& tip = PickValue(fuzzed_data_provider, blocks); try { (void)GetBlockProofEquivalentTime(*to, *from, *tip, consensus_params); } catch (const uint_error&) { diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp index e2d65a4796..c8fd9aca30 100644 --- a/src/test/fuzz/prevector.cpp +++ b/src/test/fuzz/prevector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 5a4df735da..0a7924f226 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,11 +14,11 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <test/util/mining.h> #include <test/util/net.h> #include <test/util/setup_common.h> #include <test/util/validation.h> -#include <txorphanage.h> #include <validationinterface.h> #include <version.h> @@ -56,7 +56,9 @@ void initialize_process_message() { Assert(GetNumMsgTypes() == getAllNetMessageTypes().size()); // If this fails, add or remove the message type below - static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); + static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>( + /*chain_name=*/CBaseChainParams::REGTEST, + /*extra_args=*/{"-txreconciliation"}); g_setup = testing_setup.get(); for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { MineBlock(g_setup->m_node, CScript() << OP_TRUE); diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 1df1717ec3..96339743ba 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,11 +9,11 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <test/util/mining.h> #include <test/util/net.h> #include <test/util/setup_common.h> #include <test/util/validation.h> -#include <txorphanage.h> #include <validation.h> #include <validationinterface.h> @@ -23,7 +23,9 @@ const TestingSetup* g_setup; void initialize_process_messages() { - static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); + static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>( + /*chain_name=*/CBaseChainParams::REGTEST, + /*extra_args=*/{"-txreconciliation"}); g_setup = testing_setup.get(); for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { MineBlock(g_setup->m_node, CScript() << OP_TRUE); diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp index baa64bba0f..825ed67ec1 100644 --- a/src/test/fuzz/psbt.cpp +++ b/src/test/fuzz/psbt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 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,7 @@ using node::AnalyzePSBT; using node::PSBTAnalysis; using node::PSBTInputAnalysis; -void initialize_psbt() -{ - static const ECCVerifyHandle verify_handle; -} - -FUZZ_TARGET_INIT(psbt, initialize_psbt) +FUZZ_TARGET(psbt) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; PartiallySignedTransaction psbt_mut; diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp index 678fc7a5aa..57a9a15a85 100644 --- a/src/test/fuzz/rbf.cpp +++ b/src/test/fuzz/rbf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index f32046e69f..361cfa6cb6 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 00d7b7e29a..1037dd934a 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -32,9 +32,6 @@ void initialize_script() { - // Fuzzers using pubkey must hold an ECCVerifyHandle. - static const ECCVerifyHandle verify_handle; - SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index 35d7246ed8..206d219afe 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -184,10 +184,7 @@ void Test(const std::string& str) } } -void test_init() -{ - static ECCVerifyHandle handle; -} +void test_init() {} FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, test_init, /*hidden=*/true) { diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp index 8dc99ee069..f8594fc233 100644 --- a/src/test/fuzz/script_flags.cpp +++ b/src/test/fuzz/script_flags.cpp @@ -11,12 +11,7 @@ #include <test/fuzz/fuzz.h> -void initialize_script_flags() -{ - static const ECCVerifyHandle verify_handle; -} - -FUZZ_TARGET_INIT(script_flags, initialize_script_flags) +FUZZ_TARGET(script_flags) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); try { diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp index f6af7947df..de895cc69c 100644 --- a/src/test/fuzz/script_sigcache.cpp +++ b/src/test/fuzz/script_sigcache.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp index 3ddb30d870..3cef81c251 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -26,7 +26,6 @@ void initialize_script_sign() { - static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp index f437d53b57..74ef6bfd4e 100644 --- a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp +++ b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp @@ -12,7 +12,7 @@ #include <vector> bool SigHasLowR(const secp256k1_ecdsa_signature* sig); -int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen); +int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen); FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax) { @@ -21,13 +21,11 @@ FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax) if (signature_bytes.data() == nullptr) { return; } - secp256k1_context* secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); secp256k1_ecdsa_signature sig_der_lax; - const bool parsed_der_lax = ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig_der_lax, signature_bytes.data(), signature_bytes.size()) == 1; + const bool parsed_der_lax = ecdsa_signature_parse_der_lax(&sig_der_lax, signature_bytes.data(), signature_bytes.size()) == 1; if (parsed_der_lax) { ECC_Start(); (void)SigHasLowR(&sig_der_lax); ECC_Stop(); } - secp256k1_context_destroy(secp256k1_context_verify); } diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp index a585680de1..59f4792961 100644 --- a/src/test/fuzz/signature_checker.cpp +++ b/src/test/fuzz/signature_checker.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,11 +14,6 @@ #include <string> #include <vector> -void initialize_signature_checker() -{ - static const auto verify_handle = std::make_unique<ECCVerifyHandle>(); -} - namespace { class FuzzedSignatureChecker : public BaseSignatureChecker { @@ -53,7 +48,7 @@ public: }; } // namespace -FUZZ_TARGET_INIT(signature_checker, initialize_signature_checker) +FUZZ_TARGET(signature_checker) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index c3a6eed089..97f643db49 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/fuzz/util/net.h> #include <test/util/setup_common.h> #include <cstdint> diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index f6373351d8..3c427b9bef 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index 7fa4523800..bacb178b44 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/tx_out.cpp b/src/test/fuzz/tx_out.cpp index a2421ff582..337b8e2771 100644 --- a/src/test/fuzz/tx_out.cpp +++ b/src/test/fuzz/tx_out.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index 46ca8e47e9..e933167341 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -211,7 +211,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) for (int i = 0; i < num_out; ++i) { tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE); } - const auto tx = MakeTransactionRef(tx_mut); + auto tx = MakeTransactionRef(tx_mut); // Restore previously removed outpoints for (const auto& in : tx->vin) { Assert(outpoints_rbf.insert(in.prevout).second); diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp index 55060f31cf..dafe8249c0 100644 --- a/src/test/fuzz/txorphan.cpp +++ b/src/test/fuzz/txorphan.cpp @@ -36,7 +36,6 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage) SetMockTime(ConsumeTime(fuzzed_data_provider)); TxOrphanage orphanage; - std::set<uint256> orphan_work_set; std::vector<COutPoint> outpoints; // initial outpoints used to construct transactions later for (uint8_t i = 0; i < 4; i++) { @@ -70,7 +69,7 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage) for (auto& in : tx_mut.vin) { outpoints.push_back(in.prevout); } - const auto new_tx = MakeTransactionRef(tx_mut); + auto new_tx = MakeTransactionRef(tx_mut); // add newly constructed transaction to outpoints for (uint32_t i = 0; i < num_out; i++) { outpoints.emplace_back(new_tx->GetHash(), i); @@ -86,15 +85,19 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage) CallOneOf( fuzzed_data_provider, [&] { - LOCK(g_cs_orphans); - orphanage.AddChildrenToWorkSet(*tx, orphan_work_set); + orphanage.AddChildrenToWorkSet(*tx, peer_id); }, [&] { - bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash())); { - LOCK(g_cs_orphans); - bool get_tx = orphanage.GetTx(tx->GetHash()).first != nullptr; - Assert(have_tx == get_tx); + NodeId originator; + bool more = true; + CTransactionRef ref = orphanage.GetTxToReconsider(peer_id, originator, more); + if (!ref) { + Assert(!more); + } else { + bool have_tx = orphanage.HaveTx(GenTxid::Txid(ref->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(ref->GetHash())); + Assert(have_tx); + } } }, [&] { @@ -102,14 +105,12 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage) // AddTx should return false if tx is too big or already have it // tx weight is unknown, we only check when tx is already in orphanage { - LOCK(g_cs_orphans); bool add_tx = orphanage.AddTx(tx, peer_id); // have_tx == true -> add_tx == false Assert(!have_tx || !add_tx); } have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash())); { - LOCK(g_cs_orphans); bool add_tx = orphanage.AddTx(tx, peer_id); // if have_tx is still false, it must be too big Assert(!have_tx == (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT)); @@ -120,25 +121,22 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage) bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash())); // EraseTx should return 0 if m_orphans doesn't have the tx { - LOCK(g_cs_orphans); Assert(have_tx == orphanage.EraseTx(tx->GetHash())); } have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash())); // have_tx should be false and EraseTx should fail { - LOCK(g_cs_orphans); Assert(!have_tx && !orphanage.EraseTx(tx->GetHash())); } }, [&] { - LOCK(g_cs_orphans); orphanage.EraseForPeer(peer_id); }, [&] { // test mocktime and expiry SetMockTime(ConsumeTime(fuzzed_data_provider)); auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); - WITH_LOCK(g_cs_orphans, orphanage.LimitOrphans(limit)); + orphanage.LimitOrphans(limit); Assert(orphanage.Size() <= limit); }); } diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 73ceb94b14..9da84fe90e 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -1,14 +1,12 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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 <consensus/amount.h> -#include <net_processing.h> -#include <netaddress.h> -#include <netmessagemaker.h> #include <pubkey.h> #include <test/fuzz/util.h> #include <test/util/script.h> +#include <util/check.h> #include <util/overflow.h> #include <util/rbf.h> #include <util/time.h> @@ -16,308 +14,6 @@ #include <memory> -FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) - : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()} -{ - m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET); -} - -FuzzedSock::~FuzzedSock() -{ - // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call - // close(m_socket) if m_socket is not INVALID_SOCKET. - // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which - // theoretically may concide with a real opened file descriptor). - m_socket = INVALID_SOCKET; -} - -FuzzedSock& FuzzedSock::operator=(Sock&& other) -{ - assert(false && "Move of Sock into FuzzedSock not allowed."); - return *this; -} - -ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const -{ - constexpr std::array send_errnos{ - EACCES, - EAGAIN, - EALREADY, - EBADF, - ECONNRESET, - EDESTADDRREQ, - EFAULT, - EINTR, - EINVAL, - EISCONN, - EMSGSIZE, - ENOBUFS, - ENOMEM, - ENOTCONN, - ENOTSOCK, - EOPNOTSUPP, - EPIPE, - EWOULDBLOCK, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - return len; - } - const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len); - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); - } - return r; -} - -ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const -{ - // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() - // returning -1 and setting errno to EAGAIN repeatedly. - constexpr std::array recv_errnos{ - ECONNREFUSED, - EAGAIN, - EBADF, - EFAULT, - EINTR, - EINVAL, - ENOMEM, - ENOTCONN, - ENOTSOCK, - EWOULDBLOCK, - }; - assert(buf != nullptr || len == 0); - if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; - } - std::vector<uint8_t> random_bytes; - bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; - if (m_peek_data.has_value()) { - // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. - random_bytes.assign({m_peek_data.value()}); - if ((flags & MSG_PEEK) == 0) { - m_peek_data.reset(); - } - pad_to_len_bytes = false; - } else if ((flags & MSG_PEEK) != 0) { - // New call with `MSG_PEEK`. - random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); - if (!random_bytes.empty()) { - m_peek_data = random_bytes[0]; - pad_to_len_bytes = false; - } - } else { - random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( - m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); - } - if (random_bytes.empty()) { - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - if (r == -1) { - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); - } - return r; - } - std::memcpy(buf, random_bytes.data(), random_bytes.size()); - if (pad_to_len_bytes) { - if (len > random_bytes.size()) { - std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); - } - return len; - } - if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { - std::this_thread::sleep_for(std::chrono::milliseconds{2}); - } - return random_bytes.size(); -} - -int FuzzedSock::Connect(const sockaddr*, socklen_t) const -{ - // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() - // returning -1 and setting errno to EAGAIN repeatedly. - constexpr std::array connect_errnos{ - ECONNREFUSED, - EAGAIN, - ECONNRESET, - EHOSTUNREACH, - EINPROGRESS, - EINTR, - ENETUNREACH, - ETIMEDOUT, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); - return -1; - } - return 0; -} - -int FuzzedSock::Bind(const sockaddr*, socklen_t) const -{ - // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to - // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) - // repeatedly because proper code should retry on temporary errors, leading to an - // infinite loop. - constexpr std::array bind_errnos{ - EACCES, - EADDRINUSE, - EADDRNOTAVAIL, - EAGAIN, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos); - return -1; - } - return 0; -} - -int FuzzedSock::Listen(int) const -{ - // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted - // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to - // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) - // repeatedly because proper code should retry on temporary errors, leading to an - // infinite loop. - constexpr std::array listen_errnos{ - EADDRINUSE, - EINVAL, - EOPNOTSUPP, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos); - return -1; - } - return 0; -} - -std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const -{ - constexpr std::array accept_errnos{ - ECONNABORTED, - EINTR, - ENOMEM, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos); - return std::unique_ptr<FuzzedSock>(); - } - return std::make_unique<FuzzedSock>(m_fuzzed_data_provider); -} - -int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const -{ - constexpr std::array getsockopt_errnos{ - ENOMEM, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); - return -1; - } - if (opt_val == nullptr) { - return 0; - } - std::memcpy(opt_val, - ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), - *opt_len); - return 0; -} - -int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const -{ - constexpr std::array setsockopt_errnos{ - ENOMEM, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos); - return -1; - } - return 0; -} - -int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const -{ - constexpr std::array getsockname_errnos{ - ECONNRESET, - ENOBUFS, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos); - return -1; - } - *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len); - return 0; -} - -bool FuzzedSock::SetNonBlocking() const -{ - constexpr std::array setnonblocking_errnos{ - EBADF, - EPERM, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos); - return false; - } - return true; -} - -bool FuzzedSock::IsSelectable() const -{ - return m_selectable; -} - -bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const -{ - constexpr std::array wait_errnos{ - EBADF, - EINTR, - EINVAL, - }; - if (m_fuzzed_data_provider.ConsumeBool()) { - SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos); - return false; - } - if (occurred != nullptr) { - *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0; - } - return true; -} - -bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const -{ - for (auto& [sock, events] : events_per_sock) { - (void)sock; - events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0; - } - return true; -} - -bool FuzzedSock::IsConnected(std::string& errmsg) const -{ - if (m_fuzzed_data_provider.ConsumeBool()) { - return true; - } - errmsg = "disconnected at random by the fuzzer"; - return false; -} - -void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept -{ - connman.Handshake(node, - /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(), - /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), - /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), - /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()), - /*relay_txs=*/fuzzed_data_provider.ConsumeBool()); -} - CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept { return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY)); @@ -508,11 +204,6 @@ bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) n return false; } -CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}}; -} - FILE* FuzzedFileProvider::open() { SetFuzzedErrNo(m_fuzzed_data_provider); diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index ecd6eead3f..af1d65cd38 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,9 +12,6 @@ #include <consensus/amount.h> #include <consensus/consensus.h> #include <merkleblock.h> -#include <net.h> -#include <netaddress.h> -#include <netbase.h> #include <primitives/transaction.h> #include <script/script.h> #include <script/standard.h> @@ -22,8 +19,6 @@ #include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> -#include <test/fuzz/util/net.h> -#include <test/util/net.h> #include <uint256.h> #include <version.h> @@ -37,65 +32,6 @@ class PeerManager; -class FuzzedSock : public Sock -{ - FuzzedDataProvider& m_fuzzed_data_provider; - - /** - * Data to return when `MSG_PEEK` is used as a `Recv()` flag. - * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next - * `Recv()` call we must return the same data, thus we remember it here. - */ - mutable std::optional<uint8_t> m_peek_data; - - /** - * Whether to pretend that the socket is select(2)-able. This is randomly set in the - * constructor. It should remain constant so that repeated calls to `IsSelectable()` - * return the same value. - */ - const bool m_selectable; - -public: - explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider); - - ~FuzzedSock() override; - - FuzzedSock& operator=(Sock&& other) override; - - ssize_t Send(const void* data, size_t len, int flags) const override; - - ssize_t Recv(void* buf, size_t len, int flags) const override; - - int Connect(const sockaddr*, socklen_t) const override; - - int Bind(const sockaddr*, socklen_t) const override; - - int Listen(int backlog) const override; - - std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override; - - int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; - - int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override; - - int GetSockName(sockaddr* name, socklen_t* name_len) const override; - - bool SetNonBlocking() const override; - - bool IsSelectable() const override; - - bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override; - - bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override; - - bool IsConnected(std::string& errmsg) const override; -}; - -[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider) -{ - return FuzzedSock{fuzzed_data_provider}; -} - template <typename... Callables> size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) { @@ -284,59 +220,6 @@ inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept return result; } -inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()}; -} - -inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; -} - -CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept; - -template <bool ReturnUniquePtr = false> -auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept -{ - const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max())); - const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider); - const CAddress address = ConsumeAddress(fuzzed_data_provider); - const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); - const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); - const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider); - const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64); - const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES); - const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false}; - NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS); - if constexpr (ReturnUniquePtr) { - return std::make_unique<CNode>(node_id, - sock, - address, - keyed_net_group, - local_host_nonce, - addr_bind, - addr_name, - conn_type, - inbound_onion, - CNodeOptions{ .permission_flags = permission_flags }); - } else { - return CNode{node_id, - sock, - address, - keyed_net_group, - local_host_nonce, - addr_bind, - addr_name, - conn_type, - inbound_onion, - CNodeOptions{ .permission_flags = permission_flags }}; - } -} -inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); } - -void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex); - class FuzzedFileProvider { FuzzedDataProvider& m_fuzzed_data_provider; diff --git a/src/test/fuzz/util/mempool.cpp b/src/test/fuzz/util/mempool.cpp index ac83f6ca21..4baca5ec77 100644 --- a/src/test/fuzz/util/mempool.cpp +++ b/src/test/fuzz/util/mempool.cpp @@ -3,12 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <consensus/amount.h> +#include <consensus/consensus.h> +#include <kernel/mempool_entry.h> #include <primitives/transaction.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/util.h> #include <test/fuzz/util/mempool.h> -#include <txmempool_entry.h> +#include <cassert> +#include <cstdint> #include <limits> CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept diff --git a/src/test/fuzz/util/mempool.h b/src/test/fuzz/util/mempool.h index 4304e5294e..31b578dc4b 100644 --- a/src/test/fuzz/util/mempool.h +++ b/src/test/fuzz/util/mempool.h @@ -5,11 +5,13 @@ #ifndef BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H #define BITCOIN_TEST_FUZZ_UTIL_MEMPOOL_H -#include <primitives/transaction.h> -#include <test/fuzz/FuzzedDataProvider.h> -#include <txmempool.h> +#include <kernel/mempool_entry.h> #include <validation.h> +class CTransaction; +class CTxMemPool; +class FuzzedDataProvider; + class DummyChainState final : public Chainstate { public: diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp index f8e996cfa5..65bc336297 100644 --- a/src/test/fuzz/util/net.cpp +++ b/src/test/fuzz/util/net.cpp @@ -1,15 +1,30 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 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 <test/fuzz/util/net.h> + #include <compat/compat.h> #include <netaddress.h> +#include <protocol.h> #include <test/fuzz/FuzzedDataProvider.h> -#include <util/strencodings.h> +#include <test/fuzz/util.h> +#include <test/util/net.h> +#include <util/sock.h> +#include <util/time.h> +#include <version.h> +#include <array> +#include <cassert> +#include <cerrno> #include <cstdint> +#include <cstdlib> +#include <cstring> +#include <thread> #include <vector> +class CNode; + CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept { const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION}); @@ -34,3 +49,310 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept } return net_addr; } + +CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}}; +} + +FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) + : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()} +{ + m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET); +} + +FuzzedSock::~FuzzedSock() +{ + // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call + // close(m_socket) if m_socket is not INVALID_SOCKET. + // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which + // theoretically may concide with a real opened file descriptor). + m_socket = INVALID_SOCKET; +} + +FuzzedSock& FuzzedSock::operator=(Sock&& other) +{ + assert(false && "Move of Sock into FuzzedSock not allowed."); + return *this; +} + +ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const +{ + constexpr std::array send_errnos{ + EACCES, + EAGAIN, + EALREADY, + EBADF, + ECONNRESET, + EDESTADDRREQ, + EFAULT, + EINTR, + EINVAL, + EISCONN, + EMSGSIZE, + ENOBUFS, + ENOMEM, + ENOTCONN, + ENOTSOCK, + EOPNOTSUPP, + EPIPE, + EWOULDBLOCK, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + return len; + } + const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len); + if (r == -1) { + SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); + } + return r; +} + +ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const +{ + // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() + // returning -1 and setting errno to EAGAIN repeatedly. + constexpr std::array recv_errnos{ + ECONNREFUSED, + EAGAIN, + EBADF, + EFAULT, + EINTR, + EINVAL, + ENOMEM, + ENOTCONN, + ENOTSOCK, + EWOULDBLOCK, + }; + assert(buf != nullptr || len == 0); + if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { + const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; + if (r == -1) { + SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); + } + return r; + } + std::vector<uint8_t> random_bytes; + bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; + if (m_peek_data.has_value()) { + // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. + random_bytes.assign({m_peek_data.value()}); + if ((flags & MSG_PEEK) == 0) { + m_peek_data.reset(); + } + pad_to_len_bytes = false; + } else if ((flags & MSG_PEEK) != 0) { + // New call with `MSG_PEEK`. + random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); + if (!random_bytes.empty()) { + m_peek_data = random_bytes[0]; + pad_to_len_bytes = false; + } + } else { + random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( + m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); + } + if (random_bytes.empty()) { + const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; + if (r == -1) { + SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); + } + return r; + } + std::memcpy(buf, random_bytes.data(), random_bytes.size()); + if (pad_to_len_bytes) { + if (len > random_bytes.size()) { + std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); + } + return len; + } + if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { + std::this_thread::sleep_for(std::chrono::milliseconds{2}); + } + return random_bytes.size(); +} + +int FuzzedSock::Connect(const sockaddr*, socklen_t) const +{ + // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() + // returning -1 and setting errno to EAGAIN repeatedly. + constexpr std::array connect_errnos{ + ECONNREFUSED, + EAGAIN, + ECONNRESET, + EHOSTUNREACH, + EINPROGRESS, + EINTR, + ENETUNREACH, + ETIMEDOUT, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); + return -1; + } + return 0; +} + +int FuzzedSock::Bind(const sockaddr*, socklen_t) const +{ + // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to + // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) + // repeatedly because proper code should retry on temporary errors, leading to an + // infinite loop. + constexpr std::array bind_errnos{ + EACCES, + EADDRINUSE, + EADDRNOTAVAIL, + EAGAIN, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos); + return -1; + } + return 0; +} + +int FuzzedSock::Listen(int) const +{ + // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to + // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) + // repeatedly because proper code should retry on temporary errors, leading to an + // infinite loop. + constexpr std::array listen_errnos{ + EADDRINUSE, + EINVAL, + EOPNOTSUPP, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos); + return -1; + } + return 0; +} + +std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const +{ + constexpr std::array accept_errnos{ + ECONNABORTED, + EINTR, + ENOMEM, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos); + return std::unique_ptr<FuzzedSock>(); + } + return std::make_unique<FuzzedSock>(m_fuzzed_data_provider); +} + +int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const +{ + constexpr std::array getsockopt_errnos{ + ENOMEM, + ENOBUFS, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); + return -1; + } + if (opt_val == nullptr) { + return 0; + } + std::memcpy(opt_val, + ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), + *opt_len); + return 0; +} + +int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const +{ + constexpr std::array setsockopt_errnos{ + ENOMEM, + ENOBUFS, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos); + return -1; + } + return 0; +} + +int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const +{ + constexpr std::array getsockname_errnos{ + ECONNRESET, + ENOBUFS, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos); + return -1; + } + *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len); + return 0; +} + +bool FuzzedSock::SetNonBlocking() const +{ + constexpr std::array setnonblocking_errnos{ + EBADF, + EPERM, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos); + return false; + } + return true; +} + +bool FuzzedSock::IsSelectable() const +{ + return m_selectable; +} + +bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const +{ + constexpr std::array wait_errnos{ + EBADF, + EINTR, + EINVAL, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos); + return false; + } + if (occurred != nullptr) { + *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0; + } + return true; +} + +bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const +{ + for (auto& [sock, events] : events_per_sock) { + (void)sock; + events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0; + } + return true; +} + +bool FuzzedSock::IsConnected(std::string& errmsg) const +{ + if (m_fuzzed_data_provider.ConsumeBool()) { + return true; + } + errmsg = "disconnected at random by the fuzzer"; + return false; +} + +void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept +{ + connman.Handshake(node, + /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(), + /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), + /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), + /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()), + /*relay_txs=*/fuzzed_data_provider.ConsumeBool()); +} diff --git a/src/test/fuzz/util/net.h b/src/test/fuzz/util/net.h index d81adab650..47e4a2fac0 100644 --- a/src/test/fuzz/util/net.h +++ b/src/test/fuzz/util/net.h @@ -1,14 +1,141 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 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_TEST_FUZZ_UTIL_NET_H #define BITCOIN_TEST_FUZZ_UTIL_NET_H +#include <net.h> +#include <net_permissions.h> #include <netaddress.h> +#include <node/connection_types.h> +#include <node/eviction.h> +#include <protocol.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/util.h> +#include <test/util/net.h> +#include <threadsafety.h> +#include <util/sock.h> -class FuzzedDataProvider; +#include <chrono> +#include <cstdint> +#include <limits> +#include <memory> +#include <optional> +#include <string> CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept; +class FuzzedSock : public Sock +{ + FuzzedDataProvider& m_fuzzed_data_provider; + + /** + * Data to return when `MSG_PEEK` is used as a `Recv()` flag. + * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next + * `Recv()` call we must return the same data, thus we remember it here. + */ + mutable std::optional<uint8_t> m_peek_data; + + /** + * Whether to pretend that the socket is select(2)-able. This is randomly set in the + * constructor. It should remain constant so that repeated calls to `IsSelectable()` + * return the same value. + */ + const bool m_selectable; + +public: + explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider); + + ~FuzzedSock() override; + + FuzzedSock& operator=(Sock&& other) override; + + ssize_t Send(const void* data, size_t len, int flags) const override; + + ssize_t Recv(void* buf, size_t len, int flags) const override; + + int Connect(const sockaddr*, socklen_t) const override; + + int Bind(const sockaddr*, socklen_t) const override; + + int Listen(int backlog) const override; + + std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override; + + int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; + + int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override; + + int GetSockName(sockaddr* name, socklen_t* name_len) const override; + + bool SetNonBlocking() const override; + + bool IsSelectable() const override; + + bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override; + + bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override; + + bool IsConnected(std::string& errmsg) const override; +}; + +[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider) +{ + return FuzzedSock{fuzzed_data_provider}; +} + +inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()}; +} + +inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; +} + +CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept; + +template <bool ReturnUniquePtr = false> +auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept +{ + const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max())); + const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider); + const CAddress address = ConsumeAddress(fuzzed_data_provider); + const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); + const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); + const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider); + const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64); + const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES); + const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false}; + NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS); + if constexpr (ReturnUniquePtr) { + return std::make_unique<CNode>(node_id, + sock, + address, + keyed_net_group, + local_host_nonce, + addr_bind, + addr_name, + conn_type, + inbound_onion, + CNodeOptions{ .permission_flags = permission_flags }); + } else { + return CNode{node_id, + sock, + address, + keyed_net_group, + local_host_nonce, + addr_bind, + addr_name, + conn_type, + inbound_onion, + CNodeOptions{ .permission_flags = permission_flags }}; + } +} +inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); } + +void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex); + #endif // BITCOIN_TEST_FUZZ_UTIL_NET_H diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 8abb943266..7119643b45 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp index 9a90de8911..817593cf6e 100644 --- a/src/test/fuzz/validation_load_mempool.cpp +++ b/src/test/fuzz/validation_load_mempool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp index 95eb71099d..143027662f 100644 --- a/src/test/fuzz/versionbits.cpp +++ b/src/test/fuzz/versionbits.cpp @@ -55,7 +55,7 @@ public: bool Condition(int32_t version) const { - uint32_t mask = ((uint32_t)1) << m_bit; + uint32_t mask = (uint32_t{1}) << m_bit; return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0); } diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 3643b80d5f..9c2d8a4dad 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp index 9da1ee11f9..3e20b527b5 100644 --- a/src/test/i2p_tests.cpp +++ b/src/test/i2p_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,8 +8,8 @@ #include <test/util/logging.h> #include <test/util/net.h> #include <test/util/setup_common.h> -#include <threadinterrupt.h> #include <util/system.h> +#include <util/threadinterrupt.h> #include <boost/test/unit_test.hpp> diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp index cb901b2259..d37fe35a11 100644 --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index 1eac68de14..fb0a07934d 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 8cb0515a8a..21ed2f1080 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp index a6f3a62c71..022e33f99d 100644 --- a/src/test/logging_tests.cpp +++ b/src/test/logging_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/main.cpp b/src/test/main.cpp index 73bb331e21..0809f83c93 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 393311e4e4..94e553a304 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) CTxMemPool& testPool = *Assert(m_node.mempool); - LOCK2(cs_main, testPool.cs); + LOCK2(::cs_main, testPool.cs); // Nothing in pool, remove should do nothing: unsigned int poolSize = testPool.size(); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx5.vout.resize(1); tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; - entry.nTime = 1; + entry.time = NodeSeconds{1s}; pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5U); @@ -202,10 +202,9 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx7.vout[1].nValue = 1 * COIN; - CTxMemPool::setEntries setAncestorsCalculated; - std::string dummy; - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2'000'000LL).FromTx(tx7), setAncestorsCalculated, CTxMemPool::Limits::NoLimits(), dummy), true); - BOOST_CHECK(setAncestorsCalculated == setAncestors); + auto ancestors_calculated{pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), CTxMemPool::Limits::NoLimits())}; + BOOST_REQUIRE(ancestors_calculated.has_value()); + BOOST_CHECK(*ancestors_calculated == setAncestors); pool.addUnchecked(entry.FromTx(tx7), setAncestors); BOOST_CHECK_EQUAL(pool.size(), 7U); @@ -225,7 +224,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx8.vout[0].nValue = 10 * COIN; setAncestors.insert(pool.mapTx.find(tx7.GetHash())); - pool.addUnchecked(entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); + pool.addUnchecked(entry.Fee(0LL).Time(NodeSeconds{2s}).FromTx(tx8), setAncestors); // Now tx8 should be sorted low, but tx6/tx both high sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); @@ -239,7 +238,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx9.vout.resize(1); tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx9.vout[0].nValue = 1 * COIN; - pool.addUnchecked(entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); + pool.addUnchecked(entry.Fee(0LL).Time(NodeSeconds{3s}).FromTx(tx9), setAncestors); // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9U); @@ -261,9 +260,9 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx10.vout[0].nValue = 10 * COIN; - setAncestorsCalculated.clear(); - BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200'000LL).Time(4).FromTx(tx10), setAncestorsCalculated, CTxMemPool::Limits::NoLimits(), dummy), true); - BOOST_CHECK(setAncestorsCalculated == setAncestors); + ancestors_calculated = pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(NodeSeconds{4s}).FromTx(tx10), CTxMemPool::Limits::NoLimits()); + BOOST_REQUIRE(ancestors_calculated); + BOOST_CHECK(*ancestors_calculated == setAncestors); pool.addUnchecked(entry.FromTx(tx10), setAncestors); diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 942d54ede8..bba103d1b0 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -50,7 +50,7 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot // For each of the lower bits in count that are 0, do 1 step. Each // corresponds to an inner value that existed before processing the // current leaf, and each needs a hash to combine it. - for (level = 0; !(count & (((uint32_t)1) << level)); level++) { + for (level = 0; !(count & ((uint32_t{1}) << level)); level++) { if (pbranch) { if (matchh) { pbranch->push_back(inner[level]); @@ -74,12 +74,12 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot int level = 0; // As long as bit number level in count is zero, skip it. It means there // is nothing left at this level. - while (!(count & (((uint32_t)1) << level))) { + while (!(count & ((uint32_t{1}) << level))) { level++; } uint256 h = inner[level]; bool matchh = matchlevel == level; - while (count != (((uint32_t)1) << level)) { + while (count != ((uint32_t{1}) << level)) { // If we reach this point, h is an inner value that is not the top. // We combine it with itself (Bitcoin's special rule for odd levels in // the tree) to produce a higher level one. @@ -89,10 +89,10 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot CHash256().Write(h).Write(h).Finalize(h); // Increment count to the value it would have if two entries at this // level had existed. - count += (((uint32_t)1) << level); + count += ((uint32_t{1}) << level); level++; // And propagate the result upwards accordingly. - while (!(count & (((uint32_t)1) << level))) { + while (!(count & ((uint32_t{1}) << level))) { if (pbranch) { if (matchh) { pbranch->push_back(inner[level]); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 9bc29e3599..e766a55673 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -87,11 +87,11 @@ constexpr static struct { {0, 792342903}, {6, 678455063}, {6, 773251385}, {5, 186617471}, {6, 883189502}, {7, 396077336}, {8, 254702874}, {0, 455592851}}; -static CBlockIndex CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static std::unique_ptr<CBlockIndex> CreateBlockIndex(int nHeight, CBlockIndex* active_chain_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - CBlockIndex index; - index.nHeight = nHeight; - index.pprev = active_chain_tip; + auto index{std::make_unique<CBlockIndex>()}; + index->nHeight = nHeight; + index->pprev = active_chain_tip; return index; } @@ -116,19 +116,19 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee uint256 hashHighFeeTx = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U); @@ -239,7 +239,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } @@ -257,7 +257,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); @@ -281,7 +281,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); @@ -293,7 +293,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: // orphan in tx_mempool, template creation fails hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); } @@ -306,7 +306,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -314,7 +314,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vin[1].prevout.n = 0; tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); } @@ -329,7 +329,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].nValue = 0; hash = tx.GetHash(); // give it a fee so it'll get mined - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); // Should throw bad-cb-multiple BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); } @@ -344,10 +344,10 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); } @@ -390,12 +390,12 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: CScript script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end()); tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); // Should throw block-validation-failed BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); @@ -432,13 +432,13 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail { CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip(); - BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 2, active_chain_tip))); // Sequence locks pass on 2nd block + BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, *CreateBlockIndex(active_chain_tip->nHeight + 2, active_chain_tip))); // Sequence locks pass on 2nd block } // relative time locked @@ -446,7 +446,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1-m_node.chainman->ActiveChain()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block prevheights[0] = baseheight + 2; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Time(Now<NodeSeconds>()).FromTx(tx)); BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail @@ -455,7 +455,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += SEQUENCE_LOCK_TIME; // Trick the MedianTimePast { CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip(); - BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip))); + BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, *CreateBlockIndex(active_chain_tip->nHeight + 1, active_chain_tip))); } for (int i = 0; i < CBlockIndex::nMedianTimeSpan; ++i) { @@ -469,7 +469,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: prevheights[0] = baseheight + 3; tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Time(Now<NodeSeconds>()).FromTx(tx)); BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block @@ -480,7 +480,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetHash(); - tx_mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); + tx_mempool.addUnchecked(entry.Time(Now<NodeSeconds>()).FromTx(tx)); BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later @@ -535,7 +535,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const tx.vout.resize(1); tx.vout[0].nValue = 5000000000LL; // 0 fee uint256 hashFreePrioritisedTx = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(0).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN); tx.vin[0].prevout.hash = txFirst[1]->GetHash(); @@ -543,20 +543,20 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[2]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); tx_mempool.PrioritiseTransaction(hashMediumFeeTx, -5 * COIN); // This tx also has a low fee, but is prioritised tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee uint256 hashPrioritsedChild = tx.GetHash(); - tx_mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); tx_mempool.PrioritiseTransaction(hashPrioritsedChild, 2 * COIN); // Test that transaction selection properly updates ancestor fee calculations as prioritised diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 9387c01e73..3181c9cf28 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp index 81f2aad623..59c0aab053 100644 --- a/src/test/minisketch_tests.cpp +++ b/src/test/minisketch_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index ce23d6013d..1e1a9932ad 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp index d519a4442f..51d6c4384a 100644 --- a/src/test/net_peer_eviction_tests.cpp +++ b/src/test/net_peer_eviction_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index f24509dd97..5a97e9429a 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 0e1e9ae211..cef42b7dd8 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp index 842daa8bd4..a55b0bbcd0 100644 --- a/src/test/orphanage_tests.cpp +++ b/src/test/orphanage_tests.cpp @@ -20,13 +20,15 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup) class TxOrphanageTest : public TxOrphanage { public: - inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans) + inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { + LOCK(m_mutex); return m_orphans.size(); } - CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans) + CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { + LOCK(m_mutex); std::map<uint256, OrphanTx>::iterator it; it = m_orphans.lower_bound(InsecureRand256()); if (it == m_orphans.end()) @@ -59,8 +61,6 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) FillableSigningProvider keystore; BOOST_CHECK(keystore.AddKey(key)); - LOCK(g_cs_orphans); - // 50 orphan transactions: for (int i = 0; i < 50; i++) { diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 3cbbec92d6..d6aee472a8 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index b652dc44c0..75ba9972f6 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique uint256 hash = tx.GetHash(); - mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx)); txHashes[j].push_back(hash); } } @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx)); txHashes[j].push_back(hash); } } @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx)); CTransactionRef ptx = mpool.get(hash); if (ptx) block.push_back(ptx); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 3695ea9d16..7cd12ede0a 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index 3977a3d548..4068775cfa 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp index d4487cd941..ada61029ee 100644 --- a/src/test/raii_event_tests.cpp +++ b/src/test/raii_event_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 96fb28dc9f..e5cf767614 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -94,14 +94,14 @@ BOOST_AUTO_TEST_CASE(fastrandom_randbits) for (int j = 0; j < 1000; ++j) { uint64_t rangebits = ctx1.randbits(bits); BOOST_CHECK_EQUAL(rangebits >> bits, 0U); - uint64_t range = ((uint64_t)1) << bits | rangebits; + uint64_t range = (uint64_t{1}) << bits | rangebits; uint64_t rand = ctx2.randrange(range); BOOST_CHECK(rand < range); } } } -/** Does-it-compile test for compatibility with standard C++11 RNG interface. */ +/** Does-it-compile test for compatibility with standard library RNG interface. */ BOOST_AUTO_TEST_CASE(stdrandom_test) { FastRandomContext ctx; diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp index d362c85560..0ec253747b 100644 --- a/src/test/rbf_tests.cpp +++ b/src/test/rbf_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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 <policy/rbf.h> diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index a52530e179..d807c7cda2 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,12 +17,49 @@ #include <boost/test/unit_test.hpp> +static UniValue JSON(std::string_view json) +{ + UniValue value; + BOOST_CHECK(value.read(json.data(), json.size())); + return value; +} + +class HasJSON +{ +public: + explicit HasJSON(std::string json) : m_json(std::move(json)) {} + bool operator()(const UniValue& value) const + { + std::string json{value.write()}; + BOOST_CHECK_EQUAL(json, m_json); + return json == m_json; + }; + +private: + const std::string m_json; +}; + class RPCTestingSetup : public TestingSetup { public: + UniValue TransformParams(const UniValue& params, std::vector<std::string> arg_names) const; UniValue CallRPC(std::string args); }; +UniValue RPCTestingSetup::TransformParams(const UniValue& params, std::vector<std::string> arg_names) const +{ + UniValue transformed_params; + CRPCTable table; + CRPCCommand command{"category", "method", [&](const JSONRPCRequest& request, UniValue&, bool) -> bool { transformed_params = request.params; return true; }, arg_names, /*unique_id=*/0}; + table.appendCommand("method", &command); + JSONRPCRequest request; + request.strMethod = "method"; + request.params = params; + if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished(); + table.execute(request); + return transformed_params; +} + UniValue RPCTestingSetup::CallRPC(std::string args) { std::vector<std::string> vArgs{SplitString(args, ' ')}; @@ -45,6 +82,33 @@ UniValue RPCTestingSetup::CallRPC(std::string args) BOOST_FIXTURE_TEST_SUITE(rpc_tests, RPCTestingSetup) +BOOST_AUTO_TEST_CASE(rpc_namedparams) +{ + const std::vector<std::string> arg_names{"arg1", "arg2", "arg3", "arg4", "arg5"}; + + // Make sure named arguments are transformed into positional arguments in correct places separated by nulls + BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg4": 4})"), arg_names).write(), "[null,2,null,4]"); + + // Make sure named argument specified multiple times raises an exception + BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg2": 2, "arg2": 4})"), arg_names), UniValue, + HasJSON(R"({"code":-8,"message":"Parameter arg2 specified multiple times"})")); + + // Make sure named and positional arguments can be combined. + BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg5": 5, "args": [1, 2], "arg4": 4})"), arg_names).write(), "[1,2,null,4,5]"); + + // Make sure a unknown named argument raises an exception + BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg2": 2, "unknown": 6})"), arg_names), UniValue, + HasJSON(R"({"code":-8,"message":"Unknown named parameter unknown"})")); + + // Make sure an overlap between a named argument and positional argument raises an exception + BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"args": [1,2,3], "arg4": 4, "arg2": 2})"), arg_names), UniValue, + HasJSON(R"({"code":-8,"message":"Parameter arg2 specified twice both as positional and named argument"})")); + + // Make sure extra positional arguments can be passed through to the method implementation, as long as they don't overlap with named arguments. + BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"args": [1,2,3,4,5,6,7,8,9,10]})"), arg_names).write(), "[1,2,3,4,5,6,7,8,9,10]"); + BOOST_CHECK_EQUAL(TransformParams(JSON(R"([1,2,3,4,5,6,7,8,9,10])"), arg_names).write(), "[1,2,3,4,5,6,7,8,9,10]"); +} + BOOST_AUTO_TEST_CASE(rpc_rawparams) { // Test raw transaction API argument handling diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 907a3fd15b..451bc99d44 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 7b5dda8114..1301a1b219 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index a02d51eecc..e439ff3519 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 13a1f0f9eb..7bebadf224 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index e74678394f..300760282b 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 8c7c650cb1..c90ae38ae8 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -123,17 +123,17 @@ BOOST_AUTO_TEST_CASE(varints_bitpatterns) CDataStream ss(SER_DISK, 0); ss << VARINT_MODE(0, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "00"); ss.clear(); ss << VARINT_MODE(0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear(); - ss << VARINT_MODE((int8_t)0x7f, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear(); + ss << VARINT_MODE(int8_t{0x7f}, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "7f"); ss.clear(); ss << VARINT_MODE(0x80, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear(); - ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear(); + ss << VARINT(uint8_t{0x80}); BOOST_CHECK_EQUAL(HexStr(ss), "8000"); ss.clear(); ss << VARINT_MODE(0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear(); - ss << VARINT_MODE((int16_t)0x1234, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear(); + ss << VARINT_MODE(int16_t{0x1234}, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "a334"); ss.clear(); ss << VARINT_MODE(0xffff, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear(); - ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear(); + ss << VARINT(uint16_t{0xffff}); BOOST_CHECK_EQUAL(HexStr(ss), "82fe7f"); ss.clear(); ss << VARINT_MODE(0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear(); - ss << VARINT_MODE((int32_t)0x123456, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear(); + ss << VARINT_MODE(int32_t{0x123456}, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "c7e756"); ss.clear(); ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear(); - ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear(); + ss << VARINT(uint32_t{0x80123456U}); BOOST_CHECK_EQUAL(HexStr(ss), "86ffc7e756"); ss.clear(); ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), "8efefefe7f"); ss.clear(); ss << VARINT_MODE(0x7fffffffffffffffLL, VarIntMode::NONNEGATIVE_SIGNED); BOOST_CHECK_EQUAL(HexStr(ss), "fefefefefefefefe7f"); ss.clear(); ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), "80fefefefefefefefe7f"); ss.clear(); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 514798d8fa..1ce694b8c6 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2021 The Bitcoin Core developers +// Copyright (c) 2013-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index d78f62972f..a17be54419 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 9f5e3ab7ae..ae9021df58 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp index 8376ec1a68..9e6f73745e 100644 --- a/src/test/sock_tests.cpp +++ b/src/test/sock_tests.cpp @@ -1,12 +1,12 @@ -// Copyright (c) 2021-2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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 <compat/compat.h> #include <test/util/setup_common.h> -#include <threadinterrupt.h> #include <util/sock.h> #include <util/system.h> +#include <util/threadinterrupt.h> #include <boost/test/unit_test.hpp> diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index b1b262eade..03117f76ae 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -144,10 +144,10 @@ BOOST_AUTO_TEST_CASE(bitstream_reader_writer) CDataStream data_copy(data); uint32_t serialized_int1; data >> serialized_int1; - BOOST_CHECK_EQUAL(serialized_int1, (uint32_t)0x7700C35A); // NOTE: Serialized as LE + BOOST_CHECK_EQUAL(serialized_int1, uint32_t{0x7700C35A}); // NOTE: Serialized as LE uint16_t serialized_int2; data >> serialized_int2; - BOOST_CHECK_EQUAL(serialized_int2, (uint16_t)0x1072); // NOTE: Serialized as LE + BOOST_CHECK_EQUAL(serialized_int2, uint16_t{0x1072}); // NOTE: Serialized as LE BitStreamReader<CDataStream> bit_reader(data_copy); BOOST_CHECK_EQUAL(bit_reader.Read(1), 0U); @@ -500,4 +500,18 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) fs::remove(streams_test_filename); } +BOOST_AUTO_TEST_CASE(streams_hashed) +{ + CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); + HashedSourceWriter hash_writer{stream}; + const std::string data{"bitcoin"}; + hash_writer << data; + + CHashVerifier hash_verifier{&stream}; + std::string result; + hash_verifier >> result; + BOOST_CHECK_EQUAL(data, result); + BOOST_CHECK_EQUAL(hash_writer.GetHash(), hash_verifier.GetHash()); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp index 55c2c5108d..0576bf1633 100644 --- a/src/test/sync_tests.cpp +++ b/src/test/sync_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -107,12 +107,12 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected) #ifdef DEBUG_LOCKORDER BOOST_AUTO_TEST_CASE(double_lock_mutex) { - TestDoubleLock<Mutex>(true /* should throw */); + TestDoubleLock<Mutex>(/*should_throw=*/true); } BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex) { - TestDoubleLock<RecursiveMutex>(false /* should not throw */); + TestDoubleLock<RecursiveMutex>(/*should_throw=*/false); } #endif /* DEBUG_LOCKORDER */ diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index d5b65b9c08..f2dc6ee739 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(run_command) BOOST_CHECK(result.isObject()); const UniValue& success = find_value(result, "success"); BOOST_CHECK(!success.isNull()); - BOOST_CHECK_EQUAL(success.getBool(), true); + BOOST_CHECK_EQUAL(success.get_bool(), true); } { // An invalid command is handled by Boost @@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(run_command) BOOST_CHECK(result.isObject()); const UniValue& success = find_value(result, "success"); BOOST_CHECK(!success.isNull()); - BOOST_CHECK_EQUAL(success.getBool(), true); + BOOST_CHECK_EQUAL(success.get_bool(), true); } #endif } diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp index 478d61d5e2..2814dbf4c0 100644 --- a/src/test/timedata_tests.cpp +++ b/src/test/timedata_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 952598f745..69b03e07bf 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 643d9221fe..b9bfa65c0a 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp index 079b753304..e438867d15 100644 --- a/src/test/txpackage_tests.cpp +++ b/src/test/txpackage_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -90,17 +90,21 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /*test_accept=*/true); BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(), "Package validation unexpectedly failed: " << result_parent_child.m_state.GetRejectReason()); + BOOST_CHECK(result_parent_child.m_tx_results.size() == 2); auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash()); auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash()); BOOST_CHECK(it_parent != result_parent_child.m_tx_results.end()); BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(), "Package validation unexpectedly failed: " << it_parent->second.m_state.GetRejectReason()); + BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == COIN); + BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1); + BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash()); BOOST_CHECK(it_child != result_parent_child.m_tx_results.end()); BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(), "Package validation unexpectedly failed: " << it_child->second.m_state.GetRejectReason()); - BOOST_CHECK(result_parent_child.m_package_feerate.has_value()); - BOOST_CHECK(result_parent_child.m_package_feerate.value() == - CFeeRate(2 * COIN, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child))); + BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == COIN); + BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1); + BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash()); // A single, giant transaction submitted through ProcessNewPackage fails on single tx policy. CTransactionRef giant_ptx = create_placeholder_tx(999, 999); @@ -109,10 +113,10 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) BOOST_CHECK(result_single_large.m_state.IsInvalid()); BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX); BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed"); + BOOST_CHECK(result_single_large.m_tx_results.size() == 1); auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash()); BOOST_CHECK(it_giant_tx != result_single_large.m_tx_results.end()); BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size"); - BOOST_CHECK(result_single_large.m_package_feerate == std::nullopt); // Check that mempool size hasn't changed. BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize); @@ -233,7 +237,6 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY); BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents"); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); - BOOST_CHECK(result_unrelated_submit.m_package_feerate == std::nullopt); // Parent and Child (and Grandchild) Package Package package_parent_child; @@ -275,7 +278,30 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY); BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents"); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); - BOOST_CHECK(result_3gen_submit.m_package_feerate == std::nullopt); + } + + // Parent and child package where transactions are invalid for reasons other than fee and + // missing inputs, so the package validation isn't expected to happen. + { + CScriptWitness bad_witness; + bad_witness.stack.push_back(std::vector<unsigned char>(1)); + CMutableTransaction mtx_parent_invalid{mtx_parent}; + mtx_parent_invalid.vin[0].scriptWitness = bad_witness; + CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid); + auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, + {tx_parent_invalid, tx_child}, /*test_accept=*/ false); + BOOST_CHECK(result_quit_early.m_state.IsInvalid()); + BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX); + BOOST_CHECK(!result_quit_early.m_tx_results.empty()); + BOOST_CHECK_EQUAL(result_quit_early.m_tx_results.size(), 2); + auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash()); + auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash()); + BOOST_CHECK(it_parent != result_quit_early.m_tx_results.end()); + BOOST_CHECK(it_child != result_quit_early.m_tx_results.end()); + BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED); + BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard"); + BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS); + BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent"); } // Child with missing parent. @@ -290,8 +316,6 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY); BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(), "package-not-child-with-unconfirmed-parents"); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); - - BOOST_CHECK(result_missing_parent.m_package_feerate == std::nullopt); } // Submit package with parent + child. @@ -301,20 +325,23 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) expected_pool_size += 2; BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size()); auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash()); auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash()); BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end()); BOOST_CHECK(it_parent->second.m_state.IsValid()); + BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent))); + BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1); + BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash()); BOOST_CHECK(it_child != submit_parent_child.m_tx_results.end()); BOOST_CHECK(it_child->second.m_state.IsValid()); + BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child))); + BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1); + BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash()); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash()))); BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash()))); - - // Since both transactions have high feerates, they each passed validation individually. - // Package validation was unnecessary, so there is no package feerate. - BOOST_CHECK(submit_parent_child.m_package_feerate == std::nullopt); } // Already-in-mempool transactions should be detected and de-duplicated. @@ -323,6 +350,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) package_parent_child, /*test_accept=*/false); BOOST_CHECK_MESSAGE(submit_deduped.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_deduped.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_deduped.m_tx_results.size(), package_parent_child.size()); auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash()); auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash()); BOOST_CHECK(it_parent_deduped != submit_deduped.m_tx_results.end()); @@ -335,8 +363,6 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent->GetHash()))); BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash()))); - - BOOST_CHECK(submit_deduped.m_package_feerate == std::nullopt); } } @@ -399,6 +425,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) {ptx_parent, ptx_child1}, /*test_accept=*/false); BOOST_CHECK_MESSAGE(submit_witness1.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_witness1.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_witness1.m_tx_results.size(), 2); auto it_parent1 = submit_witness1.m_tx_results.find(ptx_parent->GetWitnessHash()); auto it_child1 = submit_witness1.m_tx_results.find(ptx_child1->GetWitnessHash()); BOOST_CHECK(it_parent1 != submit_witness1.m_tx_results.end()); @@ -412,13 +439,11 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child1->GetHash()))); // Child2 would have been validated individually. - BOOST_CHECK(submit_witness1.m_package_feerate == std::nullopt); - const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {ptx_parent, ptx_child2}, /*test_accept=*/false); - BOOST_CHECK(submit_witness2.m_package_feerate == std::nullopt); BOOST_CHECK_MESSAGE(submit_witness2.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_witness2.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_witness2.m_tx_results.size(), 2); auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash()); auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash()); BOOST_CHECK(it_parent2_deduped != submit_witness2.m_tx_results.end()); @@ -436,11 +461,11 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) {ptx_parent, ptx_child1}, /*test_accept=*/false); BOOST_CHECK_MESSAGE(submit_segwit_dedup.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_segwit_dedup.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_segwit_dedup.m_tx_results.size(), 2); auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash()); auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash()); BOOST_CHECK(it_parent_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); BOOST_CHECK(it_child_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); - BOOST_CHECK(submit_witness2.m_package_feerate == std::nullopt); } // Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as @@ -465,6 +490,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) {ptx_child2, ptx_grandchild}, /*test_accept=*/false); BOOST_CHECK_MESSAGE(submit_spend_ignored.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_spend_ignored.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_spend_ignored.m_tx_results.size(), 2); auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash()); auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash()); BOOST_CHECK(it_child2_ignored != submit_spend_ignored.m_tx_results.end()); @@ -475,9 +501,6 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child2->GetHash()))); BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_child2->GetWitnessHash()))); BOOST_CHECK(m_node.mempool->exists(GenTxid::Wtxid(ptx_grandchild->GetWitnessHash()))); - - // Since child2 is ignored, grandchild would be validated individually. - BOOST_CHECK(submit_spend_ignored.m_package_feerate == std::nullopt); } // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of @@ -568,6 +591,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) { const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false); BOOST_CHECK_MESSAGE(mixed_result.m_state.IsValid(), mixed_result.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(mixed_result.m_tx_results.size(), package_mixed.size()); auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash()); auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash()); auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash()); @@ -590,11 +614,12 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_mixed_child->GetHash()))); // package feerate should include parent3 and child. It should not include parent1 or parent2_v1. - BOOST_CHECK(mixed_result.m_package_feerate.has_value()); const CFeeRate expected_feerate(1 * COIN, GetVirtualTransactionSize(*ptx_parent3) + GetVirtualTransactionSize(*ptx_mixed_child)); - BOOST_CHECK_MESSAGE(mixed_result.m_package_feerate.value() == expected_feerate, - strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(), - mixed_result.m_package_feerate.value().ToString())); + BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate); + BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate); + std::vector<uint256> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()}); + BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids); + BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids); } } @@ -638,16 +663,12 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_cpfp, /*test_accept=*/ false); + BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_POLICY); BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_state.IsInvalid(), "Package validation unexpectedly succeeded: " << submit_cpfp_deprio.m_state.GetRejectReason()); BOOST_CHECK(submit_cpfp_deprio.m_tx_results.empty()); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); const CFeeRate expected_feerate(0, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child)); - BOOST_CHECK(submit_cpfp_deprio.m_package_feerate.has_value()); - BOOST_CHECK(submit_cpfp_deprio.m_package_feerate.value() == CFeeRate{0}); - BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_package_feerate.value() == expected_feerate, - strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(), - submit_cpfp_deprio.m_package_feerate.value().ToString())); } // Clear the prioritisation of the parent transaction. @@ -662,6 +683,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) expected_pool_size += 2; BOOST_CHECK_MESSAGE(submit_cpfp.m_state.IsValid(), "Package validation unexpectedly failed: " << submit_cpfp.m_state.GetRejectReason()); + BOOST_CHECK_EQUAL(submit_cpfp.m_tx_results.size(), package_cpfp.size()); auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash()); auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash()); BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end()); @@ -677,11 +699,12 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) const CFeeRate expected_feerate(coinbase_value - child_value, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child)); + BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate); + BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate); + std::vector<uint256> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()}); + BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids); + BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids); BOOST_CHECK(expected_feerate.GetFeePerK() > 1000); - BOOST_CHECK(submit_cpfp.m_package_feerate.has_value()); - BOOST_CHECK_MESSAGE(submit_cpfp.m_package_feerate.value() == expected_feerate, - strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(), - submit_cpfp.m_package_feerate.value().ToString())); } // Just because we allow low-fee parents doesn't mean we allow low-feerate packages. @@ -716,10 +739,6 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) const CFeeRate expected_feerate(200, GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)); BOOST_CHECK(expected_feerate.GetFeePerK() < 1000); - BOOST_CHECK(submit_package_too_low.m_package_feerate.has_value()); - BOOST_CHECK_MESSAGE(submit_package_too_low.m_package_feerate.value() == expected_feerate, - strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(), - submit_package_too_low.m_package_feerate.value().ToString())); } // Package feerate includes the modified fees of the transactions. @@ -734,10 +753,20 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) "Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason()); const CFeeRate expected_feerate(1 * COIN + 200, GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)); - BOOST_CHECK(submit_prioritised_package.m_package_feerate.has_value()); - BOOST_CHECK_MESSAGE(submit_prioritised_package.m_package_feerate.value() == expected_feerate, - strprintf("Expected package feerate %s, got %s", expected_feerate.ToString(), - submit_prioritised_package.m_package_feerate.value().ToString())); + BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size()); + auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash()); + auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash()); + BOOST_CHECK(it_parent != submit_prioritised_package.m_tx_results.end()); + BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK(it_parent->second.m_base_fees.value() == 0); + BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate); + BOOST_CHECK(it_child != submit_prioritised_package.m_tx_results.end()); + BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK(it_child->second.m_base_fees.value() == 200); + BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate); + std::vector<uint256> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()}); + BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids); + BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids); } // Package feerate is calculated without topology in mind; it's just aggregating fees and sizes. @@ -770,10 +799,6 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) BOOST_CHECK_MESSAGE(submit_rich_parent.m_state.IsInvalid(), "Package validation unexpectedly succeeded"); // The child would have been validated on its own and failed, then submitted as a "package" of 1. - // The package feerate is just the child's feerate, which is 0sat/vb. - BOOST_CHECK(submit_rich_parent.m_package_feerate.has_value()); - BOOST_CHECK_MESSAGE(submit_rich_parent.m_package_feerate.value() == CFeeRate(), - "expected 0, got " << submit_rich_parent.m_package_feerate.value().ToString()); BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY); BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "package-fee-too-low"); @@ -783,6 +808,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) BOOST_CHECK(it_parent->second.m_state.GetRejectReason() == ""); BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee, strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value())); + BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich))); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent_rich->GetHash()))); diff --git a/src/test/txreconciliation_tests.cpp b/src/test/txreconciliation_tests.cpp index bd74998002..e258e3353d 100644 --- a/src/test/txreconciliation_tests.cpp +++ b/src/test/txreconciliation_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,56 +12,54 @@ BOOST_FIXTURE_TEST_SUITE(txreconciliation_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(RegisterPeerTest) { - TxReconciliationTracker tracker(1); + TxReconciliationTracker tracker(TXRECONCILIATION_VERSION); const uint64_t salt = 0; // Prepare a peer for reconciliation. tracker.PreRegisterPeer(0); - // Both roles are false, don't register. - BOOST_CHECK(tracker.RegisterPeer(/*peer_id=*/0, /*is_peer_inbound=*/true, - /*is_peer_recon_initiator=*/false, - /*is_peer_recon_responder=*/false, - /*peer_recon_version=*/1, salt) == - ReconciliationRegisterResult::PROTOCOL_VIOLATION); - - // Invalid roles for the given connection direction. - BOOST_CHECK(tracker.RegisterPeer(0, true, false, true, 1, salt) == ReconciliationRegisterResult::PROTOCOL_VIOLATION); - BOOST_CHECK(tracker.RegisterPeer(0, false, true, false, 1, salt) == ReconciliationRegisterResult::PROTOCOL_VIOLATION); - // Invalid version. - BOOST_CHECK(tracker.RegisterPeer(0, true, true, false, 0, salt) == ReconciliationRegisterResult::PROTOCOL_VIOLATION); + BOOST_CHECK_EQUAL(tracker.RegisterPeer(/*peer_id=*/0, /*is_peer_inbound=*/true, + /*peer_recon_version=*/0, salt), + ReconciliationRegisterResult::PROTOCOL_VIOLATION); - // Valid registration. + // Valid registration (inbound and outbound peers). BOOST_REQUIRE(!tracker.IsPeerRegistered(0)); - BOOST_REQUIRE(tracker.RegisterPeer(0, true, true, false, 1, salt) == ReconciliationRegisterResult::SUCCESS); + BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(0, true, 1, salt), ReconciliationRegisterResult::SUCCESS); BOOST_CHECK(tracker.IsPeerRegistered(0)); - - // Reconciliation version is higher than ours, should be able to register. BOOST_REQUIRE(!tracker.IsPeerRegistered(1)); tracker.PreRegisterPeer(1); - BOOST_REQUIRE(tracker.RegisterPeer(1, true, true, false, 2, salt) == ReconciliationRegisterResult::SUCCESS); + BOOST_REQUIRE(tracker.RegisterPeer(1, false, 1, salt) == ReconciliationRegisterResult::SUCCESS); BOOST_CHECK(tracker.IsPeerRegistered(1)); + // Reconciliation version is higher than ours, should be able to register. + BOOST_REQUIRE(!tracker.IsPeerRegistered(2)); + tracker.PreRegisterPeer(2); + BOOST_REQUIRE(tracker.RegisterPeer(2, true, 2, salt) == ReconciliationRegisterResult::SUCCESS); + BOOST_CHECK(tracker.IsPeerRegistered(2)); + + // Try registering for the second time. + BOOST_REQUIRE(tracker.RegisterPeer(1, false, 1, salt) == ReconciliationRegisterResult::ALREADY_REGISTERED); + // Do not register if there were no pre-registration for the peer. - BOOST_REQUIRE(tracker.RegisterPeer(100, true, true, false, 1, salt) == ReconciliationRegisterResult::NOT_FOUND); + BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(100, true, 1, salt), ReconciliationRegisterResult::NOT_FOUND); BOOST_CHECK(!tracker.IsPeerRegistered(100)); } BOOST_AUTO_TEST_CASE(ForgetPeerTest) { - TxReconciliationTracker tracker(1); + TxReconciliationTracker tracker(TXRECONCILIATION_VERSION); NodeId peer_id0 = 0; // Removing peer after pre-registring works and does not let to register the peer. tracker.PreRegisterPeer(peer_id0); tracker.ForgetPeer(peer_id0); - BOOST_CHECK(tracker.RegisterPeer(peer_id0, true, true, false, 1, 1) == ReconciliationRegisterResult::NOT_FOUND); + BOOST_CHECK_EQUAL(tracker.RegisterPeer(peer_id0, true, 1, 1), ReconciliationRegisterResult::NOT_FOUND); // Removing peer after it is registered works. tracker.PreRegisterPeer(peer_id0); BOOST_REQUIRE(!tracker.IsPeerRegistered(peer_id0)); - BOOST_REQUIRE(tracker.RegisterPeer(peer_id0, true, true, false, 1, 1) == ReconciliationRegisterResult::SUCCESS); + BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(peer_id0, true, 1, 1), ReconciliationRegisterResult::SUCCESS); BOOST_CHECK(tracker.IsPeerRegistered(peer_id0)); tracker.ForgetPeer(peer_id0); BOOST_CHECK(!tracker.IsPeerRegistered(peer_id0)); @@ -69,14 +67,14 @@ BOOST_AUTO_TEST_CASE(ForgetPeerTest) BOOST_AUTO_TEST_CASE(IsPeerRegisteredTest) { - TxReconciliationTracker tracker(1); + TxReconciliationTracker tracker(TXRECONCILIATION_VERSION); NodeId peer_id0 = 0; BOOST_REQUIRE(!tracker.IsPeerRegistered(peer_id0)); tracker.PreRegisterPeer(peer_id0); BOOST_REQUIRE(!tracker.IsPeerRegistered(peer_id0)); - BOOST_REQUIRE(tracker.RegisterPeer(peer_id0, true, true, false, 1, 1) == ReconciliationRegisterResult::SUCCESS); + BOOST_REQUIRE_EQUAL(tracker.RegisterPeer(peer_id0, true, 1, 1), ReconciliationRegisterResult::SUCCESS); BOOST_CHECK(tracker.IsPeerRegistered(peer_id0)); tracker.ForgetPeer(peer_id0); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 633f75ff4f..8cdea3890e 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -77,7 +77,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup) LOCK(cs_main); BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash()); } - m_node.mempool->clear(); + BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U); + WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[0]}, MemPoolRemovalReason::CONFLICT)); + BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); @@ -86,7 +88,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup) LOCK(cs_main); BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash()); } - m_node.mempool->clear(); + BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U); + WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[1]}, MemPoolRemovalReason::CONFLICT)); + BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U); // Final sanity test: first spend in *m_node.mempool, second in block, that's OK: std::vector<CMutableTransaction> oneSpend; @@ -113,7 +117,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup) // should fail. // Capture this interaction with the upgraded_nop argument: set it when evaluating // any script flag that is implemented as an upgraded NOP code. -static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { PrecomputedTransactionData txdata; diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h index 0ca63810f3..e664435e03 100644 --- a/src/test/util/chainstate.h +++ b/src/test/util/chainstate.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/test/util/logging.h b/src/test/util/logging.h index f477088392..73ac23825f 100644 --- a/src/test/util/logging.h +++ b/src/test/util/logging.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index faa0b2878c..0df1db84c4 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,7 +8,6 @@ #include <consensus/merkle.h> #include <key_io.h> #include <node/context.h> -#include <node/miner.h> #include <pow.h> #include <script/standard.h> #include <test/util/script.h> @@ -74,10 +73,11 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) return CTxIn{block->vtx[0]->GetHash(), 0}; } -std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) +std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey, + const BlockAssembler::Options& assembler_options) { auto block = std::make_shared<CBlock>( - BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get())} + BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options} .CreateNewBlock(coinbase_scriptPubKey) ->block); @@ -87,3 +87,9 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi return block; } +std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) +{ + BlockAssembler::Options assembler_options; + ApplyArgsManOptions(*node.args, assembler_options); + return PrepareBlock(node, coinbase_scriptPubKey, assembler_options); +} diff --git a/src/test/util/mining.h b/src/test/util/mining.h index 09e712cd35..70b1f7b3fb 100644 --- a/src/test/util/mining.h +++ b/src/test/util/mining.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_TEST_UTIL_MINING_H #define BITCOIN_TEST_UTIL_MINING_H +#include <node/miner.h> + #include <memory> #include <string> #include <vector> @@ -25,6 +27,8 @@ CTxIn MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey); /** Prepare a block to be mined */ std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey); +std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const CScript& coinbase_scriptPubKey, + const node::BlockAssembler::Options& assembler_options); /** RPC-like helper function, returns the generated coin */ CTxIn generatetoaddress(const node::NodeContext&, const std::string& address); diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp index 2e3e16e681..975aff13c0 100644 --- a/src/test/util/net.cpp +++ b/src/test/util/net.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/net.h b/src/test/util/net.h index 9ae7981980..90c606306f 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index a7ca97222a..1b28e5f2c0 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,6 +17,7 @@ #include <init.h> #include <init/common.h> #include <interfaces/chain.h> +#include <kernel/mempool_entry.h> #include <net.h> #include <net_processing.h> #include <node/blockstorage.h> @@ -41,7 +42,6 @@ #include <timedata.h> #include <txdb.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <util/strencodings.h> #include <util/string.h> #include <util/thread.h> @@ -321,7 +321,7 @@ CBlock TestChain100Setup::CreateAndProcessBlock( chainstate = &Assert(m_node.chainman)->ActiveChainstate(); } - const CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate); + CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate); std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block); Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, true, nullptr); @@ -397,15 +397,15 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex unspent_prevouts.pop_front(); } const size_t num_outputs = det_rand.randrange(24) + 1; - // Approximately 1000sat "fee," equal output amounts. - const CAmount amount_per_output = (total_in - 1000) / num_outputs; + const CAmount fee = 100 * det_rand.randrange(30); + const CAmount amount_per_output = (total_in - fee) / num_outputs; for (size_t n{0}; n < num_outputs; ++n) { CScript spk = CScript() << CScriptNum(num_transactions + n); mtx.vout.push_back(CTxOut(amount_per_output, spk)); } CTransactionRef ptx = MakeTransactionRef(mtx); mempool_transactions.push_back(ptx); - if (amount_per_output > 2000) { + if (amount_per_output > 3000) { // If the value is high enough to fund another transaction + fees, keep track of it so // it can be used to build a more complex transaction graph. Insert randomly into // unspent_prevouts for extra randomness in the resulting structures. @@ -415,9 +415,11 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex } } if (submit) { - LOCK2(m_node.mempool->cs, cs_main); + LOCK2(cs_main, m_node.mempool->cs); LockPoints lp; - m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, 1000, 0, 1, false, 4, lp)); + m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, /*fee=*/(total_in - num_outputs * amount_per_output), + /*time=*/0, /*entry_height=*/1, + /*spends_coinbase=*/false, /*sigops_cost=*/4, lp)); } --num_transactions; } diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index dfa36039a2..5f653d83ae 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp index 12cc1a4a3d..1873cf5ec8 100644 --- a/src/test/util/txmempool.cpp +++ b/src/test/util/txmempool.cpp @@ -34,6 +34,5 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) co CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) const { - return CTxMemPoolEntry(tx, nFee, nTime, nHeight, - spendsCoinbase, sigOpCost, lp); + return CTxMemPoolEntry{tx, nFee, TicksSinceEpoch<std::chrono::seconds>(time), nHeight, spendsCoinbase, sigOpCost, lp}; } diff --git a/src/test/util/txmempool.h b/src/test/util/txmempool.h index 70b9ed88db..2fe7d69693 100644 --- a/src/test/util/txmempool.h +++ b/src/test/util/txmempool.h @@ -6,6 +6,7 @@ #define BITCOIN_TEST_UTIL_TXMEMPOOL_H #include <txmempool.h> +#include <util/time.h> namespace node { struct NodeContext; @@ -13,11 +14,10 @@ struct NodeContext; CTxMemPool::Options MemPoolOptionsForTest(const node::NodeContext& node); -struct TestMemPoolEntryHelper -{ +struct TestMemPoolEntryHelper { // Default values CAmount nFee{0}; - int64_t nTime{0}; + NodeSeconds time{}; unsigned int nHeight{1}; bool spendsCoinbase{false}; unsigned int sigOpCost{4}; @@ -27,11 +27,11 @@ struct TestMemPoolEntryHelper CTxMemPoolEntry FromTx(const CTransactionRef& tx) const; // Change the default value - TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; } - TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; } - TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; } - TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; } - TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; } + TestMemPoolEntryHelper& Fee(CAmount _fee) { nFee = _fee; return *this; } + TestMemPoolEntryHelper& Time(NodeSeconds tp) { time = tp; return *this; } + TestMemPoolEntryHelper& Height(unsigned int _height) { nHeight = _height; return *this; } + TestMemPoolEntryHelper& SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; } + TestMemPoolEntryHelper& SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; } }; #endif // BITCOIN_TEST_UTIL_TXMEMPOOL_H diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp index 49535855f9..c0d7a532dc 100644 --- a/src/test/util/validation.cpp +++ b/src/test/util/validation.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/validation.h b/src/test/util/validation.h index cbe7745b81..7a511a2b79 100644 --- a/src/test/util/validation.h +++ b/src/test/util/validation.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp deleted file mode 100644 index 2dadffafb4..0000000000 --- a/src/test/util/wallet.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2019-2021 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 <test/util/wallet.h> - -#include <key_io.h> -#include <outputtype.h> -#include <script/standard.h> -#ifdef ENABLE_WALLET -#include <util/check.h> -#include <util/translation.h> -#include <wallet/wallet.h> -#endif - -using wallet::CWallet; - -const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj"; - -#ifdef ENABLE_WALLET -std::string getnewaddress(CWallet& w) -{ - constexpr auto output_type = OutputType::BECH32; - return EncodeDestination(getNewDestination(w, output_type)); -} - -CTxDestination getNewDestination(CWallet& w, OutputType output_type) -{ - return *Assert(w.GetNewDestination(output_type, "")); -} - -#endif // ENABLE_WALLET diff --git a/src/test/util/wallet.h b/src/test/util/wallet.h deleted file mode 100644 index d8f1db3fd7..0000000000 --- a/src/test/util/wallet.h +++ /dev/null @@ -1,29 +0,0 @@ -// 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_TEST_UTIL_WALLET_H -#define BITCOIN_TEST_UTIL_WALLET_H - -#include <outputtype.h> -#include <string> - -namespace wallet { -class CWallet; -} // namespace wallet - -// Constants // - -extern const std::string ADDRESS_BCRT1_UNSPENDABLE; - -// RPC-like // - -/** Import the address to the wallet */ -void importaddress(wallet::CWallet& wallet, const std::string& address); -/** Returns a new encoded destination from the wallet (hardcoded to BECH32) */ -std::string getnewaddress(wallet::CWallet& w); -/** Returns a new destination, of an specific type, from the wallet */ -CTxDestination getNewDestination(wallet::CWallet& w, OutputType output_type); - - -#endif // BITCOIN_TEST_UTIL_WALLET_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 602c848c2a..6b6bb18523 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -810,8 +810,8 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64) BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL); BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL); - BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807); - BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807-1); + BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == int64_t{9223372036854775807}); + BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == int64_t{-9223372036854775807-1}); BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL); // Invalid values BOOST_CHECK(!ParseInt64("", &n)); @@ -907,8 +907,8 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt32) BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234); BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647); - BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648); - BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295); + BOOST_CHECK(ParseUInt32("2147483648", &n) && n == uint32_t{2147483648}); + BOOST_CHECK(ParseUInt32("4294967295", &n) && n == uint32_t{4294967295}); BOOST_CHECK(ParseUInt32("+1234", &n) && n == 1234); BOOST_CHECK(ParseUInt32("00000000000000001234", &n) && n == 1234); BOOST_CHECK(ParseUInt32("00000000000000000000", &n) && n == 0); diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index bb1ade153a..823c9877ac 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index f868c0d4e6..c40481a95c 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) COutPoint outp{txid, 0}; newcoin.nHeight = 1; newcoin.out.nValue = InsecureRand32(); - newcoin.out.scriptPubKey.assign((uint32_t)56, 1); + newcoin.out.scriptPubKey.assign(uint32_t{56}, 1); coins_view.AddCoin(outp, std::move(newcoin), false); return outp; diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 22b9af1201..56867a584b 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) // Create a legacy (IBD) chainstate. // - Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); + Chainstate& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index c06e6c8d3b..f2ff570ca6 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) COutPoint outp{txid, 0}; newcoin.nHeight = 1; newcoin.out.nValue = InsecureRand32(); - newcoin.out.scriptPubKey.assign((uint32_t)56, 1); + newcoin.out.scriptPubKey.assign(uint32_t{56}, 1); coins_view.AddCoin(outp, std::move(newcoin), false); return outp; diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index e6203af4b4..4a42cec4af 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2021 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/timedata.cpp b/src/timedata.cpp index fe9a5fbed7..a0646b4707 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2021 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/timedata.h b/src/timedata.h index 669a571f47..c6c36d9a39 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/tinyformat.h b/src/tinyformat.h index bedaa14007..8eded00add 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -508,9 +508,9 @@ class FormatArg { public: FormatArg() - : m_value(NULL), - m_formatImpl(NULL), - m_toIntImpl(NULL) + : m_value(nullptr), + m_formatImpl(nullptr), + m_toIntImpl(nullptr) { } template<typename T> @@ -1005,7 +1005,8 @@ class FormatListN : public FormatList // Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard template<> class FormatListN<0> : public FormatList { - public: FormatListN() : FormatList(0, 0) {} +public: + FormatListN() : FormatList(nullptr, 0) {} }; } // namespace detail diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 3a21a79a34..b5f1fa7138 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/txdb.cpp b/src/txdb.cpp index bad3bb80a9..f04a4e9800 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/txdb.h b/src/txdb.h index 8c41e26f6a..5a409d7dcc 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +8,7 @@ #include <coins.h> #include <dbwrapper.h> +#include <kernel/cs_main.h> #include <sync.h> #include <fs.h> @@ -44,9 +45,6 @@ static const int64_t max_filter_index_cache = 1024; //! Max memory allocated to coin DB specific cache (MiB) static const int64_t nMaxCoinsDBCache = 8; -// Actually declared in validation.cpp; can't include because of circular dependency. -extern RecursiveMutex cs_main; - /** CCoinsView backed by the coin database (chainstate/) */ class CCoinsViewDB final : public CCoinsView { diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 12e2d5f224..aa04f8a4d0 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,12 +17,16 @@ #include <util/check.h> #include <util/moneystr.h> #include <util/overflow.h> +#include <util/result.h> #include <util/system.h> #include <util/time.h> +#include <util/translation.h> #include <validationinterface.h> #include <cmath> #include <optional> +#include <string_view> +#include <utility> bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) { @@ -147,32 +151,29 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes } } -bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, - size_t entry_count, - setEntries& setAncestors, - CTxMemPoolEntry::Parents& staged_ancestors, - const Limits& limits, - std::string &errString) const +util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateAncestorsAndCheckLimits( + size_t entry_size, + size_t entry_count, + CTxMemPoolEntry::Parents& staged_ancestors, + const Limits& limits) const { size_t totalSizeWithAncestors = entry_size; + setEntries ancestors; while (!staged_ancestors.empty()) { const CTxMemPoolEntry& stage = staged_ancestors.begin()->get(); txiter stageit = mapTx.iterator_to(stage); - setAncestors.insert(stageit); + ancestors.insert(stageit); staged_ancestors.erase(stage); totalSizeWithAncestors += stageit->GetTxSize(); if (stageit->GetSizeWithDescendants() + entry_size > static_cast<uint64_t>(limits.descendant_size_vbytes)) { - errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes); - return false; + return util::Error{Untranslated(strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_size_vbytes))}; } else if (stageit->GetCountWithDescendants() + entry_count > static_cast<uint64_t>(limits.descendant_count)) { - errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count); - return false; + return util::Error{Untranslated(strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limits.descendant_count))}; } else if (totalSizeWithAncestors > static_cast<uint64_t>(limits.ancestor_size_vbytes)) { - errString = strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes); - return false; + return util::Error{Untranslated(strprintf("exceeds ancestor size limit [limit: %u]", limits.ancestor_size_vbytes))}; } const CTxMemPoolEntry::Parents& parents = stageit->GetMemPoolParentsConst(); @@ -180,17 +181,16 @@ bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, txiter parent_it = mapTx.iterator_to(parent); // If this is a new ancestor, add it. - if (setAncestors.count(parent_it) == 0) { + if (ancestors.count(parent_it) == 0) { staged_ancestors.insert(parent); } - if (staged_ancestors.size() + setAncestors.size() + entry_count > static_cast<uint64_t>(limits.ancestor_count)) { - errString = strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count); - return false; + if (staged_ancestors.size() + ancestors.size() + entry_count > static_cast<uint64_t>(limits.ancestor_count)) { + return util::Error{Untranslated(strprintf("too many unconfirmed ancestors [limit: %u]", limits.ancestor_count))}; } } } - return true; + return ancestors; } bool CTxMemPool::CheckPackageLimits(const Package& package, @@ -215,20 +215,17 @@ bool CTxMemPool::CheckPackageLimits(const Package& package, // When multiple transactions are passed in, the ancestors and descendants of all transactions // considered together must be within limits even if they are not interdependent. This may be // stricter than the limits for each individual transaction. - setEntries setAncestors; - const auto ret = CalculateAncestorsAndCheckLimits(total_size, package.size(), - setAncestors, staged_ancestors, - limits, errString); + const auto ancestors{CalculateAncestorsAndCheckLimits(total_size, package.size(), + staged_ancestors, limits)}; // It's possible to overestimate the ancestor/descendant totals. - if (!ret) errString.insert(0, "possibly "); - return ret; + if (!ancestors.has_value()) errString = "possibly " + util::ErrorString(ancestors).original; + return ancestors.has_value(); } -bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, - setEntries &setAncestors, - const Limits& limits, - std::string &errString, - bool fSearchForParents /* = true */) const +util::Result<CTxMemPool::setEntries> CTxMemPool::CalculateMemPoolAncestors( + const CTxMemPoolEntry &entry, + const Limits& limits, + bool fSearchForParents /* = true */) const { CTxMemPoolEntry::Parents staged_ancestors; const CTransaction &tx = entry.GetTx(); @@ -242,8 +239,7 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, if (piter) { staged_ancestors.insert(**piter); if (staged_ancestors.size() + 1 > static_cast<uint64_t>(limits.ancestor_count)) { - errString = strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count); - return false; + return util::Error{Untranslated(strprintf("too many unconfirmed parents [limit: %u]", limits.ancestor_count))}; } } } @@ -254,9 +250,22 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, staged_ancestors = it->GetMemPoolParentsConst(); } - return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1, - setAncestors, staged_ancestors, - limits, errString); + return CalculateAncestorsAndCheckLimits(entry.GetTxSize(), /*entry_count=*/1, staged_ancestors, + limits); +} + +CTxMemPool::setEntries CTxMemPool::AssumeCalculateMemPoolAncestors( + std::string_view calling_fn_name, + const CTxMemPoolEntry &entry, + const Limits& limits, + bool fSearchForParents /* = true */) const +{ + auto result{CalculateMemPoolAncestors(entry, limits, fSearchForParents)}; + if (!Assume(result)) { + LogPrintLevel(BCLog::MEMPOOL, BCLog::Level::Error, "%s: CalculateMemPoolAncestors failed unexpectedly, continuing with empty ancestor set (%s)\n", + calling_fn_name, util::ErrorString(result).original); + } + return std::move(result).value_or(CTxMemPool::setEntries{}); } void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors) @@ -320,9 +329,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b } } for (txiter removeIt : entriesToRemove) { - setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; - std::string dummy; // Since this is a tx that is already in the mempool, we can call CMPA // with fSearchForParents = false. If the mempool is in a consistent // state, then using true or false should both be correct, though false @@ -342,10 +349,10 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b // mempool parents we'd calculate by searching, and it's important that // we use the cached notion of ancestor transactions as the set of // things to update for removal. - CalculateMemPoolAncestors(entry, setAncestors, Limits::NoLimits(), dummy, false); + auto ancestors{AssumeCalculateMemPoolAncestors(__func__, entry, Limits::NoLimits(), /*fSearchForParents=*/false)}; // Note that UpdateAncestorsOf severs the child links that point to // removeIt in the entries for the parents of removeIt. - UpdateAncestorsOf(false, removeIt, setAncestors); + UpdateAncestorsOf(false, removeIt, ancestors); } // After updating all the ancestor sizes, we can now sever the link between each // transaction being removed and any mempool children (ie, update CTxMemPoolEntry::m_parents @@ -389,7 +396,6 @@ CTxMemPool::CTxMemPool(const Options& opts) m_full_rbf{opts.full_rbf}, m_limits{opts.limits} { - _clear(); //lock free clear } bool CTxMemPool::isSpent(const COutPoint& outpoint) const @@ -627,26 +633,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne blockSinceLastRollingFeeBump = true; } -void CTxMemPool::_clear() -{ - vTxHashes.clear(); - mapTx.clear(); - mapNextTx.clear(); - totalTxSize = 0; - m_total_fee = 0; - cachedInnerUsage = 0; - lastRollingFeeUpdate = GetTime(); - blockSinceLastRollingFeeBump = false; - rollingMinimumFeeRate = 0; - ++nTransactionsUpdated; -} - -void CTxMemPool::clear() -{ - LOCK(cs); - _clear(); -} - void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendheight) const { if (m_check_ratio == 0) return; @@ -695,15 +681,13 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei assert(setParentCheck.size() == it->GetMemPoolParentsConst().size()); assert(std::equal(setParentCheck.begin(), setParentCheck.end(), it->GetMemPoolParentsConst().begin(), comp)); // Verify ancestor state is correct. - setEntries setAncestors; - std::string dummy; - CalculateMemPoolAncestors(*it, setAncestors, Limits::NoLimits(), dummy); - uint64_t nCountCheck = setAncestors.size() + 1; + auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())}; + uint64_t nCountCheck = ancestors.size() + 1; uint64_t nSizeCheck = it->GetTxSize(); CAmount nFeesCheck = it->GetModifiedFee(); int64_t nSigOpCheck = it->GetSigOpCost(); - for (txiter ancestorIt : setAncestors) { + for (txiter ancestorIt : ancestors) { nSizeCheck += ancestorIt->GetTxSize(); nFeesCheck += ancestorIt->GetModifiedFee(); nSigOpCheck += ancestorIt->GetSigOpCost(); @@ -858,10 +842,8 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD if (it != mapTx.end()) { mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); }); // Now update all ancestors' modified fees with descendants - setEntries setAncestors; - std::string dummy; - CalculateMemPoolAncestors(*it, setAncestors, Limits::NoLimits(), dummy, false); - for (txiter ancestorIt : setAncestors) { + auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits(), /*fSearchForParents=*/false)}; + for (txiter ancestorIt : ancestors) { mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);}); } // Now update all descendants' modified fees with ancestors @@ -998,10 +980,8 @@ int CTxMemPool::Expire(std::chrono::seconds time) void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate) { - setEntries setAncestors; - std::string dummy; - CalculateMemPoolAncestors(entry, setAncestors, Limits::NoLimits(), dummy); - return addUnchecked(entry, setAncestors, validFeeEstimate); + auto ancestors{AssumeCalculateMemPoolAncestors(__func__, entry, Limits::NoLimits())}; + return addUnchecked(entry, ancestors, validFeeEstimate); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) diff --git a/src/txmempool.h b/src/txmempool.h index d48327e5dc..51b8af3286 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +11,7 @@ #include <optional> #include <set> #include <string> +#include <string_view> #include <utility> #include <vector> @@ -20,14 +21,16 @@ #include <coins.h> #include <consensus/amount.h> #include <indirectmap.h> +#include <kernel/cs_main.h> +#include <kernel/mempool_entry.h> #include <policy/feerate.h> #include <policy/packages.h> #include <primitives/transaction.h> #include <random.h> #include <sync.h> -#include <txmempool_entry.h> #include <util/epochguard.h> #include <util/hasher.h> +#include <util/result.h> #include <boost/multi_index/hashed_index.hpp> #include <boost/multi_index/ordered_index.hpp> @@ -37,7 +40,6 @@ class CBlockIndex; class CChain; class Chainstate; -extern RecursiveMutex cs_main; /** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */ static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF; @@ -317,14 +319,14 @@ protected: std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation CBlockPolicyEstimator* const minerPolicyEstimator; - uint64_t totalTxSize GUARDED_BY(cs); //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141. - CAmount m_total_fee GUARDED_BY(cs); //!< sum of all mempool tx's fees (NOT modified fee) - uint64_t cachedInnerUsage GUARDED_BY(cs); //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves) + uint64_t totalTxSize GUARDED_BY(cs){0}; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141. + CAmount m_total_fee GUARDED_BY(cs){0}; //!< sum of all mempool tx's fees (NOT modified fee) + uint64_t cachedInnerUsage GUARDED_BY(cs){0}; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves) - mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs); - mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs); - mutable double rollingMinimumFeeRate GUARDED_BY(cs); //!< minimum fee to get into the pool, decreases exponentially - mutable Epoch m_epoch GUARDED_BY(cs); + mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs){GetTime()}; + mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs){false}; + mutable double rollingMinimumFeeRate GUARDED_BY(cs){0}; //!< minimum fee to get into the pool, decreases exponentially + mutable Epoch m_epoch GUARDED_BY(cs){}; // In-memory counter for external mempool tracking purposes. // This number is incremented once every time a transaction @@ -428,24 +430,20 @@ private: /** * Helper function to calculate all in-mempool ancestors of staged_ancestors and apply ancestor - * and descendant limits (including staged_ancestors thsemselves, entry_size and entry_count). + * and descendant limits (including staged_ancestors themselves, entry_size and entry_count). * * @param[in] entry_size Virtual size to include in the limits. * @param[in] entry_count How many entries to include in the limits. - * @param[out] setAncestors Will be populated with all mempool ancestors. * @param[in] staged_ancestors Should contain entries in the mempool. * @param[in] limits Maximum number and size of ancestors and descendants - * @param[out] errString Populated with error reason if any limits are hit * - * @return true if no limits were hit and all in-mempool ancestors were calculated, false - * otherwise + * @return all in-mempool ancestors, or an error if any ancestor or descendant limits were hit */ - bool CalculateAncestorsAndCheckLimits(size_t entry_size, - size_t entry_count, - setEntries& setAncestors, - CTxMemPoolEntry::Parents &staged_ancestors, - const Limits& limits, - std::string &errString) const EXCLUSIVE_LOCKS_REQUIRED(cs); + util::Result<setEntries> CalculateAncestorsAndCheckLimits(size_t entry_size, + size_t entry_count, + CTxMemPoolEntry::Parents &staged_ancestors, + const Limits& limits + ) const EXCLUSIVE_LOCKS_REQUIRED(cs); public: indirectmap<COutPoint, const CTransaction*> mapNextTx GUARDED_BY(cs); @@ -502,8 +500,6 @@ public: void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs); - void clear(); - void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid=false); void queryHashes(std::vector<uint256>& vtxid) const; bool isSpent(const COutPoint& outpoint) const; @@ -558,22 +554,37 @@ public: * (these are all calculated including the tx itself) * * @param[in] entry CTxMemPoolEntry of which all in-mempool ancestors are calculated - * @param[out] setAncestors Will be populated with all mempool ancestors. * @param[in] limits Maximum number and size of ancestors and descendants - * @param[out] errString Populated with error reason if any limits are hit * @param[in] fSearchForParents Whether to search a tx's vin for in-mempool parents, or look * up parents from mapLinks. Must be true for entries not in * the mempool * - * @return true if no limits were hit and all in-mempool ancestors were calculated, false - * otherwise + * @return all in-mempool ancestors, or an error if any ancestor or descendant limits were hit */ - bool CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, - setEntries& setAncestors, + util::Result<setEntries> CalculateMemPoolAncestors(const CTxMemPoolEntry& entry, const Limits& limits, - std::string& errString, bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs); + /** + * Same as CalculateMemPoolAncestors, but always returns a (non-optional) setEntries. + * Should only be used when it is assumed CalculateMemPoolAncestors would not fail. If + * CalculateMemPoolAncestors does unexpectedly fail, an empty setEntries is returned and the + * error is logged to BCLog::MEMPOOL with level BCLog::Level::Error. In debug builds, failure + * of CalculateMemPoolAncestors will lead to shutdown due to assertion failure. + * + * @param[in] calling_fn_name Name of calling function so we can properly log the call site + * + * @return a setEntries corresponding to the result of CalculateMemPoolAncestors or an empty + * setEntries if it failed + * + * @see CTXMemPool::CalculateMemPoolAncestors() + */ + setEntries AssumeCalculateMemPoolAncestors( + std::string_view calling_fn_name, + const CTxMemPoolEntry &entry, + const Limits& limits, + bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs); + /** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and * check ancestor and descendant limits. Heuristics are used to estimate the ancestor and * descendant count of all entries if the package were to be added to the mempool. The limits diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp index 69ae8ea582..94f64abca7 100644 --- a/src/txorphanage.cpp +++ b/src/txorphanage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,11 +15,10 @@ static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; /** Minimum time between orphan transactions expire time checks in seconds */ static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; -RecursiveMutex g_cs_orphans; bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) { - AssertLockHeld(g_cs_orphans); + LOCK(m_mutex); const uint256& hash = tx->GetHash(); if (m_orphans.count(hash)) @@ -55,7 +54,13 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) int TxOrphanage::EraseTx(const uint256& txid) { - AssertLockHeld(g_cs_orphans); + LOCK(m_mutex); + return _EraseTx(txid); +} + +int TxOrphanage::_EraseTx(const uint256& txid) +{ + AssertLockHeld(m_mutex); std::map<uint256, OrphanTx>::iterator it = m_orphans.find(txid); if (it == m_orphans.end()) return 0; @@ -87,7 +92,9 @@ int TxOrphanage::EraseTx(const uint256& txid) void TxOrphanage::EraseForPeer(NodeId peer) { - AssertLockHeld(g_cs_orphans); + LOCK(m_mutex); + + m_peer_work_set.erase(peer); int nErased = 0; std::map<uint256, OrphanTx>::iterator iter = m_orphans.begin(); @@ -96,7 +103,7 @@ void TxOrphanage::EraseForPeer(NodeId peer) std::map<uint256, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid if (maybeErase->second.fromPeer == peer) { - nErased += EraseTx(maybeErase->second.tx->GetHash()); + nErased += _EraseTx(maybeErase->second.tx->GetHash()); } } if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer); @@ -104,7 +111,7 @@ void TxOrphanage::EraseForPeer(NodeId peer) void TxOrphanage::LimitOrphans(unsigned int max_orphans) { - AssertLockHeld(g_cs_orphans); + LOCK(m_mutex); unsigned int nEvicted = 0; static int64_t nNextSweep; @@ -118,7 +125,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans) { std::map<uint256, OrphanTx>::iterator maybeErase = iter++; if (maybeErase->second.nTimeExpire <= nNow) { - nErased += EraseTx(maybeErase->second.tx->GetHash()); + nErased += _EraseTx(maybeErase->second.tx->GetHash()); } else { nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); } @@ -132,15 +139,19 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans) { // Evict a random orphan: size_t randompos = rng.randrange(m_orphan_list.size()); - EraseTx(m_orphan_list[randompos]->first); + _EraseTx(m_orphan_list[randompos]->first); ++nEvicted; } if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted); } -void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const +void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, NodeId peer) { - AssertLockHeld(g_cs_orphans); + LOCK(m_mutex); + + // Get this peer's work set, emplacing an empty set it didn't exist + std::set<uint256>& orphan_work_set = m_peer_work_set.try_emplace(peer).first->second; + for (unsigned int i = 0; i < tx.vout.size(); i++) { const auto it_by_prev = m_outpoint_to_orphan_it.find(COutPoint(tx.GetHash(), i)); if (it_by_prev != m_outpoint_to_orphan_it.end()) { @@ -153,7 +164,7 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256> bool TxOrphanage::HaveTx(const GenTxid& gtxid) const { - LOCK(g_cs_orphans); + LOCK(m_mutex); if (gtxid.IsWtxid()) { return m_wtxid_to_orphan_it.count(gtxid.GetHash()); } else { @@ -161,18 +172,32 @@ bool TxOrphanage::HaveTx(const GenTxid& gtxid) const } } -std::pair<CTransactionRef, NodeId> TxOrphanage::GetTx(const uint256& txid) const +CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer, NodeId& originator, bool& more) { - AssertLockHeld(g_cs_orphans); - - const auto it = m_orphans.find(txid); - if (it == m_orphans.end()) return {nullptr, -1}; - return {it->second.tx, it->second.fromPeer}; + LOCK(m_mutex); + + auto work_set_it = m_peer_work_set.find(peer); + if (work_set_it != m_peer_work_set.end()) { + auto& work_set = work_set_it->second; + while (!work_set.empty()) { + uint256 txid = *work_set.begin(); + work_set.erase(work_set.begin()); + + const auto orphan_it = m_orphans.find(txid); + if (orphan_it != m_orphans.end()) { + more = !work_set.empty(); + originator = orphan_it->second.fromPeer; + return orphan_it->second.tx; + } + } + } + more = false; + return nullptr; } void TxOrphanage::EraseForBlock(const CBlock& block) { - LOCK(g_cs_orphans); + LOCK(m_mutex); std::vector<uint256> vOrphanErase; @@ -195,7 +220,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block) if (vOrphanErase.size()) { int nErased = 0; for (const uint256& orphanHash : vOrphanErase) { - nErased += EraseTx(orphanHash); + nErased += _EraseTx(orphanHash); } LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased); } diff --git a/src/txorphanage.h b/src/txorphanage.h index 9363e6f733..cd7587fab5 100644 --- a/src/txorphanage.h +++ b/src/txorphanage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,8 +10,8 @@ #include <primitives/transaction.h> #include <sync.h> -/** Guards orphan transactions and extra txs for compact blocks */ -extern RecursiveMutex g_cs_orphans; +#include <map> +#include <set> /** A class to track orphan transactions (failed on TX_MISSING_INPUTS) * Since we cannot distinguish orphans from bad transactions with @@ -21,40 +21,46 @@ extern RecursiveMutex g_cs_orphans; class TxOrphanage { public: /** Add a new orphan transaction */ - bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Check if we already have an orphan transaction (by txid or wtxid) */ - bool HaveTx(const GenTxid& gtxid) const LOCKS_EXCLUDED(::g_cs_orphans); - - /** Get an orphan transaction and its originating peer - * (Transaction ref will be nullptr if not found) + bool HaveTx(const GenTxid& gtxid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + + /** Extract a transaction from a peer's work set + * Returns nullptr and sets more to false if there are no transactions + * to work on. Otherwise returns the transaction reference, removes + * the transaction from the work set, and populates its arguments with + * the originating peer, and whether there are more orphans for this peer + * to work on after this tx. */ - std::pair<CTransactionRef, NodeId> GetTx(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + CTransactionRef GetTxToReconsider(NodeId peer, NodeId& originator, bool& more) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Erase an orphan by txid */ - int EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + int EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Erase all orphans announced by a peer (eg, after that peer disconnects) */ - void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Erase all orphans included in or invalidated by a new block */ - void EraseForBlock(const CBlock& block) LOCKS_EXCLUDED(::g_cs_orphans); + void EraseForBlock(const CBlock& block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Limit the orphanage to the given maximum */ - void LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + void LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); - /** Add any orphans that list a particular tx as a parent into a peer's work set - * (ie orphans that may have found their final missing parent, and so should be reconsidered for the mempool) */ - void AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans); + /** Add any orphans that list a particular tx as a parent into a peer's work set */ + void AddChildrenToWorkSet(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Return how many entries exist in the orphange */ - size_t Size() LOCKS_EXCLUDED(::g_cs_orphans) + size_t Size() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { - LOCK(::g_cs_orphans); + LOCK(m_mutex); return m_orphans.size(); } protected: + /** Guards orphan transactions */ + mutable Mutex m_mutex; + struct OrphanTx { CTransactionRef tx; NodeId fromPeer; @@ -64,7 +70,10 @@ protected: /** Map from txid to orphan transaction record. Limited by * -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */ - std::map<uint256, OrphanTx> m_orphans GUARDED_BY(g_cs_orphans); + std::map<uint256, OrphanTx> m_orphans GUARDED_BY(m_mutex); + + /** Which peer provided a parent tx of orphans that need to be reconsidered */ + std::map<NodeId, std::set<uint256>> m_peer_work_set GUARDED_BY(m_mutex); using OrphanMap = decltype(m_orphans); @@ -79,14 +88,17 @@ protected: /** Index from the parents' COutPoint into the m_orphans. Used * to remove orphan transactions from the m_orphans */ - std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it GUARDED_BY(g_cs_orphans); + std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it GUARDED_BY(m_mutex); /** Orphan transactions in vector for quick random eviction */ - std::vector<OrphanMap::iterator> m_orphan_list GUARDED_BY(g_cs_orphans); + std::vector<OrphanMap::iterator> m_orphan_list GUARDED_BY(m_mutex); /** Index from wtxid into the m_orphans to lookup orphan * transactions using their witness ids. */ - std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(g_cs_orphans); + std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(m_mutex); + + /** Erase an orphan by txid */ + int _EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex); }; #endif // BITCOIN_TXORPHANAGE_H diff --git a/src/uint256.h b/src/uint256.h index e74b9ff7b1..58e595c4ca 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 1af7df079e..16853260b8 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -66,7 +66,6 @@ public: size_t size() const { return values.size(); } - bool getBool() const { return isTrue(); } void getObjMap(std::map<std::string,UniValue>& kv) const; bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const; const UniValue& operator[](const std::string& key) const; diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp index 5c58f388dd..037449ca08 100644 --- a/src/univalue/lib/univalue_get.cpp +++ b/src/univalue/lib/univalue_get.cpp @@ -60,7 +60,7 @@ const std::vector<UniValue>& UniValue::getValues() const bool UniValue::get_bool() const { checkType(VBOOL); - return getBool(); + return isTrue(); } const std::string& UniValue::get_str() const diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 65e82543e4..5ddf300393 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2014 BitPay Inc. -// Copyright (c) 2014-2016 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. @@ -193,13 +193,13 @@ void univalue_set() BOOST_CHECK_EQUAL(v.isBool(), true); BOOST_CHECK_EQUAL(v.isTrue(), false); BOOST_CHECK_EQUAL(v.isFalse(), true); - BOOST_CHECK_EQUAL(v.getBool(), false); + BOOST_CHECK_EQUAL(v.get_bool(), false); v.setBool(true); BOOST_CHECK_EQUAL(v.isBool(), true); BOOST_CHECK_EQUAL(v.isTrue(), true); BOOST_CHECK_EQUAL(v.isFalse(), false); - BOOST_CHECK_EQUAL(v.getBool(), true); + BOOST_CHECK_EQUAL(v.get_bool(), true); BOOST_CHECK_THROW(v.setNumStr("zombocom"), std::runtime_error); diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp index 33258d9962..4b548c5a4d 100644 --- a/src/util/asmap.cpp +++ b/src/util/asmap.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp index 796af4a544..c4b7120394 100644 --- a/src/util/bip32.cpp +++ b/src/util/bip32.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/bip32.h b/src/util/bip32.h index 0872bc88de..b720cb5638 100644 --- a/src/util/bip32.h +++ b/src/util/bip32.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp index 6d777613e6..29be138eeb 100644 --- a/src/util/bytevectorhash.cpp +++ b/src/util/bytevectorhash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/bytevectorhash.h b/src/util/bytevectorhash.h index c2322b8daf..079385678c 100644 --- a/src/util/bytevectorhash.h +++ b/src/util/bytevectorhash.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/check.cpp b/src/util/check.cpp index e50d6087d0..34b9d376a7 100644 --- a/src/util/check.cpp +++ b/src/util/check.cpp @@ -8,16 +8,23 @@ #include <config/bitcoin-config.h> #endif +#include <clientversion.h> #include <tinyformat.h> #include <cstdio> #include <cstdlib> #include <string> +std::string StrFormatInternalBug(const char* msg, const char* file, int line, const char* func) +{ + return strprintf("Internal bug detected: \"%s\"\n%s:%d (%s)\n" + "%s %s\n" + "Please report this issue here: %s\n", + msg, file, line, func, PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT); +} NonFatalCheckError::NonFatalCheckError(const char* msg, const char* file, int line, const char* func) - : std::runtime_error{ - strprintf("Internal bug detected: \"%s\"\n%s:%d (%s)\nPlease report this issue here: %s\n", msg, file, line, func, PACKAGE_BUGREPORT)} + : std::runtime_error{StrFormatInternalBug(msg, file, line, func)} { } diff --git a/src/util/check.h b/src/util/check.h index b6c03bed2a..96cd905d47 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,12 +10,16 @@ #include <stdexcept> #include <utility> +std::string StrFormatInternalBug(const char* msg, const char* file, int line, const char* func); + class NonFatalCheckError : public std::runtime_error { public: NonFatalCheckError(const char* msg, const char* file, int line, const char* func); }; +#define STR_INTERNAL_BUG(msg) StrFormatInternalBug((msg), __FILE__, __LINE__, __func__) + /** Helper for CHECK_NONFATAL() */ template <typename T> T&& inline_check_non_fatal(LIFETIMEBOUND T&& val, const char* file, int line, const char* func, const char* assertion) diff --git a/src/util/epochguard.h b/src/util/epochguard.h index 7f6477fb3b..145f4dc132 100644 --- a/src/util/epochguard.h +++ b/src/util/epochguard.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/error.cpp b/src/util/error.cpp index 390cb6c11b..193265c842 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2021 The Bitcoin Core developers +// Copyright (c) 2010-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/error.h b/src/util/error.h index 27916501f0..649200c98e 100644 --- a/src/util/error.h +++ b/src/util/error.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020 The Bitcoin Core developers +// Copyright (c) 2010-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/fastrange.h b/src/util/fastrange.h index 77cb883ce0..87a2415976 100644 --- a/src/util/fastrange.h +++ b/src/util/fastrange.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/getuniquepath.cpp b/src/util/getuniquepath.cpp index 1d8e511c83..42c5dee0ed 100644 --- a/src/util/getuniquepath.cpp +++ b/src/util/getuniquepath.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/golombrice.h b/src/util/golombrice.h index 4ff4f6d7e5..63402c5e4d 100644 --- a/src/util/golombrice.h +++ b/src/util/golombrice.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp index a80f20c894..a3a3f7a429 100644 --- a/src/util/hasher.cpp +++ b/src/util/hasher.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/hasher.h b/src/util/hasher.h index 426b8990e6..82d278b086 100644 --- a/src/util/hasher.h +++ b/src/util/hasher.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/macros.h b/src/util/macros.h index bf6ba665dc..11aa683152 100644 --- a/src/util/macros.h +++ b/src/util/macros.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/message.cpp b/src/util/message.cpp index 7d6f3403f4..f8ea8247d5 100644 --- a/src/util/message.cpp +++ b/src/util/message.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/message.h b/src/util/message.h index 1b7febe60a..d0e2422574 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp index d9e6cef600..9181329afc 100644 --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,7 +34,7 @@ std::string FormatMoney(const CAmount n) str.erase(str.size()-nTrim, nTrim); if (n < 0) - str.insert((unsigned int)0, 1, '-'); + str.insert(uint32_t{0}, 1, '-'); return str; } diff --git a/src/util/moneystr.h b/src/util/moneystr.h index 3d33bd7f99..dba0ce676a 100644 --- a/src/util/moneystr.h +++ b/src/util/moneystr.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/overflow.h b/src/util/overflow.h index 6b7dd1e8fd..7e0cce6c27 100644 --- a/src/util/overflow.h +++ b/src/util/overflow.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/readwritefile.cpp b/src/util/readwritefile.cpp index 3ec08119e7..c22e6815e3 100644 --- a/src/util/readwritefile.cpp +++ b/src/util/readwritefile.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/serfloat.h b/src/util/serfloat.h index 343ccb9d3a..0dbba6ee03 100644 --- a/src/util/serfloat.h +++ b/src/util/serfloat.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/settings.cpp b/src/util/settings.cpp index 924a9cfab2..2b25b7f0e1 100644 --- a/src/util/settings.cpp +++ b/src/util/settings.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/settings.h b/src/util/settings.h index e97158dc09..b0d8acb711 100644 --- a/src/util/settings.h +++ b/src/util/settings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/sock.cpp b/src/util/sock.cpp index 84ac2759fa..53d20bdf19 100644 --- a/src/util/sock.cpp +++ b/src/util/sock.cpp @@ -1,14 +1,14 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 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 <compat/compat.h> #include <logging.h> -#include <threadinterrupt.h> #include <tinyformat.h> #include <util/sock.h> #include <util/syserror.h> #include <util/system.h> +#include <util/threadinterrupt.h> #include <util/time.h> #include <memory> diff --git a/src/util/sock.h b/src/util/sock.h index 7912284904..adcca377e3 100644 --- a/src/util/sock.h +++ b/src/util/sock.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,7 +6,7 @@ #define BITCOIN_UTIL_SOCK_H #include <compat/compat.h> -#include <threadinterrupt.h> +#include <util/threadinterrupt.h> #include <util/time.h> #include <chrono> diff --git a/src/util/spanparsing.cpp b/src/util/spanparsing.cpp index 565c867e18..c464fc2b87 100644 --- a/src/util/spanparsing.cpp +++ b/src/util/spanparsing.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/spanparsing.h b/src/util/spanparsing.h index 51795271de..765fe13aca 100644 --- a/src/util/spanparsing.h +++ b/src/util/spanparsing.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index e28ca8e73a..45a01429e1 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 94bc6cc2f3..626e48f499 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/string.cpp b/src/util/string.cpp index e994c85f1c..3d31849745 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/string.h b/src/util/string.h index 9b4c9a7e28..fb93d2a80e 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp index a69f815ce4..b1579bdb9c 100644 --- a/src/util/syscall_sandbox.cpp +++ b/src/util/syscall_sandbox.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/syscall_sandbox.h b/src/util/syscall_sandbox.h index dc02ce29e9..3e56ebe937 100644 --- a/src/util/syscall_sandbox.h +++ b/src/util/syscall_sandbox.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/system.cpp b/src/util/system.cpp index d7a0793ea8..309595ff5b 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/system.h b/src/util/system.h index 29629e547e..671491f2ff 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/thread.cpp b/src/util/thread.cpp index ae98abdb3d..e9f611bc50 100644 --- a/src/util/thread.cpp +++ b/src/util/thread.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/thread.h b/src/util/thread.h index b80bf046a0..8a2de84a7f 100644 --- a/src/util/thread.h +++ b/src/util/thread.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/threadinterrupt.cpp b/src/util/threadinterrupt.cpp index e28b447c1d..3ea406d4a8 100644 --- a/src/threadinterrupt.cpp +++ b/src/util/threadinterrupt.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2022 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 <threadinterrupt.h> +#include <util/threadinterrupt.h> #include <sync.h> diff --git a/src/threadinterrupt.h b/src/util/threadinterrupt.h index 979bc2ee3e..ccc053f576 100644 --- a/src/threadinterrupt.h +++ b/src/util/threadinterrupt.h @@ -1,9 +1,9 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 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_THREADINTERRUPT_H -#define BITCOIN_THREADINTERRUPT_H +#ifndef BITCOIN_UTIL_THREADINTERRUPT_H +#define BITCOIN_UTIL_THREADINTERRUPT_H #include <sync.h> #include <threadsafety.h> @@ -33,4 +33,4 @@ private: std::atomic<bool> flag; }; -#endif // BITCOIN_THREADINTERRUPT_H +#endif // BITCOIN_UTIL_THREADINTERRUPT_H diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp index a5a86d2598..91883fe4ff 100644 --- a/src/util/threadnames.cpp +++ b/src/util/threadnames.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/time.cpp b/src/util/time.cpp index 0b20849079..58200c83fc 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/time.h b/src/util/time.h index 10a581a44c..d45baaa378 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/tokenpipe.cpp b/src/util/tokenpipe.cpp index 49456814e2..3c27d5e523 100644 --- a/src/util/tokenpipe.cpp +++ b/src/util/tokenpipe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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/tokenpipe.h> diff --git a/src/util/translation.h b/src/util/translation.h index 07b7f43c8a..05e7da0b5a 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/vector.h b/src/util/vector.h index ed745affe5..9b9218e54f 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/validation.cpp b/src/validation.cpp index 1cf6fc0675..b42b398619 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 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,6 +22,7 @@ #include <flatfile.h> #include <fs.h> #include <hash.h> +#include <kernel/mempool_entry.h> #include <logging.h> #include <logging/timer.h> #include <node/blockstorage.h> @@ -42,7 +43,6 @@ #include <tinyformat.h> #include <txdb.h> #include <txmempool.h> -#include <txmempool_entry.h> #include <uint256.h> #include <undo.h> #include <util/check.h> // For NDEBUG compile time check @@ -64,6 +64,7 @@ #include <numeric> #include <optional> #include <string> +#include <utility> using kernel::CCoinsStats; using kernel::CoinStatsHashType; @@ -106,18 +107,6 @@ const std::vector<std::string> CHECKLEVEL_DOC { * */ static constexpr int PRUNE_LOCK_BUFFER{10}; -/** - * Mutex to guard access to validation specific variables, such as reading - * or changing the chainstate. - * - * This may also need to be locked when updating the transaction pool, e.g. on - * AcceptToMemoryPool. See CTxMemPool::cs comment for details. - * - * The transaction pool has a separate lock to allow reading from it and the - * chainstate at the same time. - */ -RecursiveMutex cs_main; - GlobalMutex g_best_block_mutex; std::condition_variable g_best_block_cv; uint256 g_best_block; @@ -582,6 +571,11 @@ private: /** Total virtual size of all transactions being replaced. */ size_t m_conflicting_size{0}; + /** If we're doing package validation (i.e. m_package_feerates=true), the "effective" + * package feerate of this transaction is the total fees divided by the total size of + * transactions (which may include its ancestors and/or descendants). */ + CFeeRate m_package_feerate{0}; + const CTransactionRef& m_ptx; /** Txid. */ const uint256& m_hash; @@ -690,10 +684,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); } - // Do not work on transactions that are too small. - // A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes. - // Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying - // 64-byte transactions. + // Transactions smaller than 65 non-witness bytes are not relayed to mitigate CVE-2017-12842. if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE) return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "tx-size-small"); @@ -870,11 +861,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) m_limits.descendant_size_vbytes += conflict->GetSizeWithDescendants(); } - std::string errString; - if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limits, errString)) { - ws.m_ancestors.clear(); + auto ancestors{m_pool.CalculateMemPoolAncestors(*entry, m_limits)}; + if (!ancestors) { // If CalculateMemPoolAncestors fails second time, we want the original error string. - std::string dummy_err_string; // Contracting/payment channels CPFP carve-out: // If the new transaction is relatively small (up to 40k weight) // and has at most one ancestor (ie ancestor limit of 2, including @@ -892,14 +881,16 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) .descendant_count = m_limits.descendant_count + 1, .descendant_size_vbytes = m_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT, }; - if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || - !m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, - cpfp_carve_out_limits, - dummy_err_string)) { - return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", errString); + const auto error_message{util::ErrorString(ancestors).original}; + if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT) { + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message); } + ancestors = m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits); + if (!ancestors) return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message); } + ws.m_ancestors = *ancestors; + // A transaction that spends outputs that would be replaced by it is invalid. Now // that we have the set of all ancestors we can detect this // pathological case by making sure ws.m_conflicts and ws.m_ancestors don't @@ -1114,15 +1105,18 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& // Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the // last calculation done in PreChecks, since package ancestors have already been submitted. - std::string unused_err_string; - if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limits, unused_err_string)) { - results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); - // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail. - Assume(false); - all_submitted = false; - package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR, - strprintf("BUG! Mempool ancestors or descendants were underestimated: %s", - ws.m_ptx->GetHash().ToString())); + { + auto ancestors{m_pool.CalculateMemPoolAncestors(*ws.m_entry, m_limits)}; + if(!ancestors) { + results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); + // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail. + Assume(false); + all_submitted = false; + package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR, + strprintf("BUG! Mempool ancestors or descendants were underestimated: %s", + ws.m_ptx->GetHash().ToString())); + } + ws.m_ancestors = std::move(ancestors).value_or(ws.m_ancestors); } // If we call LimitMempoolSize() for each individual Finalize(), the mempool will not take // the transaction's descendant feerate into account because it hasn't seen them yet. Also, @@ -1143,12 +1137,21 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& // make sure we haven't exceeded max mempool size. LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip()); + std::vector<uint256> all_package_wtxids; + all_package_wtxids.reserve(workspaces.size()); + std::transform(workspaces.cbegin(), workspaces.cend(), std::back_inserter(all_package_wtxids), + [](const auto& ws) { return ws.m_ptx->GetWitnessHash(); }); // Find the wtxids of the transactions that made it into the mempool. Allow partial submission, // but don't report success unless they all made it into the mempool. for (Workspace& ws : workspaces) { + const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate : + CFeeRate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)}; + const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids : + std::vector<uint256>({ws.m_ptx->GetWitnessHash()}); if (m_pool.exists(GenTxid::Wtxid(ws.m_ptx->GetWitnessHash()))) { results.emplace(ws.m_ptx->GetWitnessHash(), - MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees)); + MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, + ws.m_base_fees, effective_feerate, effective_feerate_wtxids)); GetMainSignals().TransactionAddedToMempool(ws.m_ptx, m_pool.GetAndIncrementSequence()); } else { all_submitted = false; @@ -1176,16 +1179,20 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef if (!ConsensusScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state); + const CFeeRate effective_feerate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)}; + const std::vector<uint256> single_wtxid{ws.m_ptx->GetWitnessHash()}; // Tx was accepted, but not added if (args.m_test_accept) { - return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees); + return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, + ws.m_base_fees, effective_feerate, single_wtxid); } if (!Finalize(args, ws)) return MempoolAcceptResult::Failure(ws.m_state); GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence()); - return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees); + return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees, + effective_feerate, single_wtxid); } PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::vector<CTransactionRef>& txns, ATMPArgs& args) @@ -1232,7 +1239,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: if (args.m_package_feerates && !CheckFeeRate(m_total_vsize, m_total_modified_fees, placeholder_state)) { package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-fee-too-low"); - return PackageMempoolAcceptResult(package_state, package_feerate, {}); + return PackageMempoolAcceptResult(package_state, {}); } // Apply package mempool ancestor/descendant limits. Skip if there is only one transaction, @@ -1240,51 +1247,60 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: // transactions, but this exemption is not extended to packages in CheckPackageLimits(). std::string err_string; if (txns.size() > 1 && !PackageMempoolChecks(txns, package_state)) { - return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results)); + return PackageMempoolAcceptResult(package_state, std::move(results)); } + std::vector<uint256> all_package_wtxids; + all_package_wtxids.reserve(workspaces.size()); + std::transform(workspaces.cbegin(), workspaces.cend(), std::back_inserter(all_package_wtxids), + [](const auto& ws) { return ws.m_ptx->GetWitnessHash(); }); for (Workspace& ws : workspaces) { + ws.m_package_feerate = package_feerate; if (!PolicyScriptChecks(args, ws)) { // Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished. package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed"); results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); - return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results)); + return PackageMempoolAcceptResult(package_state, std::move(results)); } if (args.m_test_accept) { - // When test_accept=true, transactions that pass PolicyScriptChecks are valid because there are - // no further mempool checks (passing PolicyScriptChecks implies passing ConsensusScriptChecks). + const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate : + CFeeRate{ws.m_modified_fees, static_cast<uint32_t>(ws.m_vsize)}; + const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids : + std::vector<uint256>{ws.m_ptx->GetWitnessHash()}; results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), - ws.m_vsize, ws.m_base_fees)); + ws.m_vsize, ws.m_base_fees, effective_feerate, + effective_feerate_wtxids)); } } - if (args.m_test_accept) return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results)); + if (args.m_test_accept) return PackageMempoolAcceptResult(package_state, std::move(results)); if (!SubmitPackage(args, workspaces, package_state, results)) { // PackageValidationState filled in by SubmitPackage(). - return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results)); + return PackageMempoolAcceptResult(package_state, std::move(results)); } - return PackageMempoolAcceptResult(package_state, package_feerate, std::move(results)); + return PackageMempoolAcceptResult(package_state, std::move(results)); } PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, ATMPArgs& args) { AssertLockHeld(cs_main); - PackageValidationState package_state; + // Used if returning a PackageMempoolAcceptResult directly from this function. + PackageValidationState package_state_quit_early; // Check that the package is well-formed. If it isn't, we won't try to validate any of the // transactions and thus won't return any MempoolAcceptResults, just a package-wide error. // Context-free package checks. - if (!CheckPackage(package, package_state)) return PackageMempoolAcceptResult(package_state, {}); + if (!CheckPackage(package, package_state_quit_early)) return PackageMempoolAcceptResult(package_state_quit_early, {}); // All transactions in the package must be a parent of the last transaction. This is just an // opportunity for us to fail fast on a context-free check without taking the mempool lock. if (!IsChildWithParents(package)) { - package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents"); - return PackageMempoolAcceptResult(package_state, {}); + package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-parents"); + return PackageMempoolAcceptResult(package_state_quit_early, {}); } // IsChildWithParents() guarantees the package is > 1 transactions. @@ -1316,15 +1332,16 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, return unconfirmed_parent_txids.count(input.prevout.hash) > 0 || m_view.HaveCoin(input.prevout); }; if (!std::all_of(child->vin.cbegin(), child->vin.cend(), package_or_confirmed)) { - package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-unconfirmed-parents"); - return PackageMempoolAcceptResult(package_state, {}); + package_state_quit_early.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-child-with-unconfirmed-parents"); + return PackageMempoolAcceptResult(package_state_quit_early, {}); } // Protect against bugs where we pull more inputs from disk that miss being added to // coins_to_uncache. The backend will be connected again when needed in PreChecks. m_view.SetBackend(m_dummy); LOCK(m_pool.cs); - std::map<const uint256, const MempoolAcceptResult> results; + // Stores final results that won't change + std::map<const uint256, const MempoolAcceptResult> results_final; // Node operators are free to set their mempool policies however they please, nodes may receive // transactions in different orders, and malicious counterparties may try to take advantage of // policy differences to pin or delay propagation of transactions. As such, it's possible for @@ -1334,8 +1351,13 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // the new transactions. This ensures we don't double-count transaction counts and sizes when // checking ancestor/descendant limits, or double-count transaction fees for fee-related policy. ATMPArgs single_args = ATMPArgs::SingleInPackageAccept(args); + // Results from individual validation. "Nonfinal" because if a transaction fails by itself but + // succeeds later (i.e. when evaluated with a fee-bumping child), the result changes (though not + // reflected in this map). If a transaction fails more than once, we want to return the first + // result, when it was considered on its own. So changes will only be from invalid -> valid. + std::map<uint256, MempoolAcceptResult> individual_results_nonfinal; bool quit_early{false}; - std::vector<CTransactionRef> txns_new; + std::vector<CTransactionRef> txns_package_eval; for (const auto& tx : package) { const auto& wtxid = tx->GetWitnessHash(); const auto& txid = tx->GetHash(); @@ -1346,7 +1368,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // Exact transaction already exists in the mempool. auto iter = m_pool.GetIter(txid); assert(iter != std::nullopt); - results.emplace(wtxid, MempoolAcceptResult::MempoolTx(iter.value()->GetTxSize(), iter.value()->GetFee())); + results_final.emplace(wtxid, MempoolAcceptResult::MempoolTx(iter.value()->GetTxSize(), iter.value()->GetFee())); } else if (m_pool.exists(GenTxid::Txid(txid))) { // Transaction with the same non-witness data but different witness (same txid, // different wtxid) already exists in the mempool. @@ -1358,7 +1380,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, auto iter = m_pool.GetIter(txid); assert(iter != std::nullopt); // Provide the wtxid of the mempool tx so that the caller can look it up in the mempool. - results.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(iter.value()->GetTx().GetWitnessHash())); + results_final.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(iter.value()->GetTx().GetWitnessHash())); } else { // Transaction does not already exist in the mempool. // Try submitting the transaction on its own. @@ -1367,7 +1389,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // The transaction succeeded on its own and is now in the mempool. Don't include it // in package validation, because its fees should only be "used" once. assert(m_pool.exists(GenTxid::Wtxid(wtxid))); - results.emplace(wtxid, single_res); + results_final.emplace(wtxid, single_res); } else if (single_res.m_state.GetResult() != TxValidationResult::TX_MEMPOOL_POLICY && single_res.m_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { // Package validation policy only differs from individual policy in its evaluation @@ -1380,24 +1402,40 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // future. Continue individually validating the rest of the transactions, because // some of them may still be valid. quit_early = true; + package_state_quit_early.Invalid(PackageValidationResult::PCKG_TX, "transaction failed"); + individual_results_nonfinal.emplace(wtxid, single_res); } else { - txns_new.push_back(tx); + individual_results_nonfinal.emplace(wtxid, single_res); + txns_package_eval.push_back(tx); } } } - // Nothing to do if the entire package has already been submitted. - if (quit_early || txns_new.empty()) { - // No package feerate when no package validation was done. - return PackageMempoolAcceptResult(package_state, std::move(results)); + // Quit early because package validation won't change the result or the entire package has + // already been submitted. + if (quit_early || txns_package_eval.empty()) { + for (const auto& [wtxid, mempoolaccept_res] : individual_results_nonfinal) { + Assume(results_final.emplace(wtxid, mempoolaccept_res).second); + Assume(mempoolaccept_res.m_result_type == MempoolAcceptResult::ResultType::INVALID); + } + return PackageMempoolAcceptResult(package_state_quit_early, std::move(results_final)); } - // Validate the (deduplicated) transactions as a package. - auto submission_result = AcceptMultipleTransactions(txns_new, args); + // Validate the (deduplicated) transactions as a package. Note that submission_result has its + // own PackageValidationState; package_state_quit_early is unused past this point. + auto submission_result = AcceptMultipleTransactions(txns_package_eval, args); // Include already-in-mempool transaction results in the final result. - for (const auto& [wtxid, mempoolaccept_res] : results) { - submission_result.m_tx_results.emplace(wtxid, mempoolaccept_res); + for (const auto& [wtxid, mempoolaccept_res] : results_final) { + Assume(submission_result.m_tx_results.emplace(wtxid, mempoolaccept_res).second); + Assume(mempoolaccept_res.m_result_type != MempoolAcceptResult::ResultType::INVALID); + } + if (submission_result.m_state.GetResult() == PackageValidationResult::PCKG_TX) { + // Package validation failed because one or more transactions failed. Provide a result for + // each transaction; if AcceptMultipleTransactions() didn't return a result for a tx, + // include the previous individual failure reason. + submission_result.m_tx_results.insert(individual_results_nonfinal.cbegin(), + individual_results_nonfinal.cend()); + Assume(submission_result.m_tx_results.size() == package.size()); } - if (submission_result.m_state.IsValid()) assert(submission_result.m_package_feerate.has_value()); return submission_result; } @@ -1414,7 +1452,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra std::vector<COutPoint> coins_to_uncache; auto args = MemPoolAccept::ATMPArgs::SingleAccept(chainparams, accept_time, bypass_limits, coins_to_uncache, test_accept); - const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args); + MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { // Remove coins that were not present in the coins cache before calling // AcceptSingleTransaction(); this is to prevent memory DoS in case we receive a large @@ -1439,7 +1477,7 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM std::vector<COutPoint> coins_to_uncache; const CChainParams& chainparams = active_chainstate.m_chainman.GetParams(); - const auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); if (test_accept) { auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), coins_to_uncache); @@ -1542,7 +1580,7 @@ bool Chainstate::IsInitialBlockDownload() const if (m_chain.Tip()->nChainWork < m_chainman.MinimumChainWork()) { return true; } - if (m_chain.Tip()->Time() < NodeClock::now() - m_chainman.m_options.max_tip_age) { + if (m_chain.Tip()->Time() < Now<NodeSeconds>() - m_chainman.m_options.max_tip_age) { return true; } LogPrintf("Leaving InitialBlockDownload (latching to false)\n"); @@ -2080,8 +2118,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the // two in the chain that violate it. This prevents exploiting the issue against nodes during their // initial block download. - bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || - (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); + bool fEnforceBIP30 = !IsBIP30Repeat(*pindex); // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the @@ -2361,8 +2398,6 @@ bool Chainstate::FlushStateToDisk( { LOCK(cs_main); assert(this->CanFlushToDisk()); - static std::chrono::microseconds nLastWrite{0}; - static std::chrono::microseconds nLastFlush{0}; std::set<int> setFilesToPrune; bool full_flush_completed = false; @@ -2416,20 +2451,20 @@ bool Chainstate::FlushStateToDisk( } const auto nNow = GetTime<std::chrono::microseconds>(); // Avoid writing/flushing immediately after startup. - if (nLastWrite.count() == 0) { - nLastWrite = nNow; + if (m_last_write.count() == 0) { + m_last_write = nNow; } - if (nLastFlush.count() == 0) { - nLastFlush = nNow; + if (m_last_flush.count() == 0) { + m_last_flush = nNow; } // The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing). bool fCacheLarge = mode == FlushStateMode::PERIODIC && cache_state >= CoinsCacheSizeState::LARGE; // The cache is over the limit, we have to write now. bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cache_state >= CoinsCacheSizeState::CRITICAL; // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. - bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > nLastWrite + DATABASE_WRITE_INTERVAL; + bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > m_last_write + DATABASE_WRITE_INTERVAL; // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. - bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + DATABASE_FLUSH_INTERVAL; + bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > m_last_flush + DATABASE_FLUSH_INTERVAL; // Combine all conditions that result in a full cache flush. fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; // Write blocks and block index to disk. @@ -2459,7 +2494,7 @@ bool Chainstate::FlushStateToDisk( UnlinkPrunedFiles(setFilesToPrune); } - nLastWrite = nNow; + m_last_write = nNow; } // Flush best chain related state. This can only be done if the blocks / block index write was also done. if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) { @@ -2477,7 +2512,7 @@ bool Chainstate::FlushStateToDisk( // Flush the chainstate (which may refer to block index entries). if (!CoinsTip().Flush()) return AbortNode(state, "Failed to write to coin database"); - nLastFlush = nNow; + m_last_flush = nNow; full_flush_completed = true; TRACE5(utxocache, flush, (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs) @@ -5313,3 +5348,15 @@ Chainstate& ChainstateManager::ActivateExistingSnapshot(CTxMemPool* mempool, uin m_active_chainstate = m_snapshot_chainstate.get(); return *m_snapshot_chainstate; } + +bool IsBIP30Repeat(const CBlockIndex& block_index) +{ + return (block_index.nHeight==91842 && block_index.GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || + (block_index.nHeight==91880 && block_index.GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")); +} + +bool IsBIP30Unspendable(const CBlockIndex& block_index) +{ + return (block_index.nHeight==91722 && block_index.GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) || + (block_index.nHeight==91812 && block_index.GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f")); +} diff --git a/src/validation.h b/src/validation.h index b8151dc1fc..7170467b00 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,6 +18,7 @@ #include <consensus/amount.h> #include <deploymentstatus.h> #include <fs.h> +#include <kernel/cs_main.h> // IWYU pragma: export #include <node/blockstorage.h> #include <policy/feerate.h> #include <policy/packages.h> @@ -86,7 +87,6 @@ enum class SynchronizationState { POST_INIT }; -extern RecursiveMutex cs_main; extern GlobalMutex g_best_block_mutex; extern std::condition_variable g_best_block_cv; /** Used to notify getblocktemplate RPC of new tips. */ @@ -134,6 +134,19 @@ struct MempoolAcceptResult { const std::optional<int64_t> m_vsize; /** Raw base fees in satoshis. */ const std::optional<CAmount> m_base_fees; + /** The feerate at which this transaction was considered. This includes any fee delta added + * using prioritisetransaction (i.e. modified fees). If this transaction was submitted as a + * package, this is the package feerate, which may also include its descendants and/or + * ancestors (see m_wtxids_fee_calculations below). + * Only present when m_result_type = ResultType::VALID. + */ + const std::optional<CFeeRate> m_effective_feerate; + /** Contains the wtxids of the transactions used for fee-related checks. Includes this + * transaction's wtxid and may include others if this transaction was validated as part of a + * package. This is not necessarily equivalent to the list of transactions passed to + * ProcessNewPackage(). + * Only present when m_result_type = ResultType::VALID. */ + const std::optional<std::vector<uint256>> m_wtxids_fee_calculations; // The following field is only present when m_result_type = ResultType::DIFFERENT_WITNESS /** The wtxid of the transaction in the mempool which has the same txid but different witness. */ @@ -143,8 +156,13 @@ struct MempoolAcceptResult { return MempoolAcceptResult(state); } - static MempoolAcceptResult Success(std::list<CTransactionRef>&& replaced_txns, int64_t vsize, CAmount fees) { - return MempoolAcceptResult(std::move(replaced_txns), vsize, fees); + static MempoolAcceptResult Success(std::list<CTransactionRef>&& replaced_txns, + int64_t vsize, + CAmount fees, + CFeeRate effective_feerate, + const std::vector<uint256>& wtxids_fee_calculations) { + return MempoolAcceptResult(std::move(replaced_txns), vsize, fees, + effective_feerate, wtxids_fee_calculations); } static MempoolAcceptResult MempoolTx(int64_t vsize, CAmount fees) { @@ -164,9 +182,17 @@ private: } /** Constructor for success case */ - explicit MempoolAcceptResult(std::list<CTransactionRef>&& replaced_txns, int64_t vsize, CAmount fees) + explicit MempoolAcceptResult(std::list<CTransactionRef>&& replaced_txns, + int64_t vsize, + CAmount fees, + CFeeRate effective_feerate, + const std::vector<uint256>& wtxids_fee_calculations) : m_result_type(ResultType::VALID), - m_replaced_transactions(std::move(replaced_txns)), m_vsize{vsize}, m_base_fees(fees) {} + m_replaced_transactions(std::move(replaced_txns)), + m_vsize{vsize}, + m_base_fees(fees), + m_effective_feerate(effective_feerate), + m_wtxids_fee_calculations(wtxids_fee_calculations) {} /** Constructor for already-in-mempool case. It wouldn't replace any transactions. */ explicit MempoolAcceptResult(int64_t vsize, CAmount fees) @@ -190,10 +216,6 @@ struct PackageMempoolAcceptResult * was a package-wide error (see result in m_state), m_tx_results will be empty. */ std::map<const uint256, const MempoolAcceptResult> m_tx_results; - /** Package feerate, defined as the aggregated modified fees divided by the total virtual size - * of all transactions in the package. May be unavailable if some inputs were not available or - * a transaction failure caused validation to terminate early. */ - std::optional<CFeeRate> m_package_feerate; explicit PackageMempoolAcceptResult(PackageValidationState state, std::map<const uint256, const MempoolAcceptResult>&& results) @@ -201,7 +223,7 @@ struct PackageMempoolAcceptResult explicit PackageMempoolAcceptResult(PackageValidationState state, CFeeRate feerate, std::map<const uint256, const MempoolAcceptResult>&& results) - : m_state{state}, m_tx_results(std::move(results)), m_package_feerate{feerate} {} + : m_state{state}, m_tx_results(std::move(results)) {} /** Constructor to create a PackageMempoolAcceptResult from a single MempoolAcceptResult */ explicit PackageMempoolAcceptResult(const uint256& wtxid, const MempoolAcceptResult& result) @@ -743,6 +765,9 @@ private: void UpdateTip(const CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + std::chrono::microseconds m_last_write{0}; + std::chrono::microseconds m_last_flush{0}; + friend ChainstateManager; }; @@ -1066,4 +1091,10 @@ bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep) */ const AssumeutxoData* ExpectedAssumeutxo(const int height, const CChainParams& params); +/** Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30) */ +bool IsBIP30Repeat(const CBlockIndex& block_index); + +/** Identifies blocks which coinbase output was subsequently overwritten in the UTXO set (see BIP30) */ +bool IsBIP30Unspendable(const CBlockIndex& block_index); + #endif // BITCOIN_VALIDATION_H diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 740c39d99d..900cb0474a 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/validationinterface.h b/src/validationinterface.h index a929a3d56b..8c20cc8ffb 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -1,18 +1,18 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 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_VALIDATIONINTERFACE_H #define BITCOIN_VALIDATIONINTERFACE_H +#include <kernel/cs_main.h> #include <primitives/transaction.h> // CTransaction(Ref) #include <sync.h> #include <functional> #include <memory> -extern RecursiveMutex cs_main; class BlockValidationState; class CBlock; class CBlockIndex; diff --git a/src/versionbits.cpp b/src/versionbits.cpp index dc85655028..fa9d1fe9c9 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -195,7 +195,7 @@ protected: public: explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {} - uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; } + uint32_t Mask(const Consensus::Params& params) const { return (uint32_t{1}) << params.vDeployments[id].bit; } }; } // namespace diff --git a/src/versionbits.h b/src/versionbits.h index 9f7ee1b48e..09313d2054 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 3a9d277f65..4ec3ac2189 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -100,7 +100,7 @@ void BerkeleyEnvironment::Close() if (ret != 0) LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) - DbEnv((uint32_t)0).remove(strPath.c_str(), 0); + DbEnv(uint32_t{0}).remove(strPath.c_str(), 0); if (error_file) fclose(error_file); diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index ddab85521b..40a1031c8e 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index b56a6d3aee..cb6f0a1635 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp index a8be6cd83a..e6ba89627c 100644 --- a/src/wallet/coinselection.cpp +++ b/src/wallet/coinselection.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 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 <wallet/coinselection.h> #include <consensus/amount.h> +#include <consensus/consensus.h> #include <policy/feerate.h> #include <util/check.h> #include <util/system.h> @@ -87,13 +88,15 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo std::vector<size_t> best_selection; CAmount best_waste = MAX_MONEY; + bool is_feerate_high = utxo_pool.at(0).fee > utxo_pool.at(0).long_term_fee; + // Depth First search loop for choosing the UTXOs for (size_t curr_try = 0, utxo_pool_index = 0; curr_try < TOTAL_TRIES; ++curr_try, ++utxo_pool_index) { // Conditions for starting a backtrack bool backtrack = false; if (curr_value + curr_available_value < selection_target || // Cannot possibly reach target with the amount remaining in the curr_available_value. curr_value > selection_target + cost_of_change || // Selected value is out of range, go back and try other branch - (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { // Don't select things which we know will be more wasteful if the waste is increasing + (curr_waste > best_waste && is_feerate_high)) { // Don't select things which we know will be more wasteful if the waste is increasing backtrack = true; } else if (curr_value >= selection_target) { // Selected value is within range curr_waste += (curr_value - selection_target); // This is the excess value which is added to the waste for the below comparison @@ -354,6 +357,10 @@ void OutputGroup::Insert(const COutput& output, size_t ancestors, size_t descend // descendants is the count as seen from the top ancestor, not the descendants as seen from the // coin itself; thus, this value is counted as the max, not the sum m_descendants = std::max(m_descendants, descendants); + + if (output.input_bytes > 0) { + m_weight += output.input_bytes * WITNESS_SCALE_FACTOR; + } } bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const @@ -436,28 +443,41 @@ void SelectionResult::Clear() { m_selected_inputs.clear(); m_waste.reset(); + m_weight = 0; } void SelectionResult::AddInput(const OutputGroup& group) { - util::insert(m_selected_inputs, group.m_outputs); + // As it can fail, combine inputs first + InsertInputs(group.m_outputs); m_use_effective = !group.m_subtract_fee_outputs; + + m_weight += group.m_weight; } void SelectionResult::AddInputs(const std::set<COutput>& inputs, bool subtract_fee_outputs) { - util::insert(m_selected_inputs, inputs); + // As it can fail, combine inputs first + InsertInputs(inputs); m_use_effective = !subtract_fee_outputs; + + m_weight += std::accumulate(inputs.cbegin(), inputs.cend(), 0, [](int sum, const auto& coin) { + return sum + std::max(coin.input_bytes, 0) * WITNESS_SCALE_FACTOR; + }); } void SelectionResult::Merge(const SelectionResult& other) { + // As it can fail, combine inputs first + InsertInputs(other.m_selected_inputs); + m_target += other.m_target; m_use_effective |= other.m_use_effective; if (m_algo == SelectionAlgorithm::MANUAL) { m_algo = other.m_algo; } - util::insert(m_selected_inputs, other.m_selected_inputs); + + m_weight += other.m_weight; } const std::set<COutput>& SelectionResult::GetInputSet() const diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index b23dd10867..9ff2011ce3 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,9 +6,12 @@ #define BITCOIN_WALLET_COINSELECTION_H #include <consensus/amount.h> +#include <consensus/consensus.h> #include <policy/feerate.h> #include <primitives/transaction.h> #include <random.h> +#include <util/system.h> +#include <util/check.h> #include <optional> @@ -110,6 +113,8 @@ public: assert(effective_value.has_value()); return effective_value.value(); } + + bool HasEffectiveValue() const { return effective_value.has_value(); } }; /** Parameters for one iteration of Coin Selection. */ @@ -183,6 +188,7 @@ struct CoinEligibilityFilter /** When avoid_reuse=true and there are full groups (OUTPUT_GROUP_MAX_ENTRIES), whether or not to use any partial groups.*/ const bool m_include_partial_groups{false}; + CoinEligibilityFilter() = delete; CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_ancestors) {} CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_descendants) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_descendants) {} CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_descendants, bool include_partial) : conf_mine(conf_mine), conf_theirs(conf_theirs), max_ancestors(max_ancestors), max_descendants(max_descendants), m_include_partial_groups(include_partial) {} @@ -221,6 +227,8 @@ struct OutputGroup /** Indicate that we are subtracting the fee from outputs. * When true, the value that is used for coin selection is the UTXO's real value rather than effective value */ bool m_subtract_fee_outputs{false}; + /** Total weight of the UTXOs in this group. */ + int m_weight{0}; OutputGroup() {} OutputGroup(const CoinSelectionParams& params) : @@ -293,6 +301,19 @@ private: bool m_use_effective{false}; /** The computed waste */ std::optional<CAmount> m_waste; + /** Total weight of the selected inputs */ + int m_weight{0}; + + template<typename T> + void InsertInputs(const T& inputs) + { + // Store sum of combined input sets to check that the results have no shared UTXOs + const size_t expected_count = m_selected_inputs.size() + inputs.size(); + util::insert(m_selected_inputs, inputs); + if (m_selected_inputs.size() != expected_count) { + throw std::runtime_error(STR_INTERNAL_BUG("Shared UTXOs among selection results")); + } + } public: explicit SelectionResult(const CAmount target, SelectionAlgorithm algo) @@ -314,6 +335,12 @@ public: void ComputeAndSetWaste(const CAmount min_viable_change, const CAmount change_cost, const CAmount change_fee); [[nodiscard]] CAmount GetWaste() const; + /** + * Combines the @param[in] other selection result into 'this' selection result. + * + * Important note: + * There must be no shared 'COutput' among the two selection results being combined. + */ void Merge(const SelectionResult& other); /** Get m_selected_inputs */ @@ -345,6 +372,8 @@ public: CAmount GetTarget() const { return m_target; } SelectionAlgorithm GetAlgo() const { return m_algo; } + + int GetWeight() const { return m_weight; } }; std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change); diff --git a/src/wallet/context.cpp b/src/wallet/context.cpp index 3d4bf9d703..39c3b54bf1 100644 --- a/src/wallet/context.cpp +++ b/src/wallet/context.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index 4d325c7557..b776a9c497 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp index f7fee443d0..efa548ad91 100644 --- a/src/wallet/dump.cpp +++ b/src/wallet/dump.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -201,7 +201,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs:: // dummy chain interface bool ret = true; - std::shared_ptr<CWallet> wallet(new CWallet(nullptr /* chain */, name, gArgs, std::move(database)), WalletToolReleaseWallet); + std::shared_ptr<CWallet> wallet(new CWallet(/*chain=*/nullptr, name, gArgs, std::move(database)), WalletToolReleaseWallet); { LOCK(wallet->cs_wallet); DBErrors load_wallet_ret = wallet->LoadWallet(); diff --git a/src/wallet/dump.h b/src/wallet/dump.h index bf683e9843..ff0d94e4b2 100644 --- a/src/wallet/dump.h +++ b/src/wallet/dump.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp index 76de51ac3e..cb861d835e 100644 --- a/src/wallet/external_signer_scriptpubkeyman.cpp +++ b/src/wallet/external_signer_scriptpubkeyman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 6d7bb299cc..bd158b5985 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -293,7 +293,22 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) { LOCK(wallet.cs_wallet); - return wallet.SignTransaction(mtx); + + if (wallet.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) { + // Make a blank psbt + PartiallySignedTransaction psbtx(mtx); + + // First fill transaction with our data without signing, + // so external signers are not asked to sign more than once. + bool complete; + wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */); + const TransactionError err = wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true /* sign */, false /* bip32derivs */); + if (err != TransactionError::OK) return false; + complete = FinalizeAndExtractPSBT(psbtx, mtx); + return complete; + } else { + return wallet.SignTransaction(mtx); + } } Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid) diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h index 760ab58e5c..a96871b26f 100644 --- a/src/wallet/feebumper.h +++ b/src/wallet/feebumper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index 3514d018b7..eda6d319ec 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -84,7 +84,7 @@ CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_contr CFeeRate GetDiscardRate(const CWallet& wallet) { unsigned int highest_target = wallet.chain().estimateMaxBlocks(); - CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, false /* conservative */); + CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, /*conservative=*/false); // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate); // Discard rate must be at least dust relay feerate diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 174c68744c..773f094274 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 9cf2b677e6..68dd3da9b5 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -36,7 +36,7 @@ using interfaces::Chain; using interfaces::FoundBlock; using interfaces::Handler; -using interfaces::MakeHandler; +using interfaces::MakeSignalHandler; using interfaces::Wallet; using interfaces::WalletAddress; using interfaces::WalletBalances; @@ -481,39 +481,39 @@ public: CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; } void remove() override { - RemoveWallet(m_context, m_wallet, false /* load_on_start */); + RemoveWallet(m_context, m_wallet, /*load_on_start=*/false); } bool isLegacy() override { return m_wallet->IsLegacy(); } std::unique_ptr<Handler> handleUnload(UnloadFn fn) override { - return MakeHandler(m_wallet->NotifyUnload.connect(fn)); + return MakeSignalHandler(m_wallet->NotifyUnload.connect(fn)); } std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override { - return MakeHandler(m_wallet->ShowProgress.connect(fn)); + return MakeSignalHandler(m_wallet->ShowProgress.connect(fn)); } std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override { - return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); })); + return MakeSignalHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); })); } std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override { - return MakeHandler(m_wallet->NotifyAddressBookChanged.connect( + return MakeSignalHandler(m_wallet->NotifyAddressBookChanged.connect( [fn](const CTxDestination& address, const std::string& label, bool is_mine, const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); })); } std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override { - return MakeHandler(m_wallet->NotifyTransactionChanged.connect( + return MakeSignalHandler(m_wallet->NotifyTransactionChanged.connect( [fn](const uint256& txid, ChangeType status) { fn(txid, status); })); } std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override { - return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn)); + return MakeSignalHandler(m_wallet->NotifyWatchonlyChanged.connect(fn)); } std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override { - return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn)); + return MakeSignalHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn)); } CWallet* wallet() override { return m_wallet.get(); } diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 6eb0ef5e7a..8c60a2da72 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.h b/src/wallet/load.h index 5c2bbdabe4..0882f7f8ad 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 7fbf2ff8cf..0a75bb6d92 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/receive.h b/src/wallet/receive.h index 9125b1e9aa..87be0fc2ae 100644 --- a/src/wallet/receive.h +++ b/src/wallet/receive.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index 903a569cb9..95e1ba4dd9 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -43,9 +43,7 @@ RPCHelpMan getnewaddress() } // Parse the label first so we don't generate a key if there's an error - std::string label; - if (!request.params[0].isNull()) - label = LabelFromValue(request.params[0]); + const std::string label{LabelFromValue(request.params[0])}; OutputType output_type = pwallet->m_default_address_type; if (!request.params[1].isNull()) { @@ -140,7 +138,7 @@ RPCHelpMan setlabel() throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } - std::string label = LabelFromValue(request.params[1]); + const std::string label{LabelFromValue(request.params[1])}; if (pwallet->IsMine(dest)) { pwallet->SetAddressBook(dest, label, "receive"); @@ -258,9 +256,7 @@ RPCHelpMan addmultisigaddress() LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore); - std::string label; - if (!request.params[2].isNull()) - label = LabelFromValue(request.params[2]); + const std::string label{LabelFromValue(request.params[2])}; int required = request.params[0].getInt<int>(); @@ -662,7 +658,7 @@ RPCHelpMan getaddressesbylabel() LOCK(pwallet->cs_wallet); - std::string label = LabelFromValue(request.params[0]); + const std::string label{LabelFromValue(request.params[0])}; // Find all addresses that have the given label UniValue ret(UniValue::VOBJ); diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 1d2d7d2a10..ab46706084 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -93,6 +93,22 @@ static void RescanWallet(CWallet& wallet, const WalletRescanReserver& reserver, } } +static void EnsureBlockDataFromTime(const CWallet& wallet, int64_t timestamp) +{ + auto& chain{wallet.chain()}; + if (!chain.havePruned()) { + return; + } + + int height{0}; + const bool found{chain.findFirstBlockWithTimeAndHeight(timestamp - TIMESTAMP_WINDOW, 0, FoundBlock().height(height))}; + + uint256 tip_hash{WITH_LOCK(wallet.cs_wallet, return wallet.GetLastBlockHash())}; + if (found && !chain.hasBlocks(tip_hash, height)) { + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Pruned blocks from height %d required to import keys. Use RPC call getblockchaininfo to determine your pruned height.", height)); + } +} + RPCHelpMan importprivkey() { return RPCHelpMan{"importprivkey", @@ -140,9 +156,7 @@ RPCHelpMan importprivkey() EnsureWalletIsUnlocked(*pwallet); std::string strSecret = request.params[0].get_str(); - std::string strLabel; - if (!request.params[1].isNull()) - strLabel = request.params[1].get_str(); + const std::string strLabel{LabelFromValue(request.params[1])}; // Whether to perform rescan after import if (!request.params[2].isNull()) @@ -184,7 +198,7 @@ RPCHelpMan importprivkey() // Add the wpkh script for this key if possible if (pubkey.IsCompressed()) { - pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, 0 /* timestamp */); + pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, /*timestamp=*/0); } } } @@ -233,9 +247,7 @@ RPCHelpMan importaddress() EnsureLegacyScriptPubKeyMan(*pwallet, true); - std::string strLabel; - if (!request.params[1].isNull()) - strLabel = request.params[1].get_str(); + const std::string strLabel{LabelFromValue(request.params[1])}; // Whether to perform rescan after import bool fRescan = true; @@ -273,19 +285,19 @@ RPCHelpMan importaddress() pwallet->MarkDirty(); - pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); + pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, /*have_solving_data=*/false, /*apply_label=*/true, /*timestamp=*/1); } else if (IsHex(request.params[0].get_str())) { std::vector<unsigned char> data(ParseHex(request.params[0].get_str())); CScript redeem_script(data.begin(), data.end()); std::set<CScript> scripts = {redeem_script}; - pwallet->ImportScripts(scripts, 0 /* timestamp */); + pwallet->ImportScripts(scripts, /*timestamp=*/0); if (fP2SH) { scripts.insert(GetScriptForDestination(ScriptHash(redeem_script))); } - pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); + pwallet->ImportScriptPubKeys(strLabel, scripts, /*have_solving_data=*/false, /*apply_label=*/true, /*timestamp=*/1); } else { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); } @@ -426,9 +438,7 @@ RPCHelpMan importpubkey() EnsureLegacyScriptPubKeyMan(*pwallet, true); - std::string strLabel; - if (!request.params[1].isNull()) - strLabel = request.params[1].get_str(); + const std::string strLabel{LabelFromValue(request.params[1])}; // Whether to perform rescan after import bool fRescan = true; @@ -464,9 +474,9 @@ RPCHelpMan importpubkey() pwallet->MarkDirty(); - pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); + pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, /*have_solving_data=*/true, /*apply_label=*/true, /*timestamp=*/1); - pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */); + pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/false, /*timestamp=*/1); } if (fRescan) { @@ -504,13 +514,6 @@ RPCHelpMan importwallet() EnsureLegacyScriptPubKeyMan(*pwallet, true); - if (pwallet->chain().havePruned()) { - // Exit early and print an error. - // If a block is pruned after this check, we will import the key(s), - // but fail the rescan with a generic error. - throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned"); - } - WalletRescanReserver reserver(*pwallet); if (!reserver.reserve()) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait."); @@ -565,15 +568,18 @@ RPCHelpMan importwallet() fLabel = true; } } + nTimeBegin = std::min(nTimeBegin, nTime); keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel)); } else if(IsHex(vstr[0])) { std::vector<unsigned char> vData(ParseHex(vstr[0])); CScript script = CScript(vData.begin(), vData.end()); int64_t birth_time = ParseISO8601DateTime(vstr[1]); + if (birth_time > 0) nTimeBegin = std::min(nTimeBegin, birth_time); scripts.push_back(std::pair<CScript, int64_t>(script, birth_time)); } } file.close(); + EnsureBlockDataFromTime(*pwallet, nTimeBegin); // We now know whether we are importing private keys, so we can error if private keys are disabled if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI @@ -602,8 +608,6 @@ RPCHelpMan importwallet() if (has_label) pwallet->SetAddressBook(PKHash(keyid), label, "receive"); - - nTimeBegin = std::min(nTimeBegin, time); progress++; } for (const auto& script_pair : scripts) { @@ -616,16 +620,13 @@ RPCHelpMan importwallet() fGood = false; continue; } - if (time > 0) { - nTimeBegin = std::min(nTimeBegin, time); - } progress++; } pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI } pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI - RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */); + RescanWallet(*pwallet, reserver, nTimeBegin, /*update=*/false); pwallet->MarkDirty(); if (!fGood) @@ -1163,7 +1164,7 @@ static UniValue ProcessImport(CWallet& wallet, const UniValue& data, const int64 if (internal && data.exists("label")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label"); } - const std::string& label = data.exists("label") ? data["label"].get_str() : ""; + const std::string label{LabelFromValue(data["label"])}; const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false; // Add to keypool only works with privkeys disabled @@ -1329,8 +1330,6 @@ RPCHelpMan importmulti() // the user could have gotten from another RPC command prior to now wallet.BlockUntilSyncedToCurrentChain(); - RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); - EnsureLegacyScriptPubKeyMan(*pwallet, true); const UniValue& requests = mainRequest.params[0]; @@ -1399,7 +1398,7 @@ RPCHelpMan importmulti() } } if (fRescan && fRunScan && requests.size()) { - int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */); + int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, /*update=*/true); pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); if (pwallet->IsAbortingRescan()) { @@ -1457,7 +1456,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c const std::string& descriptor = data["desc"].get_str(); const bool active = data.exists("active") ? data["active"].get_bool() : false; const bool internal = data.exists("internal") ? data["internal"].get_bool() : false; - const std::string& label = data.exists("label") ? data["label"].get_str() : ""; + const std::string label{LabelFromValue(data["label"])}; // Parse descriptor string FlatSigningProvider keys; @@ -1651,8 +1650,6 @@ RPCHelpMan importdescriptors() throw JSONRPCError(RPC_WALLET_ERROR, "importdescriptors is not available for non-descriptor wallets"); } - RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ}); - WalletRescanReserver reserver(*pwallet); if (!reserver.reserve()) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait."); @@ -1691,7 +1688,7 @@ RPCHelpMan importdescriptors() // Rescan the blockchain using the lowest timestamp if (rescan) { - int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, true /* update */); + int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, /*update=*/true); pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); if (pwallet->IsAbortingRescan()) { diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 6021e4bf4f..82642194c2 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp index a68f52a718..fcf25e01d6 100644 --- a/src/wallet/rpc/encrypt.cpp +++ b/src/wallet/rpc/encrypt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp index ae4bd4fbc5..c9fb693482 100644 --- a/src/wallet/rpc/signmessage.cpp +++ b/src/wallet/rpc/signmessage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 0fa693e7e7..f7fd6e479f 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -82,10 +82,10 @@ static UniValue FinishTransaction(const std::shared_ptr<CWallet> pwallet, const PartiallySignedTransaction psbtx(rawTx); // First fill transaction with our data without signing, - // so external signers are not asked sign more than once. + // so external signers are not asked to sign more than once. bool complete; - pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false, true); - const TransactionError err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, true, false)}; + pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true); + const TransactionError err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/true, /*bip32derivs=*/false)}; if (err != TransactionError::OK) { throw JSONRPCTransactionError(err); } @@ -161,7 +161,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original); } const CTransactionRef& tx = res->tx; - wallet.CommitTransaction(tx, std::move(map_value), {} /* orderForm */); + wallet.CommitTransaction(tx, std::move(map_value), /*orderForm=*/{}); if (verbose) { UniValue entry(UniValue::VOBJ); entry.pushKV("txid", tx->GetHash().GetHex()); @@ -314,10 +314,13 @@ RPCHelpMan sendtoaddress() RPCHelpMan sendmany() { return RPCHelpMan{"sendmany", - "\nSend multiple times. Amounts are double-precision floating point numbers." + + "Send multiple times. Amounts are double-precision floating point numbers." + HELP_REQUIRING_PASSPHRASE, { - {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", RPCArgOptions{.oneline_description="\"\""}}, + {"dummy", RPCArg::Type::STR, RPCArg::Default{"\"\""}, "Must be set to \"\" for backwards compatibility.", + RPCArgOptions{ + .oneline_description = "\"\"", + }}, {"amounts", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::NO, "The addresses and amounts", { {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"}, @@ -528,6 +531,8 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, {"replaceable", UniValueType(UniValue::VBOOL)}, {"conf_target", UniValueType(UniValue::VNUM)}, {"estimate_mode", UniValueType(UniValue::VSTR)}, + {"minconf", UniValueType(UniValue::VNUM)}, + {"maxconf", UniValueType(UniValue::VNUM)}, {"input_weights", UniValueType(UniValue::VARR)}, }, true, true); @@ -593,6 +598,22 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, if (options.exists("replaceable")) { coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool(); } + + if (options.exists("minconf")) { + coinControl.m_min_depth = options["minconf"].getInt<int>(); + + if (coinControl.m_min_depth < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative minconf"); + } + } + + if (options.exists("maxconf")) { + coinControl.m_max_depth = options["maxconf"].getInt<int>(); + + if (coinControl.m_max_depth < coinControl.m_min_depth) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coinControl.m_max_depth, coinControl.m_min_depth)); + } + } SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee); } } else { @@ -744,6 +765,8 @@ RPCHelpMan fundrawtransaction() {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n" "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n" "If that happens, you will need to fund the transaction with different inputs and republish it."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."}, + {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."}, {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"}, {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"}, {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."}, @@ -763,18 +786,25 @@ RPCHelpMan fundrawtransaction() }, {"input_weights", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding weights", { - {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, - {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"}, - {"weight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum weight for this input, " - "including the weight of the outpoint and sequence number. " - "Note that serialized signature sizes are not guaranteed to be consistent, " - "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." - "Remember to convert serialized sizes to weight units when necessary."}, + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"}, + {"weight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum weight for this input, " + "including the weight of the outpoint and sequence number. " + "Note that serialized signature sizes are not guaranteed to be consistent, " + "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." + "Remember to convert serialized sizes to weight units when necessary."}, + }, + }, }, }, }, FundTxDoc()), - RPCArgOptions{.oneline_description="options"}}, + RPCArgOptions{ + .skip_type_check = true, + .oneline_description = "options", + }}, {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n" "If iswitness is not present, heuristic tests will be used in decoding.\n" "If true, only witness deserialization will be tried.\n" @@ -806,8 +836,6 @@ RPCHelpMan fundrawtransaction() std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL}); - // parse hex string from parameter CMutableTransaction tx; bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool(); @@ -896,8 +924,6 @@ RPCHelpMan signrawtransactionwithwallet() const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); - CMutableTransaction mtx; if (!DecodeHexTx(mtx, request.params[0].get_str())) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); @@ -993,11 +1019,10 @@ static RPCHelpMan bumpfee_helper(std::string method_name) std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) { + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER) && !want_psbt) { throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead."); } - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ}); uint256 hash(ParseHashV(request.params[0], "txid")); CCoinControl coin_control; @@ -1071,6 +1096,9 @@ static RPCHelpMan bumpfee_helper(std::string method_name) // For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction. if (!want_psbt) { if (!feebumper::SignTransaction(*pwallet, mtx)) { + if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction incomplete. Try psbtbumpfee instead."); + } throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction."); } @@ -1083,7 +1111,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) } else { PartiallySignedTransaction psbtx(mtx); bool complete = false; - const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false /* sign */, true /* bip32derivs */); + const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true); CHECK_NONFATAL(err == TransactionError::OK); CHECK_NONFATAL(!complete); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -1128,7 +1156,7 @@ RPCHelpMan send() }, }, }, - }, + RPCArgOptions{.skip_type_check = true}}, {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n" "\"" + FeeModes("\"\n\"") + "\""}, @@ -1140,6 +1168,8 @@ RPCHelpMan send() {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n" "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n" "If that happens, you will need to fund the transaction with different inputs and republish it."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."}, + {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."}, {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"}, {"change_address", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"}, {"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"}, @@ -1198,15 +1228,6 @@ RPCHelpMan send() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValueType(), // outputs (ARR or OBJ, checked later) - UniValue::VNUM, // conf_target - UniValue::VSTR, // estimate_mode - UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode() - UniValue::VOBJ, // options - }, true - ); - std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; @@ -1263,7 +1284,7 @@ RPCHelpMan sendall() {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch-only.\n" "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n" "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."}, - {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with send_max.", + {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with the send_max, minconf, and maxconf options.", { {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { @@ -1278,6 +1299,8 @@ RPCHelpMan sendall() {"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"}, {"psbt", RPCArg::Type::BOOL, RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."}, {"send_max", RPCArg::Type::BOOL, RPCArg::Default{false}, "When true, only use UTXOs that can pay for their own fees to maximize the output amount. When 'false' (default), no UTXO is left behind. send_max is incompatible with providing specific inputs."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Require inputs with at least this many confirmations."}, + {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Require inputs with at most this many confirmations."}, }, FundTxDoc() ), @@ -1307,15 +1330,6 @@ RPCHelpMan sendall() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - RPCTypeCheck(request.params, { - UniValue::VARR, // recipients - UniValue::VNUM, // conf_target - UniValue::VSTR, // estimate_mode - UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode() - UniValue::VOBJ, // options - }, true - ); - std::shared_ptr<CWallet> const pwallet{GetWalletForJSONRPCRequest(request)}; if (!pwallet) return UniValue::VNULL; // Make sure the results are valid at least up to the most recent block @@ -1352,6 +1366,23 @@ RPCHelpMan sendall() coin_control.fAllowWatchOnly = ParseIncludeWatchonly(options["include_watching"], *pwallet); + if (options.exists("minconf")) { + if (options["minconf"].getInt<int>() < 0) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid minconf (minconf cannot be negative): %s", options["minconf"].getInt<int>())); + } + + coin_control.m_min_depth = options["minconf"].getInt<int>(); + } + + if (options.exists("maxconf")) { + coin_control.m_max_depth = options["maxconf"].getInt<int>(); + + if (coin_control.m_max_depth < coin_control.m_min_depth) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coin_control.m_max_depth, coin_control.m_min_depth)); + } + } + const bool rbf{options.exists("replaceable") ? options["replaceable"].get_bool() : pwallet->m_signal_rbf}; FeeCalculation fee_calc_out; @@ -1373,6 +1404,8 @@ RPCHelpMan sendall() bool send_max{options.exists("send_max") ? options["send_max"].get_bool() : false}; if (options.exists("inputs") && options.exists("send_max")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot combine send_max with specific inputs."); + } else if (options.exists("inputs") && (options.exists("minconf") || options.exists("maxconf"))) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot combine minconf or maxconf with specific inputs."); } else if (options.exists("inputs")) { for (const CTxIn& input : rawTx.vin) { if (pwallet->IsSpent(input.prevout)) { @@ -1511,8 +1544,6 @@ RPCHelpMan walletprocesspsbt() // the user could have gotten from another RPC command prior to now wallet.BlockUntilSyncedToCurrentChain(); - RPCTypeCheck(request.params, {UniValue::VSTR}); - // Unserialize the transaction PartiallySignedTransaction psbtx; std::string error; @@ -1587,7 +1618,7 @@ RPCHelpMan walletcreatefundedpsbt() }, }, }, - }, + RPCArgOptions{.skip_type_check = true}}, {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", Cat<std::vector<RPCArg>>( @@ -1596,6 +1627,8 @@ RPCHelpMan walletcreatefundedpsbt() {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n" "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n" "If that happens, you will need to fund the transaction with different inputs and republish it."}, + {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."}, + {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."}, {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"}, {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"}, {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."}, @@ -1638,24 +1671,12 @@ RPCHelpMan walletcreatefundedpsbt() // the user could have gotten from another RPC command prior to now wallet.BlockUntilSyncedToCurrentChain(); - RPCTypeCheck(request.params, { - UniValue::VARR, - UniValueType(), // ARR or OBJ, checked later - UniValue::VNUM, - UniValue::VOBJ, - UniValue::VBOOL - }, true - ); - UniValue options{request.params[3].isNull() ? UniValue::VOBJ : request.params[3]}; CAmount fee; int change_position; - bool rbf{wallet.m_signal_rbf}; const UniValue &replaceable_arg = options["replaceable"]; - if (!replaceable_arg.isNull()) { - rbf = replaceable_arg.isTrue(); - } + const bool rbf{replaceable_arg.isNull() ? wallet.m_signal_rbf : replaceable_arg.get_bool()}; CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf); CCoinControl coin_control; // Automatically select coins, unless at least one is manually selected. Can @@ -1670,7 +1691,7 @@ RPCHelpMan walletcreatefundedpsbt() // Fill transaction with out data but don't sign bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool(); bool complete = true; - const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs)}; + const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, /*sign=*/false, /*bip32derivs=*/bip32derivs)}; if (err != TransactionError::OK) { throw JSONRPCTransactionError(err); } diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 3c10b47082..f571f8bcb2 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -316,7 +316,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) */ template <class Vec> static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, - Vec& ret, const isminefilter& filter_ismine, const std::string* filter_label, + Vec& ret, const isminefilter& filter_ismine, const std::optional<std::string>& filter_label, bool include_change = false) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { @@ -329,7 +329,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY); // Sent - if (!filter_label) + if (!filter_label.has_value()) { for (const COutputEntry& s : listSent) { @@ -362,7 +362,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM if (address_book_entry) { label = address_book_entry->GetLabel(); } - if (filter_label && label != *filter_label) { + if (filter_label.has_value() && label != filter_label.value()) { continue; } UniValue entry(UniValue::VOBJ); @@ -416,7 +416,6 @@ static const std::vector<RPCResult> TransactionDescriptionString() }}, {RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "The txid if this tx was replaced."}, {RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "The txid if the tx replaces one."}, - {RPCResult::Type::STR, "comment", /*optional=*/true, ""}, {RPCResult::Type::STR, "to", /*optional=*/true, "If a comment to is associated with the transaction."}, {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."}, {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."}, @@ -485,10 +484,10 @@ RPCHelpMan listtransactions() // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); - const std::string* filter_label = nullptr; + std::optional<std::string> filter_label; if (!request.params[0].isNull() && request.params[0].get_str() != "*") { - filter_label = &request.params[0].get_str(); - if (filter_label->empty()) { + filter_label.emplace(LabelFromValue(request.params[0])); + if (filter_label.value().empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\"."); } } @@ -552,6 +551,7 @@ RPCHelpMan listsinceblock() {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n" "(not guaranteed to work on pruned nodes)"}, {"include_change", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also add entries for change outputs.\n"}, + {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Return only incoming transactions paying to addresses with the specified label.\n"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -614,7 +614,7 @@ RPCHelpMan listsinceblock() blockId = ParseHashV(request.params[0], "blockhash"); height = int{}; altheight = int{}; - if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /* ancestor out */ FoundBlock().height(*height), /* blockId out */ FoundBlock().height(*altheight))) { + if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /*ancestor_out=*/FoundBlock().height(*height), /*block1_out=*/FoundBlock().height(*altheight))) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } } @@ -634,6 +634,10 @@ RPCHelpMan listsinceblock() bool include_removed = (request.params[3].isNull() || request.params[3].get_bool()); bool include_change = (!request.params[4].isNull() && request.params[4].get_bool()); + // Only set it if 'label' was provided. + std::optional<std::string> filter_label; + if (!request.params[5].isNull()) filter_label.emplace(LabelFromValue(request.params[5])); + int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1; UniValue transactions(UniValue::VARR); @@ -642,7 +646,7 @@ RPCHelpMan listsinceblock() const CWalletTx& tx = pairWtx.second; if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) { - ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */, /*include_change=*/include_change); + ListTransactions(wallet, tx, 0, true, transactions, filter, filter_label, include_change); } } @@ -659,7 +663,7 @@ RPCHelpMan listsinceblock() if (it != wallet.mapWallet.end()) { // We want all transactions regardless of confirmation count to appear here, // even negative confirmation ones, hence the big negative. - ListTransactions(wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */, /*include_change=*/include_change); + ListTransactions(wallet, it->second, -100000000, true, removed, filter, filter_label, include_change); } } blockId = block.hashPrevBlock; @@ -777,7 +781,7 @@ RPCHelpMan gettransaction() WalletTxToJSON(*pwallet, wtx, entry); UniValue details(UniValue::VARR); - ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */); + ListTransactions(*pwallet, wtx, 0, false, details, filter, /*filter_label=*/std::nullopt); entry.pushKV("details", details); std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags()); diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp index 26270f23ed..31435a69ba 100644 --- a/src/wallet/rpc/util.cpp +++ b/src/wallet/rpc/util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2021 The Bitcoin Core developers +// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -75,7 +75,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques std::string wallet_name; if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { - const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name); + std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name); if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded"); return pwallet; } @@ -132,7 +132,10 @@ const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wal std::string LabelFromValue(const UniValue& value) { - std::string label = value.get_str(); + static const std::string empty_string; + if (value.isNull()) return empty_string; + + const std::string& label{value.get_str()}; if (label == "*") throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); return label; diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h index 87d34f7c11..d5d6ac0dfa 100644 --- a/src/wallet/rpc/util.h +++ b/src/wallet/rpc/util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 675c4a759d..63be95fdd3 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -226,6 +226,14 @@ static RPCHelpMan loadwallet() bilingual_str error; std::vector<bilingual_str> warnings; std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool()); + + { + LOCK(context.wallets_mutex); + if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) { + throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded."); + } + } + std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings); HandleWalletError(wallet, status, error); @@ -437,13 +445,20 @@ static RPCHelpMan unloadwallet() throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded"); } - // Release the "main" shared pointer and prevent further notifications. - // Note that any attempt to load the same wallet would fail until the wallet - // is destroyed (see CheckUniqueFileid). std::vector<bilingual_str> warnings; - std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool()); - if (!RemoveWallet(context, wallet, load_on_start, warnings)) { - throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded"); + { + WalletRescanReserver reserver(*wallet); + if (!reserver.reserve()) { + throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait."); + } + + // Release the "main" shared pointer and prevent further notifications. + // Note that any attempt to load the same wallet would fail until the wallet + // is destroyed (see CheckUniqueFileid). + std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool()); + if (!RemoveWallet(context, wallet, load_on_start, warnings)) { + throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded"); + } } UnloadWallet(std::move(wallet)); @@ -553,8 +568,6 @@ static RPCHelpMan upgradewallet() std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; - RPCTypeCheck(request.params, {UniValue::VNUM}, true); - EnsureWalletIsUnlocked(*pwallet); int version = 0; @@ -622,8 +635,6 @@ RPCHelpMan simulaterawtransaction() if (!rpc_wallet) return UniValue::VNULL; const CWallet& wallet = *rpc_wallet; - RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ}, true); - LOCK(wallet.cs_wallet); UniValue include_watchonly(UniValue::VNULL); @@ -730,7 +741,9 @@ static RPCHelpMan migratewallet() std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; - EnsureWalletIsUnlocked(*wallet); + if (wallet->IsCrypted()) { + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported."); + } WalletContext& context = EnsureWalletContext(request.context); diff --git a/src/wallet/salvage.h b/src/wallet/salvage.h index e4822c3c75..ce918aec2d 100644 --- a/src/wallet/salvage.h +++ b/src/wallet/salvage.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 896ade77dd..d8f34dd2b0 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -2123,7 +2123,7 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size) if (size > 0) { target_size = size; } else { - target_size = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 1); + target_size = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{1}); } // Calculate the new range_end diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index eb77015956..d74388b3e8 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 8c0d56a1cb..e66ff8c97c 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -1,11 +1,14 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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 <algorithm> #include <consensus/amount.h> #include <consensus/validation.h> #include <interfaces/chain.h> +#include <numeric> #include <policy/policy.h> +#include <primitives/transaction.h> #include <script/signingprovider.h> #include <util/check.h> #include <util/fees.h> @@ -102,15 +105,19 @@ void CoinsResult::Clear() { coins.clear(); } -void CoinsResult::Erase(std::set<COutPoint>& preset_coins) +void CoinsResult::Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher>& coins_to_remove) { - for (auto& it : coins) { - auto& vec = it.second; - auto i = std::find_if(vec.begin(), vec.end(), [&](const COutput &c) { return preset_coins.count(c.outpoint);}); - if (i != vec.end()) { - vec.erase(i); - break; - } + for (auto& [type, vec] : coins) { + auto remove_it = std::remove_if(vec.begin(), vec.end(), [&](const COutput& coin) { + // remove it if it's on the set + if (coins_to_remove.count(coin.outpoint) == 0) return false; + + // update cached amounts + total_amount -= coin.txout.nValue; + if (coin.HasEffectiveValue()) total_effective_amount = *total_effective_amount - coin.GetEffectiveValue(); + return true; + }); + vec.erase(remove_it, vec.end()); } } @@ -124,6 +131,11 @@ void CoinsResult::Shuffle(FastRandomContext& rng_fast) void CoinsResult::Add(OutputType type, const COutput& out) { coins[type].emplace_back(out); + total_amount += out.txout.nValue; + if (out.HasEffectiveValue()) { + total_effective_amount = total_effective_amount.has_value() ? + *total_effective_amount + out.GetEffectiveValue() : out.GetEffectiveValue(); + } } static OutputType GetOutputType(TxoutType type, bool is_from_p2sh) @@ -275,7 +287,7 @@ CoinsResult AvailableCoins(const CWallet& wallet, if (coinControl && coinControl->HasSelected() && coinControl->IsSelected(outpoint)) continue; - if (wallet.IsLockedCoin(outpoint)) + if (wallet.IsLockedCoin(outpoint) && params.skip_locked) continue; if (wallet.IsSpent(outpoint)) @@ -321,11 +333,9 @@ CoinsResult AvailableCoins(const CWallet& wallet, result.Add(GetOutputType(type, is_from_p2sh), COutput(outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime(), tx_from_me, feerate)); - // Cache total amount as we go - result.total_amount += output.nValue; // Checks the sum amount of all UTXO's. if (params.min_sum_amount != MAX_MONEY) { - if (result.total_amount >= params.min_sum_amount) { + if (result.GetTotalAmount() >= params.min_sum_amount) { return result; } } @@ -349,70 +359,48 @@ CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl) { LOCK(wallet.cs_wallet); - return AvailableCoins(wallet, coinControl).total_amount; + return AvailableCoins(wallet, coinControl).GetTotalAmount(); } -const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output) +const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint) { AssertLockHeld(wallet.cs_wallet); - const CTransaction* ptx = &tx; - int n = output; + const CWalletTx* wtx{Assert(wallet.GetWalletTx(outpoint.hash))}; + + const CTransaction* ptx = wtx->tx.get(); + int n = outpoint.n; while (OutputIsChange(wallet, ptx->vout[n]) && ptx->vin.size() > 0) { const COutPoint& prevout = ptx->vin[0].prevout; - auto it = wallet.mapWallet.find(prevout.hash); - if (it == wallet.mapWallet.end() || it->second.tx->vout.size() <= prevout.n || - !wallet.IsMine(it->second.tx->vout[prevout.n])) { + const CWalletTx* it = wallet.GetWalletTx(prevout.hash); + if (!it || it->tx->vout.size() <= prevout.n || + !wallet.IsMine(it->tx->vout[prevout.n])) { break; } - ptx = it->second.tx.get(); + ptx = it->tx.get(); n = prevout.n; } return ptx->vout[n]; } -const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint) -{ - AssertLockHeld(wallet.cs_wallet); - return FindNonChangeParentOutput(wallet, *wallet.GetWalletTx(outpoint.hash)->tx, outpoint.n); -} - std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet) { AssertLockHeld(wallet.cs_wallet); std::map<CTxDestination, std::vector<COutput>> result; - for (COutput& coin : AvailableCoinsListUnspent(wallet).All()) { + CCoinControl coin_control; + // Include watch-only for LegacyScriptPubKeyMan wallets without private keys + coin_control.fAllowWatchOnly = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + CoinFilterParams coins_params; + coins_params.only_spendable = false; + coins_params.skip_locked = false; + for (const COutput& coin : AvailableCoins(wallet, &coin_control, /*feerate=*/std::nullopt, coins_params).All()) { CTxDestination address; if ((coin.spendable || (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable)) && ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) { - result[address].emplace_back(std::move(coin)); + result[address].emplace_back(coin); } } - - std::vector<COutPoint> lockedCoins; - wallet.ListLockedCoins(lockedCoins); - // Include watch-only for LegacyScriptPubKeyMan wallets without private keys - const bool include_watch_only = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); - const isminetype is_mine_filter = include_watch_only ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE; - for (const COutPoint& output : lockedCoins) { - auto it = wallet.mapWallet.find(output.hash); - if (it != wallet.mapWallet.end()) { - const auto& wtx = it->second; - int depth = wallet.GetTxDepthInMainChain(wtx); - if (depth >= 0 && output.n < wtx.tx->vout.size() && - wallet.IsMine(wtx.tx->vout[output.n]) == is_mine_filter - ) { - CTxDestination address; - if (ExtractDestination(FindNonChangeParentOutput(wallet, *wtx.tx, output.n).scriptPubKey, address)) { - const auto out = wtx.tx->vout.at(output.n); - result[address].emplace_back( - COutPoint(wtx.GetHash(), output.n), out, depth, CalculateMaximumSignedInputSize(out, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ false, wtx.GetTxTime(), CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)); - } - } - } - } - return result; } @@ -500,33 +488,37 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C return groups_out; } -std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins, +// Returns true if the result contains an error and the message is not empty +static bool HasErrorMsg(const util::Result<SelectionResult>& res) { return !util::ErrorString(res).empty(); } + +util::Result<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins, const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types) { // Run coin selection on each OutputType and compute the Waste Metric std::vector<SelectionResult> results; for (const auto& it : available_coins.coins) { - if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, it.second, coin_selection_params)}) { - results.push_back(*result); - } + auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, it.second, coin_selection_params)}; + // If any specific error message appears here, then something particularly wrong happened. + if (HasErrorMsg(result)) return result; // So let's return the specific error. + // Append the favorable result. + if (result) results.push_back(*result); } // If we have at least one solution for funding the transaction without mixing, choose the minimum one according to waste metric // and return the result if (results.size() > 0) return *std::min_element(results.begin(), results.end()); // If we can't fund the transaction from any individual OutputType, run coin selection one last time - // over all available coins, which would allow mixing - if (allow_mixed_output_types) { - if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.All(), coin_selection_params)}) { - return result; - } + // over all available coins, which would allow mixing. + // If TypesCount() <= 1, there is nothing to mix. + if (allow_mixed_output_types && available_coins.TypesCount() > 1) { + return ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.All(), coin_selection_params); } // Either mixing is not allowed and we couldn't find a solution from any single OutputType, or mixing was allowed and we still couldn't // find a solution using all available coins - return std::nullopt; + return util::Error(); }; -std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, const CoinSelectionParams& coin_selection_params) +util::Result<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, const CoinSelectionParams& coin_selection_params) { // Vector of results. We will choose the best one based on waste. std::vector<SelectionResult> results; @@ -548,26 +540,40 @@ std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, cons results.push_back(*srd_result); } - if (results.size() == 0) { + if (results.empty()) { // No solution found - return std::nullopt; + return util::Error(); + } + + std::vector<SelectionResult> eligible_results; + std::copy_if(results.begin(), results.end(), std::back_inserter(eligible_results), [coin_selection_params](const SelectionResult& result) { + const auto initWeight{coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR}; + return initWeight + result.GetWeight() <= static_cast<int>(MAX_STANDARD_TX_WEIGHT); + }); + + if (eligible_results.empty()) { + return util::Error{_("The inputs size exceeds the maximum weight. " + "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")}; } // Choose the result with the least waste // If the waste is the same, choose the one which spends more inputs. - auto& best_result = *std::min_element(results.begin(), results.end()); + auto& best_result = *std::min_element(eligible_results.begin(), eligible_results.end()); return best_result; } -std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs, - const CAmount& nTargetValue, const CCoinControl& coin_control, - const CoinSelectionParams& coin_selection_params) +util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs, + const CAmount& nTargetValue, const CCoinControl& coin_control, + const CoinSelectionParams& coin_selection_params) { // Deduct preset inputs amount from the search target CAmount selection_target = nTargetValue - pre_set_inputs.total_amount; // Return if automatic coin selection is disabled, and we don't cover the selection target - if (!coin_control.m_allow_other_inputs && selection_target > 0) return std::nullopt; + if (!coin_control.m_allow_other_inputs && selection_target > 0) { + return util::Error{_("The preselected coins total amount does not cover the transaction target. " + "Please allow other inputs to be automatically selected or include more coins manually")}; + } // Return if we can cover the target only with the preset inputs if (selection_target <= 0) { @@ -577,6 +583,14 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a return result; } + // Return early if we cannot cover the target with the wallet's UTXO. + // We use the total effective value if we are not subtracting fee from outputs and 'available_coins' contains the data. + CAmount available_coins_total_amount = coin_selection_params.m_subtract_fee_outputs ? available_coins.GetTotalAmount() : + (available_coins.GetEffectiveTotalAmount().has_value() ? *available_coins.GetEffectiveTotalAmount() : 0); + if (selection_target > available_coins_total_amount) { + return util::Error(); // Insufficient funds + } + // Start wallet Coin Selection procedure auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_control, coin_selection_params); if (!op_selection_result) return op_selection_result; @@ -593,7 +607,12 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a return op_selection_result; } -std::optional<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& value_to_select, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params) +struct SelectionFilter { + CoinEligibilityFilter filter; + bool allow_mixed_output_types{true}; +}; + +util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& value_to_select, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params) { unsigned int limit_ancestor_count = 0; unsigned int limit_descendant_count = 0; @@ -614,54 +633,56 @@ std::optional<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, Coi // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the // transaction at a target feerate. If an attempt fails, more attempts may be made using a more // permissive CoinEligibilityFilter. - std::optional<SelectionResult> res = [&] { - // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six - // confirmations on outputs received from other wallets and only spend confirmed change. - if (auto r1{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 6, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/false)}) return r1; - // Allow mixing only if no solution from any single output type can be found - if (auto r2{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 1, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) return r2; - + util::Result<SelectionResult> res = [&] { + // Place coins eligibility filters on a scope increasing order. + std::vector<SelectionFilter> ordered_filters{ + // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six + // confirmations on outputs received from other wallets and only spend confirmed change. + {CoinEligibilityFilter(1, 6, 0), /*allow_mixed_output_types=*/false}, + {CoinEligibilityFilter(1, 1, 0)}, + }; // Fall back to using zero confirmation change (but with as few ancestors in the mempool as // possible) if we cannot fund the transaction otherwise. if (wallet.m_spend_zero_conf_change) { - if (auto r3{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, 2), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) return r3; - if (auto r4{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), - available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) { - return r4; - } - if (auto r5{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2), - available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) { - return r5; - } + ordered_filters.push_back({CoinEligibilityFilter(0, 1, 2)}); + ordered_filters.push_back({CoinEligibilityFilter(0, 1, std::min(size_t{4}, max_ancestors/3), std::min(size_t{4}, max_descendants/3))}); + ordered_filters.push_back({CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2)}); // If partial groups are allowed, relax the requirement of spending OutputGroups (groups // of UTXOs sent to the same address, which are obviously controlled by a single wallet) // in their entirety. - if (auto r6{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), - available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) { - return r6; - } + ordered_filters.push_back({CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, /*include_partial=*/true)}); // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs // received from other wallets. if (coin_control.m_include_unsafe_inputs) { - if (auto r7{AttemptSelection(wallet, value_to_select, - CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), - available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) { - return r7; - } + ordered_filters.push_back({CoinEligibilityFilter(/*conf_mine=*/0, /*conf_theirs*/0, max_ancestors-1, max_descendants-1, /*include_partial=*/true)}); } // Try with unlimited ancestors/descendants. The transaction will still need to meet // mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but // OutputGroups use heuristics that may overestimate ancestor/descendant counts. if (!fRejectLongChains) { - if (auto r8{AttemptSelection(wallet, value_to_select, - CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */), - available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) { - return r8; - } + ordered_filters.push_back({CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), + std::numeric_limits<uint64_t>::max(), + /*include_partial=*/true)}); + } + } + + // Walk-through the filters until the solution gets found. + // If no solution is found, return the first detailed error (if any). + // future: add "error level" so the worst one can be picked instead. + std::vector<util::Result<SelectionResult>> res_detailed_errors; + for (const auto& select_filter : ordered_filters) { + if (auto res{AttemptSelection(wallet, value_to_select, select_filter.filter, available_coins, + coin_selection_params, select_filter.allow_mixed_output_types)}) { + return res; // result found + } else { + // If any specific error message appears here, then something particularly wrong might have happened. + // Save the error and continue the selection process. So if no solutions gets found, we can return + // the detailed error to the upper layers. + if (HasErrorMsg(res)) res_detailed_errors.emplace_back(res); } } // Coin Selection failed. - return std::optional<SelectionResult>(); + return res_detailed_errors.empty() ? util::Result<SelectionResult>(util::Error()) : res_detailed_errors.front(); }(); return res; @@ -751,7 +772,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( AssertLockHeld(wallet.cs_wallet); // out variables, to be packed into returned result structure - CAmount nFeeRet; int nChangePosInOut = change_pos; FastRandomContext rng_fast; @@ -852,19 +872,16 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( const auto change_spend_fee = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size); coin_selection_params.min_viable_change = std::max(change_spend_fee + 1, dust); + // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size) + coin_selection_params.tx_noinputs_size = 10 + GetSizeOfCompactSize(vecSend.size()); // bytes for output count + // vouts to the payees - if (!coin_selection_params.m_subtract_fee_outputs) { - coin_selection_params.tx_noinputs_size = 10; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size) - coin_selection_params.tx_noinputs_size += GetSizeOfCompactSize(vecSend.size()); // bytes for output count - } for (const auto& recipient : vecSend) { CTxOut txout(recipient.nAmount, recipient.scriptPubKey); // Include the fee cost for outputs. - if (!coin_selection_params.m_subtract_fee_outputs) { - coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION); - } + coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION); if (IsDust(txout, wallet.chain().relayDustFee())) { return util::Error{_("Transaction amount too small")}; @@ -873,7 +890,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( } // Include the fees for things that aren't inputs, excluding the change output - const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size); + const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.m_subtract_fee_outputs ? 0 : coin_selection_params.tx_noinputs_size); CAmount selection_target = recipients_sum + not_input_fees; // Fetch manually selected coins @@ -892,13 +909,16 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( } // Choose coins to use - std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, preset_inputs, /*nTargetValue=*/selection_target, coin_control, coin_selection_params); - if (!result) { - return util::Error{_("Insufficient funds")}; + auto select_coins_res = SelectCoins(wallet, available_coins, preset_inputs, /*nTargetValue=*/selection_target, coin_control, coin_selection_params); + if (!select_coins_res) { + // 'SelectCoins' either returns a specific error message or, if empty, means a general "Insufficient funds". + const bilingual_str& err = util::ErrorString(select_coins_res); + return util::Error{err.empty() ?_("Insufficient funds") : err}; } - TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->GetAlgo()).c_str(), result->GetTarget(), result->GetWaste(), result->GetSelectedValue()); + const SelectionResult& result = *select_coins_res; + TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result.GetAlgo()).c_str(), result.GetTarget(), result.GetWaste(), result.GetSelectedValue()); - const CAmount change_amount = result->GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee); + const CAmount change_amount = result.GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee); if (change_amount > 0) { CTxOut newTxOut(change_amount, scriptChange); if (nChangePosInOut == -1) { @@ -913,7 +933,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( } // Shuffle selected coins and fill in final vin - std::vector<COutput> selected_coins = result->GetShuffledInputVector(); + std::vector<COutput> selected_coins = result.GetShuffledInputVector(); // The sequence number is set to non-maxint so that DiscourageFeeSniping // works. @@ -936,22 +956,28 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( return util::Error{_("Missing solving data for estimating transaction size")}; } CAmount fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes); - nFeeRet = result->GetSelectedValue() - recipients_sum - change_amount; + const CAmount output_value = CalculateOutputValue(txNew); + Assume(recipients_sum + change_amount == output_value); + CAmount current_fee = result.GetSelectedValue() - output_value; - // The only time that fee_needed should be less than the amount available for fees is when - // we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug. - assert(coin_selection_params.m_subtract_fee_outputs || fee_needed <= nFeeRet); + // Sanity check that the fee cannot be negative as that means we have more output value than input value + if (current_fee < 0) { + return util::Error{Untranslated(STR_INTERNAL_BUG("Fee paid < 0"))}; + } // If there is a change output and we overpay the fees then increase the change to match the fee needed - if (nChangePosInOut != -1 && fee_needed < nFeeRet) { + if (nChangePosInOut != -1 && fee_needed < current_fee) { auto& change = txNew.vout.at(nChangePosInOut); - change.nValue += nFeeRet - fee_needed; - nFeeRet = fee_needed; + change.nValue += current_fee - fee_needed; + current_fee = result.GetSelectedValue() - CalculateOutputValue(txNew); + if (fee_needed != current_fee) { + return util::Error{Untranslated(STR_INTERNAL_BUG("Change adjustment: Fee needed != fee paid"))}; + } } // Reduce output values for subtractFeeFromAmount if (coin_selection_params.m_subtract_fee_outputs) { - CAmount to_reduce = fee_needed - nFeeRet; + CAmount to_reduce = fee_needed - current_fee; int i = 0; bool fFirst = true; for (const auto& recipient : vecSend) @@ -982,7 +1008,16 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( } ++i; } - nFeeRet = fee_needed; + current_fee = result.GetSelectedValue() - CalculateOutputValue(txNew); + if (fee_needed != current_fee) { + return util::Error{Untranslated(STR_INTERNAL_BUG("SFFO: Fee needed != fee paid"))}; + } + } + + // fee_needed should now always be less than or equal to the current fees that we pay. + // If it is not, it is a bug. + if (fee_needed > current_fee) { + return util::Error{Untranslated(STR_INTERNAL_BUG("Fee needed > fee paid"))}; } // Give up if change keypool ran out and change is required @@ -1004,7 +1039,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( return util::Error{_("Transaction too large")}; } - if (nFeeRet > wallet.m_default_max_tx_fee) { + if (current_fee > wallet.m_default_max_tx_fee) { return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)}; } @@ -1020,14 +1055,14 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( reservedest.KeepDestination(); wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", - nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, + current_fee, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, feeCalc.est.pass.start, feeCalc.est.pass.end, (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0, feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool, feeCalc.est.fail.start, feeCalc.est.fail.end, (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0, feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool); - return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc); + return CreatedTransactionResult(tx, current_fee, nChangePosInOut, feeCalc); } util::Result<CreatedTransactionResult> CreateTransaction( diff --git a/src/wallet/spend.h b/src/wallet/spend.h index ba2c6638c8..d8da556d29 100644 --- a/src/wallet/spend.h +++ b/src/wallet/spend.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -46,13 +46,21 @@ struct CoinsResult { /** The following methods are provided so that CoinsResult can mimic a vector, * i.e., methods can work with individual OutputType vectors or on the entire object */ size_t Size() const; + /** Return how many different output types this struct stores */ + size_t TypesCount() const { return coins.size(); } void Clear(); - void Erase(std::set<COutPoint>& preset_coins); + void Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher>& coins_to_remove); void Shuffle(FastRandomContext& rng_fast); void Add(OutputType type, const COutput& out); - /** Sum of all available coins */ + CAmount GetTotalAmount() { return total_amount; } + std::optional<CAmount> GetEffectiveTotalAmount() {return total_effective_amount; } + +private: + /** Sum of all available coins raw value */ CAmount total_amount{0}; + /** Sum of all available coins effective value (each output value minus fees required to spend it) */ + std::optional<CAmount> total_effective_amount{0}; }; struct CoinFilterParams { @@ -68,6 +76,8 @@ struct CoinFilterParams { bool only_spendable{true}; // By default, do not include immature coinbase outputs bool include_immature_coinbase{false}; + // By default, skip locked UTXOs + bool skip_locked{true}; }; /** @@ -89,7 +99,6 @@ CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinContr /** * Find non-change parent output. */ -const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); /** @@ -111,9 +120,11 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C * param@[in] coin_selection_params Parameters for the coin selection * param@[in] allow_mixed_output_types Relax restriction that SelectionResults must be of the same OutputType * returns If successful, a SelectionResult containing the input set - * If failed, a nullopt + * If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds") + * or (2) an specific error message if there was something particularly wrong (e.g. a selection + * result that surpassed the tx max weight size). */ -std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins, +util::Result<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins, const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types); /** @@ -127,9 +138,11 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm * param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering * param@[in] coin_selection_params Parameters for the coin selection * returns If successful, a SelectionResult containing the input set - * If failed, a nullopt + * If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds") + * or (2) an specific error message if there was something particularly wrong (e.g. a selection + * result that surpassed the tx max weight size). */ -std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, +util::Result<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, const CoinSelectionParams& coin_selection_params); // User manually selected inputs that must be part of the transaction @@ -167,18 +180,20 @@ util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const * param@[in] coin_selection_params Parameters for this coin selection such as feerates, whether to avoid partial spends, * and whether to subtract the fee from the outputs. * returns If successful, a SelectionResult containing the selected coins - * If failed, a nullopt. + * If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds") + * or (2) an specific error message if there was something particularly wrong (e.g. a selection + * result that surpassed the tx max weight size). */ -std::optional<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control, +util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); /** * Select all coins from coin_control, and if coin_control 'm_allow_other_inputs=true', call 'AutomaticCoinSelection' to * select a set of coins such that nTargetValue - pre_set_inputs.total_amount is met. */ -std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs, - const CAmount& nTargetValue, const CCoinControl& coin_control, - const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); +util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs, + const CAmount& nTargetValue, const CCoinControl& coin_control, + const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); struct CreatedTransactionResult { diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 053fb8f983..f2b9909851 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers +// Copyright (c) 2020-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 47b7ebb0ec..7680bdd07b 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/availablecoins_tests.cpp b/src/wallet/test/availablecoins_tests.cpp deleted file mode 100644 index 2427a343d5..0000000000 --- a/src/wallet/test/availablecoins_tests.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2022 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or https://www.opensource.org/licenses/mit-license.php. - -#include <validation.h> -#include <wallet/coincontrol.h> -#include <wallet/spend.h> -#include <wallet/test/util.h> -#include <wallet/test/wallet_test_fixture.h> - -#include <boost/test/unit_test.hpp> - -namespace wallet { -BOOST_FIXTURE_TEST_SUITE(availablecoins_tests, WalletTestingSetup) -class AvailableCoinsTestingSetup : public TestChain100Setup -{ -public: - AvailableCoinsTestingSetup() - { - CreateAndProcessBlock({}, {}); - wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey); - } - - ~AvailableCoinsTestingSetup() - { - wallet.reset(); - } - CWalletTx& AddTx(CRecipient recipient) - { - CTransactionRef tx; - CCoinControl dummy; - { - constexpr int RANDOM_CHANGE_POSITION = -1; - auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy); - BOOST_CHECK(res); - tx = res->tx; - } - wallet->CommitTransaction(tx, {}, {}); - CMutableTransaction blocktx; - { - LOCK(wallet->cs_wallet); - blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx); - } - CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - - LOCK(wallet->cs_wallet); - LOCK(m_node.chainman->GetMutex()); - wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, m_node.chainman->ActiveChain().Tip()->GetBlockHash()); - auto it = wallet->mapWallet.find(tx->GetHash()); - BOOST_CHECK(it != wallet->mapWallet.end()); - it->second.m_state = TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*index=*/1}; - return it->second; - } - - std::unique_ptr<CWallet> wallet; -}; - -BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, AvailableCoinsTestingSetup) -{ - CoinsResult available_coins; - util::Result<CTxDestination> dest{util::Error{}}; - LOCK(wallet->cs_wallet); - - // Verify our wallet has one usable coinbase UTXO before starting - // This UTXO is a P2PK, so it should show up in the Other bucket - available_coins = AvailableCoins(*wallet); - BOOST_CHECK_EQUAL(available_coins.Size(), 1U); - BOOST_CHECK_EQUAL(available_coins.coins[OutputType::UNKNOWN].size(), 1U); - - // We will create a self transfer for each of the OutputTypes and - // verify it is put in the correct bucket after running GetAvailablecoins - // - // For each OutputType, We expect 2 UTXOs in our wallet following the self transfer: - // 1. One UTXO as the recipient - // 2. One UTXO from the change, due to payment address matching logic - - // Bech32m - dest = wallet->GetNewDestination(OutputType::BECH32M, ""); - BOOST_ASSERT(dest); - AddTx(CRecipient{{GetScriptForDestination(*dest)}, 1 * COIN, /*fSubtractFeeFromAmount=*/true}); - available_coins = AvailableCoins(*wallet); - BOOST_CHECK_EQUAL(available_coins.coins[OutputType::BECH32M].size(), 2U); - - // Bech32 - dest = wallet->GetNewDestination(OutputType::BECH32, ""); - BOOST_ASSERT(dest); - AddTx(CRecipient{{GetScriptForDestination(*dest)}, 2 * COIN, /*fSubtractFeeFromAmount=*/true}); - available_coins = AvailableCoins(*wallet); - BOOST_CHECK_EQUAL(available_coins.coins[OutputType::BECH32].size(), 2U); - - // P2SH-SEGWIT - dest = wallet->GetNewDestination(OutputType::P2SH_SEGWIT, ""); - BOOST_ASSERT(dest); - AddTx(CRecipient{{GetScriptForDestination(*dest)}, 3 * COIN, /*fSubtractFeeFromAmount=*/true}); - available_coins = AvailableCoins(*wallet); - BOOST_CHECK_EQUAL(available_coins.coins[OutputType::P2SH_SEGWIT].size(), 2U); - - // Legacy (P2PKH) - dest = wallet->GetNewDestination(OutputType::LEGACY, ""); - BOOST_ASSERT(dest); - AddTx(CRecipient{{GetScriptForDestination(*dest)}, 4 * COIN, /*fSubtractFeeFromAmount=*/true}); - available_coins = AvailableCoins(*wallet); - BOOST_CHECK_EQUAL(available_coins.coins[OutputType::LEGACY].size(), 2U); -} - -BOOST_AUTO_TEST_SUITE_END() -} // namespace wallet diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index f9c8c8ee9d..2e12b5b1d4 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -1,9 +1,10 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 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 <consensus/amount.h> #include <node/context.h> +#include <policy/policy.h> #include <primitives/transaction.h> #include <random.h> #include <test/util/setup_common.h> @@ -83,7 +84,7 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun assert(ret.second); CWalletTx& wtx = (*ret.first).second; const auto& txout = wtx.tx->vout.at(nInput); - available_coins.coins[OutputType::BECH32].emplace_back(COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate); + available_coins.Add(OutputType::BECH32, {COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate}); } /** Check if SelectionResult a is equivalent to SelectionResult b. @@ -120,9 +121,9 @@ static CAmount make_hard_case(int utxos, std::vector<COutput>& utxo_pool) utxo_pool.clear(); CAmount target = 0; for (int i = 0; i < utxos; ++i) { - target += (CAmount)1 << (utxos+i); - add_coin((CAmount)1 << (utxos+i), 2*i, utxo_pool); - add_coin(((CAmount)1 << (utxos+i)) + ((CAmount)1 << (utxos-1-i)), 2*i + 1, utxo_pool); + target += CAmount{1} << (utxos+i); + add_coin(CAmount{1} << (utxos+i), 2*i, utxo_pool); + add_coin((CAmount{1} << (utxos+i)) + (CAmount{1} << (utxos-1-i)), 2*i + 1, utxo_pool); } return target; } @@ -301,6 +302,8 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_output_size); coin_selection_params_bnb.m_cost_of_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size) + coin_selection_params_bnb.m_change_fee; coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size); + coin_selection_params_bnb.m_subtract_fee_outputs = true; + { std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase()); wallet->LoadWallet(); @@ -318,7 +321,6 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) available_coins.Clear(); add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate); available_coins.All().at(0).input_bytes = 40; - coin_selection_params_bnb.m_subtract_fee_outputs = true; const auto result9 = SelectCoinsBnB(GroupCoins(available_coins.All()), 1 * CENT, coin_selection_params_bnb.m_cost_of_change); BOOST_CHECK(result9); BOOST_CHECK_EQUAL(result9->GetSelectedValue(), 1 * CENT); @@ -342,7 +344,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) coin_control.Select(select_coin.outpoint); PreSelectedInputs selected_input; selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs); - available_coins.coins[OutputType::BECH32].erase(available_coins.coins[OutputType::BECH32].begin()); + available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint}); coin_selection_params_bnb.m_effective_feerate = CFeeRate(0); const auto result10 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb); BOOST_CHECK(result10); @@ -402,7 +404,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) coin_control.Select(select_coin.outpoint); PreSelectedInputs selected_input; selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs); - available_coins.coins[OutputType::BECH32].erase(++available_coins.coins[OutputType::BECH32].begin()); + available_coins.Erase({(++available_coins.coins[OutputType::BECH32].begin())->outpoint}); const auto result13 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb); BOOST_CHECK(EquivalentResult(expected_result, *result13)); } @@ -930,6 +932,124 @@ BOOST_AUTO_TEST_CASE(effective_value_test) BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1 } +static util::Result<SelectionResult> select_coins(const CAmount& target, const CoinSelectionParams& cs_params, const CCoinControl& cc, std::function<CoinsResult(CWallet&)> coin_setup, interfaces::Chain* chain, const ArgsManager& args) +{ + std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(chain, "", args, CreateMockWalletDatabase()); + wallet->LoadWallet(); + LOCK(wallet->cs_wallet); + wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); + wallet->SetupDescriptorScriptPubKeyMans(); + + auto available_coins = coin_setup(*wallet); + + auto result = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/ {}, target, cc, cs_params); + if (result) { + const auto signedTxSize = 10 + 34 + 68 * result->GetInputSet().size(); // static header size + output size + inputs size (P2WPKH) + BOOST_CHECK_LE(signedTxSize * WITNESS_SCALE_FACTOR, MAX_STANDARD_TX_WEIGHT); + + BOOST_CHECK_GE(result->GetSelectedValue(), target); + } + return result; +} + +static bool has_coin(const CoinSet& set, CAmount amount) +{ + return std::any_of(set.begin(), set.end(), [&](const auto& coin) { return coin.GetEffectiveValue() == amount; }); +} + +BOOST_AUTO_TEST_CASE(check_max_weight) +{ + const CAmount target = 49.5L * COIN; + CCoinControl cc; + + FastRandomContext rand; + CoinSelectionParams cs_params{ + rand, + /*change_output_size=*/34, + /*change_spend_size=*/68, + /*min_change_target=*/CENT, + /*effective_feerate=*/CFeeRate(0), + /*long_term_feerate=*/CFeeRate(0), + /*discard_feerate=*/CFeeRate(0), + /*tx_noinputs_size=*/10 + 34, // static header size + output size + /*avoid_partial=*/false, + }; + + auto chain{m_node.chain.get()}; + + { + // Scenario 1: + // The actor starts with 1x 50.0 BTC and 1515x 0.033 BTC (~100.0 BTC total) unspent outputs + // Then tries to spend 49.5 BTC + // The 50.0 BTC output should be selected, because the transaction would otherwise be too large + + // Perform selection + + const auto result = select_coins( + target, cs_params, cc, [&](CWallet& wallet) { + CoinsResult available_coins; + for (int j = 0; j < 1515; ++j) { + add_coin(available_coins, wallet, CAmount(0.033 * COIN), CFeeRate(0), 144, false, 0, true); + } + + add_coin(available_coins, wallet, CAmount(50 * COIN), CFeeRate(0), 144, false, 0, true); + return available_coins; + }, + chain, m_args); + + BOOST_CHECK(result); + BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(50 * COIN))); + } + + { + // Scenario 2: + + // The actor starts with 400x 0.0625 BTC and 2000x 0.025 BTC (75.0 BTC total) unspent outputs + // Then tries to spend 49.5 BTC + // A combination of coins should be selected, such that the created transaction is not too large + + // Perform selection + const auto result = select_coins( + target, cs_params, cc, [&](CWallet& wallet) { + CoinsResult available_coins; + for (int j = 0; j < 400; ++j) { + add_coin(available_coins, wallet, CAmount(0.0625 * COIN), CFeeRate(0), 144, false, 0, true); + } + for (int j = 0; j < 2000; ++j) { + add_coin(available_coins, wallet, CAmount(0.025 * COIN), CFeeRate(0), 144, false, 0, true); + } + return available_coins; + }, + chain, m_args); + + BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(0.0625 * COIN))); + BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(0.025 * COIN))); + } + + { + // Scenario 3: + + // The actor starts with 1515x 0.033 BTC (49.995 BTC total) unspent outputs + // No results should be returned, because the transaction would be too large + + // Perform selection + const auto result = select_coins( + target, cs_params, cc, [&](CWallet& wallet) { + CoinsResult available_coins; + for (int j = 0; j < 1515; ++j) { + add_coin(available_coins, wallet, CAmount(0.033 * COIN), CFeeRate(0), 144, false, 0, true); + } + return available_coins; + }, + chain, m_args); + + // No results + // 1515 inputs * 68 bytes = 103,020 bytes + // 103,020 bytes * 4 = 412,080 weight, which is above the MAX_STANDARD_TX_WEIGHT of 400,000 + BOOST_CHECK(!result); + } +} + BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test) { // Test that the effective value is used to check whether preset inputs provide sufficient funds when subtract_fee_outputs is not used. @@ -974,11 +1094,51 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test) cc.SelectExternal(output.outpoint, output.txout); const auto preset_inputs = *Assert(FetchSelectedInputs(*wallet, cc, cs_params)); - available_coins.coins[OutputType::BECH32].erase(available_coins.coins[OutputType::BECH32].begin()); + available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint}); const auto result = SelectCoins(*wallet, available_coins, preset_inputs, target, cc, cs_params); BOOST_CHECK(!result); } +BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup) +{ + // Test case to verify CoinsResult object sanity. + CoinsResult available_coins; + { + std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase()); + BOOST_CHECK_EQUAL(dummyWallet->LoadWallet(), DBErrors::LOAD_OK); + LOCK(dummyWallet->cs_wallet); + dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); + dummyWallet->SetupDescriptorScriptPubKeyMans(); + + // Add some coins to 'available_coins' + for (int i=0; i<10; i++) { + add_coin(available_coins, *dummyWallet, 1 * COIN); + } + } + + { + // First test case, check that 'CoinsResult::Erase' function works as expected. + // By trying to erase two elements from the 'available_coins' object. + std::unordered_set<COutPoint, SaltedOutpointHasher> outs_to_remove; + const auto& coins = available_coins.All(); + for (int i = 0; i < 2; i++) { + outs_to_remove.emplace(coins[i].outpoint); + } + available_coins.Erase(outs_to_remove); + + // Check that the elements were actually removed. + const auto& updated_coins = available_coins.All(); + for (const auto& out: outs_to_remove) { + auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&out](const COutput &coin) { + return coin.outpoint == out; + }); + BOOST_CHECK(it == updated_coins.end()); + } + // And verify that no extra element were removed + BOOST_CHECK_EQUAL(available_coins.Size(), 8); + } +} + BOOST_AUTO_TEST_SUITE_END() } // namespace wallet diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index f61808c549..7e26656b86 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp index 5e9cd4001b..de381a5ec9 100644 --- a/src/wallet/test/fuzz/notifications.cpp +++ b/src/wallet/test/fuzz/notifications.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/fuzz/parse_iso8601.cpp b/src/wallet/test/fuzz/parse_iso8601.cpp index 5be248c2fb..c1bafc1073 100644 --- a/src/wallet/test/fuzz/parse_iso8601.cpp +++ b/src/wallet/test/fuzz/parse_iso8601.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 The Bitcoin Core developers +// Copyright (c) 2019-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp index 8eb7689c94..60b1bab8ac 100644 --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index fb0a07e181..3dbc91fc68 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp index 68146eb079..151b09d2a6 100644 --- a/src/wallet/test/ismine_tests.cpp +++ b/src/wallet/test/ismine_tests.cpp @@ -1,8 +1,9 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 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 <key.h> +#include <key_io.h> #include <node/context.h> #include <script/script.h> #include <script/standard.h> @@ -16,6 +17,25 @@ namespace wallet { BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup) +wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success) +{ + keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); + + FlatSigningProvider keys; + std::string error; + std::unique_ptr<Descriptor> parsed_desc = Parse(desc_str, keys, error, false); + BOOST_CHECK(success == (parsed_desc != nullptr)); + if (!success) return nullptr; + + const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1; + + WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index); + + LOCK(keystore.cs_wallet); + + return Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false)); +}; + BOOST_AUTO_TEST_CASE(ismine_standard) { CKey keys[2]; @@ -33,7 +53,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) CScript scriptPubKey; isminetype result; - // P2PK compressed + // P2PK compressed - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -52,7 +72,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2PK uncompressed + // P2PK compressed - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "pk(" + EncodeSecret(keys[0]) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + scriptPubKey = GetScriptForRawPubKey(pubkeys[0]); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2PK uncompressed - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -71,7 +103,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2PKH compressed + // P2PK uncompressed - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "pk(" + EncodeSecret(uncompressedKey) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2PKH compressed - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -90,7 +134,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2PKH uncompressed + // P2PKH compressed - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "pkh(" + EncodeSecret(keys[0]) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0])); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2PKH uncompressed - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -109,7 +165,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2SH + // P2PKH uncompressed - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "pkh(" + EncodeSecret(uncompressedKey) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2SH - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -136,7 +204,20 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // (P2PKH inside) P2SH inside P2SH (invalid) + // P2SH - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "sh(pkh(" + EncodeSecret(keys[0]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // (P2PKH inside) P2SH inside P2SH (invalid) - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -155,7 +236,16 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // (P2PKH inside) P2SH inside P2WSH (invalid) + // (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "sh(sh(" + EncodeSecret(keys[0]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, false); + BOOST_CHECK_EQUAL(spk_manager, nullptr); + } + + // (P2PKH inside) P2SH inside P2WSH (invalid) - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -174,7 +264,16 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // P2WPKH inside P2WSH (invalid) + // (P2PKH inside) P2SH inside P2WSH (invalid) - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "wsh(sh(" + EncodeSecret(keys[0]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, false); + BOOST_CHECK_EQUAL(spk_manager, nullptr); + } + + // P2WPKH inside P2WSH (invalid) - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -191,7 +290,16 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // (P2PKH inside) P2WSH inside P2WSH (invalid) + // P2WPKH inside P2WSH (invalid) - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "wsh(wpkh(" + EncodeSecret(keys[0]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, false); + BOOST_CHECK_EQUAL(spk_manager, nullptr); + } + + // (P2PKH inside) P2WSH inside P2WSH (invalid) - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -210,7 +318,16 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // P2WPKH compressed + // (P2PKH inside) P2WSH inside P2WSH (invalid) - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "wsh(wsh(" + EncodeSecret(keys[0]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, false); + BOOST_CHECK_EQUAL(spk_manager, nullptr); + } + + // P2WPKH compressed - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -226,7 +343,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2WPKH uncompressed + // P2WPKH compressed - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "wpkh(" + EncodeSecret(keys[0]) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2WPKH uncompressed - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -247,7 +376,16 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // scriptPubKey multisig + // P2WPKH uncompressed (invalid) - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "wpkh(" + EncodeSecret(uncompressedKey) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, false); + BOOST_CHECK_EQUAL(spk_manager, nullptr); + } + + // scriptPubKey multisig - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -282,7 +420,19 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // P2SH multisig + // scriptPubKey multisig - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + std::string desc_str = "multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2SH multisig - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -305,7 +455,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2WSH multisig with compressed keys + // P2SH multisig - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + + std::string desc_str = "sh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2WSH multisig with compressed keys - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -334,7 +498,21 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } - // P2WSH multisig with uncompressed key + // P2WSH multisig with compressed keys - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + + std::string desc_str = "wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + CScript redeemScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]}); + scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(redeemScript)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // P2WSH multisig with uncompressed key - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -363,7 +541,17 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 0); } - // P2WSH multisig wrapped in P2SH + // P2WSH multisig with uncompressed key (invalid) - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + + std::string desc_str = "wsh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, false); + BOOST_CHECK_EQUAL(spk_manager, nullptr); + } + + // P2WSH multisig wrapped in P2SH - Legacy { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); keystore.SetupLegacyScriptPubKeyMan(); @@ -393,6 +581,83 @@ BOOST_AUTO_TEST_CASE(ismine_standard) BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->GetScriptPubKeys().count(scriptPubKey) == 1); } + // P2WSH multisig wrapped in P2SH - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + + std::string desc_str = "sh(wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + ")))"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]}); + CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + + // Combo - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + + std::string desc_str = "combo(" + EncodeSecret(keys[0]) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + // Test P2PK + result = spk_manager->IsMine(GetScriptForRawPubKey(pubkeys[0])); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + + // Test P2PKH + result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0]))); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + + // Test P2SH (combo descriptor does not describe P2SH) + CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + + // Test P2WPKH + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + + // P2SH-P2WPKH output + redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + + // Test P2TR (combo descriptor does not describe P2TR) + XOnlyPubKey xpk(pubkeys[0]); + Assert(xpk.IsFullyValid()); + TaprootBuilder builder; + builder.Finalize(xpk); + WitnessV1Taproot output = builder.GetOutput(); + scriptPubKey = GetScriptForDestination(output); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + } + + // Taproot - Descriptor + { + CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); + + std::string desc_str = "tr(" + EncodeSecret(keys[0]) + ")"; + + auto spk_manager = CreateDescriptor(keystore, desc_str, true); + + XOnlyPubKey xpk(pubkeys[0]); + Assert(xpk.IsFullyValid()); + TaprootBuilder builder; + builder.Finalize(xpk); + WitnessV1Taproot output = builder.GetOutput(); + scriptPubKey = GetScriptForDestination(output); + result = spk_manager->IsMine(scriptPubKey); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + } + // OP_RETURN { CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase()); diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 62053ae8d2..9510f28282 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp index a75b014870..364cc5c20b 100644 --- a/src/wallet/test/spend_tests.cpp +++ b/src/wallet/test/spend_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,7 +26,7 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup) // leftover input amount which would have been change to the recipient // instead of the miner. auto check_tx = [&wallet](CAmount leftover_input_amount) { - CRecipient recipient{GetScriptForRawPubKey({}), 50 * COIN - leftover_input_amount, true /* subtract fee */}; + CRecipient recipient{GetScriptForRawPubKey({}), 50 * COIN - leftover_input_amount, /*subtract_fee=*/true}; constexpr int RANDOM_CHANGE_POSITION = -1; CCoinControl coin_control; coin_control.m_feerate.emplace(10000); @@ -112,5 +112,50 @@ BOOST_FIXTURE_TEST_CASE(FillInputToWeightTest, BasicTestingSetup) // Note: We don't test the next boundary because of memory allocation constraints. } +BOOST_FIXTURE_TEST_CASE(wallet_duplicated_preset_inputs_test, TestChain100Setup) +{ + // Verify that the wallet's Coin Selection process does not include pre-selected inputs twice in a transaction. + + // Add 4 spendable UTXO, 50 BTC each, to the wallet (total balance 200 BTC) + for (int i = 0; i < 4; i++) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); + auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), m_args, coinbaseKey); + + LOCK(wallet->cs_wallet); + auto available_coins = AvailableCoins(*wallet); + std::vector<COutput> coins = available_coins.All(); + // Preselect the first 3 UTXO (150 BTC total) + std::set<COutPoint> preset_inputs = {coins[0].outpoint, coins[1].outpoint, coins[2].outpoint}; + + // Try to create a tx that spends more than what preset inputs + wallet selected inputs are covering for. + // The wallet can cover up to 200 BTC, and the tx target is 299 BTC. + std::vector<CRecipient> recipients = {{GetScriptForDestination(*Assert(wallet->GetNewDestination(OutputType::BECH32, "dummy"))), + /*nAmount=*/299 * COIN, /*fSubtractFeeFromAmount=*/true}}; + CCoinControl coin_control; + coin_control.m_allow_other_inputs = true; + for (const auto& outpoint : preset_inputs) { + coin_control.Select(outpoint); + } + + // Attempt to send 299 BTC from a wallet that only has 200 BTC. The wallet should exclude + // the preset inputs from the pool of available coins, realize that there is not enough + // money to fund the 299 BTC payment, and fail with "Insufficient funds". + // + // Even with SFFO, the wallet can only afford to send 200 BTC. + // If the wallet does not properly exclude preset inputs from the pool of available coins + // prior to coin selection, it may create a transaction that does not fund the full payment + // amount or, through SFFO, incorrectly reduce the recipient's amount by the difference + // between the original target and the wrongly counted inputs (in this case 99 BTC) + // so that the recipient's amount is no longer equal to the user's selected target of 299 BTC. + + // First case, use 'subtract_fee_from_outputs=true' + util::Result<CreatedTransactionResult> res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control); + BOOST_CHECK(!res_tx.has_value()); + + // Second case, don't use 'subtract_fee_from_outputs'. + recipients[0].fSubtractFeeFromAmount = false; + res_tx = CreateTransaction(*wallet, recipients, /*change_pos*/-1, coin_control); + BOOST_CHECK(!res_tx.has_value()); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace wallet diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp index ab72721f9d..88597bd320 100644 --- a/src/wallet/test/util.cpp +++ b/src/wallet/test/util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,8 +11,6 @@ #include <wallet/wallet.h> #include <wallet/walletdb.h> -#include <boost/test/unit_test.hpp> - #include <memory> namespace wallet { @@ -39,10 +37,46 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc WalletRescanReserver reserver(*wallet); reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false); - BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(result.last_scanned_block, cchain.Tip()->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.last_scanned_height, cchain.Height()); - BOOST_CHECK(result.last_failed_block.IsNull()); + assert(result.status == CWallet::ScanResult::SUCCESS); + assert(result.last_scanned_block == cchain.Tip()->GetBlockHash()); + assert(*result.last_scanned_height == cchain.Height()); + assert(result.last_failed_block.IsNull()); return wallet; } + +std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options) +{ + auto new_database = CreateMockWalletDatabase(options); + + // Get a cursor to the original database + auto batch = database.MakeBatch(); + batch->StartCursor(); + + // Get a batch for the new database + auto new_batch = new_database->MakeBatch(); + + // Read all records from the original database and write them to the new one + while (true) { + CDataStream key(SER_DISK, CLIENT_VERSION); + CDataStream value(SER_DISK, CLIENT_VERSION); + bool complete; + batch->ReadAtCursor(key, value, complete); + if (complete) break; + new_batch->Write(key, value); + } + + return new_database; +} + +std::string getnewaddress(CWallet& w) +{ + constexpr auto output_type = OutputType::BECH32; + return EncodeDestination(getNewDestination(w, output_type)); +} + +CTxDestination getNewDestination(CWallet& w, OutputType output_type) +{ + return *Assert(w.GetNewDestination(output_type, "")); +} + } // namespace wallet diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h index 712d0251cd..635a5152ec 100644 --- a/src/wallet/test/util.h +++ b/src/wallet/test/util.h @@ -1,23 +1,36 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 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_WALLET_TEST_UTIL_H #define BITCOIN_WALLET_TEST_UTIL_H +#include <script/standard.h> #include <memory> class ArgsManager; class CChain; class CKey; +enum class OutputType; namespace interfaces { class Chain; } // namespace interfaces namespace wallet { class CWallet; +struct DatabaseOptions; +class WalletDatabase; std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key); + +// Creates a copy of the provided database +std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options); + +/** Returns a new encoded destination from the wallet (hardcoded to BECH32) */ +std::string getnewaddress(CWallet& w); +/** Returns a new destination, of an specific type, from the wallet */ +CTxDestination getNewDestination(CWallet& w, OutputType output_type); + } // namespace wallet #endif // BITCOIN_WALLET_TEST_UTIL_H diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index 327c28412a..6b8542f378 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 38d23b6f91..c47e56c093 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index e0b38a40e7..f1ef15a282 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 60fdbde71b..b6e50e961a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 The Bitcoin Core developers +// Copyright (c) 2012-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -587,7 +587,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup) // returns the coin associated with the change address underneath the // coinbaseKey pubkey, even though the change address has a different // pubkey. - AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); + AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, /*subtract_fee=*/false}); { LOCK(wallet->cs_wallet); list = ListCoins(*wallet); @@ -622,6 +622,46 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup) BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); } +void TestCoinsResult(ListCoinsTest& context, OutputType out_type, CAmount amount, + std::map<OutputType, size_t>& expected_coins_sizes) +{ + LOCK(context.wallet->cs_wallet); + util::Result<CTxDestination> dest = Assert(context.wallet->GetNewDestination(out_type, "")); + CWalletTx& wtx = context.AddTx(CRecipient{{GetScriptForDestination(*dest)}, amount, /*fSubtractFeeFromAmount=*/true}); + CoinFilterParams filter; + filter.skip_locked = false; + CoinsResult available_coins = AvailableCoins(*context.wallet, nullptr, std::nullopt, filter); + // Lock outputs so they are not spent in follow-up transactions + for (uint32_t i = 0; i < wtx.tx->vout.size(); i++) context.wallet->LockCoin({wtx.GetHash(), i}); + for (const auto& [type, size] : expected_coins_sizes) BOOST_CHECK_EQUAL(size, available_coins.coins[type].size()); +} + +BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, ListCoinsTest) +{ + std::map<OutputType, size_t> expected_coins_sizes; + for (const auto& out_type : OUTPUT_TYPES) { expected_coins_sizes[out_type] = 0U; } + + // Verify our wallet has one usable coinbase UTXO before starting + // This UTXO is a P2PK, so it should show up in the Other bucket + expected_coins_sizes[OutputType::UNKNOWN] = 1U; + CoinsResult available_coins = WITH_LOCK(wallet->cs_wallet, return AvailableCoins(*wallet)); + BOOST_CHECK_EQUAL(available_coins.Size(), expected_coins_sizes[OutputType::UNKNOWN]); + BOOST_CHECK_EQUAL(available_coins.coins[OutputType::UNKNOWN].size(), expected_coins_sizes[OutputType::UNKNOWN]); + + // We will create a self transfer for each of the OutputTypes and + // verify it is put in the correct bucket after running GetAvailablecoins + // + // For each OutputType, We expect 2 UTXOs in our wallet following the self transfer: + // 1. One UTXO as the recipient + // 2. One UTXO from the change, due to payment address matching logic + + for (const auto& out_type : OUTPUT_TYPES) { + if (out_type == OutputType::UNKNOWN) continue; + expected_coins_sizes[out_type] = 2U; + TestCoinsResult(*this, out_type, 1 * COIN, expected_coins_sizes); + } +} + BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup) { { @@ -696,10 +736,10 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup) std::vector<unsigned char> malformed_record; CVectorWriter vw(0, 0, malformed_record, 0); vw << std::string("notadescriptor"); - vw << (uint64_t)0; - vw << (int32_t)0; - vw << (int32_t)0; - vw << (int32_t)1; + vw << uint64_t{0}; + vw << int32_t{0}; + vw << int32_t{0}; + vw << int32_t{1}; SpanReader vr{0, 0, malformed_record}; WalletDescriptor w_desc; @@ -946,7 +986,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup) mtx.vin.clear(); mtx.vin.push_back(CTxIn(tx_id_to_spend, 0)); - wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0); + wallet.transactionAddedToMempool(MakeTransactionRef(mtx)); const uint256& good_tx_id = mtx.GetHash(); { @@ -967,7 +1007,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup) static_cast<FailDatabase&>(wallet.GetDatabase()).m_pass = false; mtx.vin.clear(); mtx.vin.push_back(CTxIn(good_tx_id, 0)); - BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0), + BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx)), std::runtime_error, HasReason("DB error adding transaction to wallet, write failed")); } diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp index e251a3a0e4..21842fe780 100644 --- a/src/wallet/test/walletdb_tests.cpp +++ b/src/wallet/test/walletdb_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp index f45b69a418..24d21c2f22 100644 --- a/src/wallet/test/walletload_tests.cpp +++ b/src/wallet/test/walletload_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php. +#include <wallet/test/util.h> #include <wallet/wallet.h> #include <test/util/setup_common.h> @@ -50,5 +51,139 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup) } } +bool HasAnyRecordOfType(WalletDatabase& db, const std::string& key) +{ + std::unique_ptr<DatabaseBatch> batch = db.MakeBatch(false); + BOOST_CHECK(batch->StartCursor()); + while (true) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + bool complete; + BOOST_CHECK(batch->ReadAtCursor(ssKey, ssValue, complete)); + if (complete) break; + std::string type; + ssKey >> type; + if (type == key) return true; + } + return false; +} + +BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_key_checksum, TestingSetup) +{ + // The test duplicates the db so each case has its own db instance. + int NUMBER_OF_TESTS = 4; + std::vector<std::unique_ptr<WalletDatabase>> dbs; + CKey first_key; + auto get_db = [](std::vector<std::unique_ptr<WalletDatabase>>& dbs) { + std::unique_ptr<WalletDatabase> db = std::move(dbs.back()); + dbs.pop_back(); + return db; + }; + + { // Context setup. + // Create and encrypt legacy wallet + std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, CreateMockWalletDatabase())); + LOCK(wallet->cs_wallet); + auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan(); + BOOST_CHECK(legacy_spkm->SetupGeneration(true)); + + // Get the first key in the wallet + CTxDestination dest = *Assert(legacy_spkm->GetNewDestination(OutputType::LEGACY)); + CKeyID key_id = GetKeyForDestination(*legacy_spkm, dest); + BOOST_CHECK(legacy_spkm->GetKey(key_id, first_key)); + + // Encrypt the wallet and duplicate database + BOOST_CHECK(wallet->EncryptWallet("encrypt")); + wallet->Flush(); + + DatabaseOptions options; + for (int i=0; i < NUMBER_OF_TESTS; i++) { + dbs.emplace_back(DuplicateMockDatabase(wallet->GetDatabase(), options)); + } + } + + { + // First test case: + // Erase all the crypted keys from db and unlock the wallet. + // The wallet will only re-write the crypted keys to db if any checksum is missing at load time. + // So, if any 'ckey' record re-appears on db, then the checksums were not properly calculated, and we are re-writing + // the records every time that 'CWallet::Unlock' gets called, which is not good. + + // Load the wallet and check that is encrypted + std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, get_db(dbs))); + BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK); + BOOST_CHECK(wallet->IsCrypted()); + BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY)); + + // Now delete all records and check that the 'Unlock' function doesn't re-write them + BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords()); + BOOST_CHECK(!HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY)); + BOOST_CHECK(wallet->Unlock("encrypt")); + BOOST_CHECK(!HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY)); + } + + { + // Second test case: + // Verify that loading up a 'ckey' with no checksum triggers a complete re-write of the crypted keys. + std::unique_ptr<WalletDatabase> db = get_db(dbs); + { + std::unique_ptr<DatabaseBatch> batch = db->MakeBatch(false); + std::pair<std::vector<unsigned char>, uint256> value; + BOOST_CHECK(batch->Read(std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()), value)); + + const auto key = std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()); + BOOST_CHECK(batch->Write(key, value.first, /*fOverwrite=*/true)); + } + + // Load the wallet and check that is encrypted + std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, std::move(db))); + BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK); + BOOST_CHECK(wallet->IsCrypted()); + BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY)); + + // Now delete all ckey records and check that the 'Unlock' function re-writes them + // (this is because the wallet, at load time, found a ckey record with no checksum) + BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords()); + BOOST_CHECK(!HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY)); + BOOST_CHECK(wallet->Unlock("encrypt")); + BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY)); + } + + { + // Third test case: + // Verify that loading up a 'ckey' with an invalid checksum throws an error. + std::unique_ptr<WalletDatabase> db = get_db(dbs); + { + std::unique_ptr<DatabaseBatch> batch = db->MakeBatch(false); + std::vector<unsigned char> crypted_data; + BOOST_CHECK(batch->Read(std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()), crypted_data)); + + // Write an invalid checksum + std::pair<std::vector<unsigned char>, uint256> value = std::make_pair(crypted_data, uint256::ONE); + const auto key = std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()); + BOOST_CHECK(batch->Write(key, value, /*fOverwrite=*/true)); + } + + std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, std::move(db))); + BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT); + } + + { + // Fourth test case: + // Verify that loading up a 'ckey' with an invalid pubkey throws an error + std::unique_ptr<WalletDatabase> db = get_db(dbs); + { + CPubKey invalid_key; + BOOST_ASSERT(!invalid_key.IsValid()); + const auto key = std::make_pair(DBKeys::CRYPTED_KEY, invalid_key); + std::pair<std::vector<unsigned char>, uint256> value; + BOOST_CHECK(db->MakeBatch(false)->Write(key, value, /*fOverwrite=*/true)); + } + + std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, std::move(db))); + BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT); + } +} + BOOST_AUTO_TEST_SUITE_END() } // namespace wallet diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 27983e356d..6ad222864a 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 The Bitcoin Core developers +// Copyright (c) 2021-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 431e970edc..6158ff033c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -171,7 +171,7 @@ std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, Lo { LOCK(context.wallets_mutex); auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet)); - return interfaces::MakeHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); }); + return interfaces::MakeCleanupHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); }); } void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr<CWallet>& wallet) @@ -241,7 +241,7 @@ std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::s } context.chain->initMessage(_("Loading wallet…").translated); - const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings); + std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings); if (!wallet) { error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error; status = DatabaseStatus::FAILED_LOAD; @@ -381,7 +381,7 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& // Make the wallet context.chain->initMessage(_("Loading wallet…").translated); - const std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings); + std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings); if (!wallet) { error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error; status = DatabaseStatus::FAILED_CREATE; @@ -472,8 +472,7 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b error += strprintf(Untranslated("Unexpected exception: %s"), e.what()); } if (!wallet) { - fs::remove(wallet_file); - fs::remove(wallet_path); + fs::remove_all(wallet_path); } return wallet; @@ -648,8 +647,7 @@ bool CWallet::HasWalletSpend(const CTransactionRef& tx) const AssertLockHeld(cs_wallet); const uint256& txid = tx->GetHash(); for (unsigned int i = 0; i < tx->vout.size(); ++i) { - auto iter = mapTxSpends.find(COutPoint(txid, i)); - if (iter != mapTxSpends.end()) { + if (IsSpent(COutPoint(txid, i))) { return true; } } @@ -1355,7 +1353,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const SyncTxState& sta MarkInputsDirty(ptx); } -void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) { +void CWallet::transactionAddedToMempool(const CTransactionRef& tx) { LOCK(cs_wallet); SyncTransaction(tx, TxStateInMempool{}); @@ -1365,7 +1363,7 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t memp } } -void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) { +void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) { LOCK(cs_wallet); auto it = mapWallet.find(tx->GetHash()); if (it != mapWallet.end()) { @@ -1411,7 +1409,7 @@ void CWallet::blockConnected(const interfaces::BlockInfo& block) m_last_block_processed = block.hash; for (size_t index = 0; index < block.data->vtx.size(); index++) { SyncTransaction(block.data->vtx[index], TxStateConfirmed{block.hash, block.height, static_cast<int>(index)}); - transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */); + transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK); } } @@ -2463,7 +2461,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label) { LOCK(cs_wallet); - auto spk_man = GetScriptPubKeyMan(type, false /* internal */); + auto spk_man = GetScriptPubKeyMan(type, /*internal=*/false); if (!spk_man) { return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))}; } @@ -2884,7 +2882,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri const auto start{SteadyClock::now()}; // TODO: Can't use std::make_shared because we need a custom deleter but // should be possible to use std::allocate_shared. - const std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet); + std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet); bool rescan_required = false; DBErrors nLoadWalletRet = walletInstance->LoadWallet(); if (nLoadWalletRet != DBErrors::LOAD_OK) { @@ -2919,6 +2917,10 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri "The wallet might had been created on a newer version.\n" "Please try running the latest software version.\n"), walletFile); return nullptr; + } else if (nLoadWalletRet == DBErrors::UNEXPECTED_LEGACY_ENTRY) { + error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n" + "The wallet might have been tampered with or created with malicious intent.\n"), walletFile); + return nullptr; } else { error = strprintf(_("Error loading %s"), walletFile); return nullptr; @@ -3180,6 +3182,24 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf if (tip_height && *tip_height != rescan_height) { + // No need to read and scan block if block was created before + // our wallet birthday (as adjusted for block time variability) + std::optional<int64_t> time_first_key; + for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) { + int64_t time = spk_man->GetTimeFirstKey(); + if (!time_first_key || time < *time_first_key) time_first_key = time; + } + if (time_first_key) { + FoundBlock found = FoundBlock().height(rescan_height); + chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, found); + if (!found.found) { + // We were unable to find a block that had a time more recent than our earliest timestamp + // or a height higher than the wallet was synced to, indicating that the wallet is newer than the + // current chain tip. Skip rescanning in this case. + rescan_height = *tip_height; + } + } + // Technically we could execute the code below in any case, but performing the // `while` loop below can make startup very slow, so only check blocks on disk // if necessary. @@ -3214,17 +3234,6 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf chain.initMessage(_("Rescanning…").translated); walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height); - // No need to read and scan block if block was created before - // our wallet birthday (as adjusted for block time variability) - std::optional<int64_t> time_first_key; - for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) { - int64_t time = spk_man->GetTimeFirstKey(); - if (!time_first_key || time < *time_first_key) time_first_key = time; - } - if (time_first_key) { - chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, FoundBlock().height(rescan_height)); - } - { WalletRescanReserver reserver(*walletInstance); if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/true).status)) { @@ -3998,6 +4007,23 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error) } } } + + // Persist added address book entries (labels, purpose) for watchonly and solvable wallets + auto persist_address_book = [](const CWallet& wallet) { + LOCK(wallet.cs_wallet); + WalletBatch batch{wallet.GetDatabase()}; + for (const auto& [destination, addr_book_data] : wallet.m_address_book) { + auto address{EncodeDestination(destination)}; + auto purpose{addr_book_data.purpose}; + auto label{addr_book_data.GetLabel()}; + // don't bother writing default values (unknown purpose, empty label) + if (purpose != "unknown") batch.WritePurpose(address, purpose); + if (!label.empty()) batch.WriteName(address, label); + } + }; + if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet); + if (data.solvable_wallet) persist_address_book(*data.solvable_wallet); + // Remove the things to delete if (dests_to_delete.size() > 0) { for (const auto& dest : dests_to_delete) { @@ -4182,8 +4208,8 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet> // Make list of wallets to cleanup std::vector<std::shared_ptr<CWallet>> created_wallets; - created_wallets.push_back(std::move(res.watchonly_wallet)); - created_wallets.push_back(std::move(res.solvables_wallet)); + if (res.watchonly_wallet) created_wallets.push_back(std::move(res.watchonly_wallet)); + if (res.solvables_wallet) created_wallets.push_back(std::move(res.solvables_wallet)); // Get the directories to remove after unloading for (std::shared_ptr<CWallet>& w : created_wallets) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 137320acda..8b7e6dd526 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -516,7 +516,7 @@ public: */ CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false); bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override; + void transactionAddedToMempool(const CTransactionRef& tx) override; void blockConnected(const interfaces::BlockInfo& block) override; void blockDisconnected(const interfaces::BlockInfo& block) override; void updatedBlockTip() override; @@ -538,7 +538,7 @@ public: uint256 last_failed_block; }; ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress); - void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override; + void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override; /** Set the next time this wallet should resend transactions to 12-36 hours from now, ~1 day on average. */ void SetNextResend() { m_next_resend = GetDefaultNextResend(); } /** Return true if all conditions for periodically resending transactions are met. */ diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 6a8f0d2481..b393c35112 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -315,6 +315,7 @@ public: std::map<uint160, CHDChain> m_hd_chains; bool tx_corrupt{false}; bool descriptor_unknown{false}; + bool unexpected_legacy_entry{false}; CWalletScanState() = default; }; @@ -332,6 +333,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, if (filter_fn && !filter_fn(strType)) { return true; } + // Legacy entries in descriptor wallets are not allowed, abort immediately + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && DBKeys::LEGACY_TYPES.count(strType) > 0) { + wss.unexpected_legacy_entry = true; + return false; + } if (strType == DBKeys::NAME) { std::string strAddress; ssKey >> strAddress; @@ -482,7 +488,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, if (!ssValue.eof()) { uint256 checksum; ssValue >> checksum; - if ((checksum_valid = Hash(vchPrivKey) != checksum)) { + if (!(checksum_valid = Hash(vchPrivKey) == checksum)) { strErr = "Error reading wallet database: Encrypted key corrupt"; return false; } @@ -833,6 +839,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) std::string strType, strErr; if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { + if (wss.unexpected_legacy_entry) { + strErr = strprintf("Error: Unexpected legacy entry found in descriptor wallet %s. ", pwallet->GetName()); + strErr += "The wallet might have been tampered with or created with malicious intent."; + pwallet->WalletLogPrintf("%s\n", strErr); + return DBErrors::UNEXPECTED_LEGACY_ENTRY; + } // losing keys is considered a catastrophic error, anything else // we assume the user can live with: if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) { @@ -962,7 +974,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) return result; } -DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx) +DBErrors WalletBatch::FindWalletTxHashes(std::vector<uint256>& tx_hashes) { DBErrors result = DBErrors::LOAD_OK; @@ -1000,9 +1012,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal if (strType == DBKeys::TX) { uint256 hash; ssKey >> hash; - vTxHash.push_back(hash); - vWtx.emplace_back(/*tx=*/nullptr, TxStateInactive{}); - ssValue >> vWtx.back(); + tx_hashes.push_back(hash); } } } catch (...) { @@ -1015,10 +1025,9 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut) { - // build list of wallet TXs and hashes + // build list of wallet TX hashes std::vector<uint256> vTxHash; - std::list<CWalletTx> vWtx; - DBErrors err = FindWalletTx(vTxHash, vWtx); + DBErrors err = FindWalletTxHashes(vTxHash); if (err != DBErrors::LOAD_OK) { return err; } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index da6efe534b..97e8fad278 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2021 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -52,7 +52,8 @@ enum class DBErrors LOAD_FAIL, NEED_REWRITE, NEED_RESCAN, - UNKNOWN_DESCRIPTOR + UNKNOWN_DESCRIPTOR, + UNEXPECTED_LEGACY_ENTRY }; namespace DBKeys { @@ -272,7 +273,7 @@ public: bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal); DBErrors LoadWallet(CWallet* pwallet); - DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx); + DBErrors FindWalletTxHashes(std::vector<uint256>& tx_hashes); DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut); /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */ static bool IsKeyType(const std::string& strType); diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index e991bc0814..f93b666bd5 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2021 The Bitcoin Core developers +// Copyright (c) 2016-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -58,7 +58,7 @@ static const std::shared_ptr<CWallet> MakeWallet(const std::string& name, const } // dummy chain interface - std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, args, std::move(database)), WalletToolReleaseWallet}; + std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, name, args, std::move(database)), WalletToolReleaseWallet}; DBErrors load_wallet_ret; try { load_wallet_ret = wallet_instance->LoadWallet(); diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index df1b10a634..299c74d01c 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021 The Bitcoin Core developers +// Copyright (c) 2017-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index 7624c2b16d..ce8b6cfd6e 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/warnings.cpp b/src/warnings.cpp index dabb194ce1..d0de706953 100644 --- a/src/warnings.cpp +++ b/src/warnings.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h index 97c2599366..6899ee8fa6 100644 --- a/src/zmq/zmqabstractnotifier.h +++ b/src/zmq/zmqabstractnotifier.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 6ee134f392..6dc4737d0a 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index 585e900ca6..b24d4664da 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index eaf3455296..6418455d19 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2021 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #include <chain.h> #include <chainparams.h> #include <crypto/common.h> +#include <kernel/cs_main.h> #include <logging.h> #include <netaddress.h> #include <netbase.h> @@ -248,18 +249,14 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); - { - LOCK(cs_main); - CBlock block; - if(!ReadBlockFromDisk(block, pindex, consensusParams)) - { - zmqError("Can't read block from disk"); - return false; - } - - ss << block; + CBlock block; + if (!ReadBlockFromDisk(block, pindex, consensusParams)) { + zmqError("Can't read block from disk"); + return false; } + ss << block; + return SendZmqMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size()); } diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h index fcedd1aabe..18336a5eb0 100644 --- a/src/zmq/zmqpublishnotifier.h +++ b/src/zmq/zmqpublishnotifier.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp index 047e6bf9b7..fcc2608262 100644 --- a/src/zmq/zmqrpc.cpp +++ b/src/zmq/zmqrpc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2021 The Bitcoin Core developers +// Copyright (c) 2018-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqutil.cpp b/src/zmq/zmqutil.cpp index cf3a0b2d71..3c6d1b9ab5 100644 --- a/src/zmq/zmqutil.cpp +++ b/src/zmq/zmqutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2021 The Bitcoin Core developers +// Copyright (c) 2014-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py index 3747b2a98d..33054fd517 100644 --- a/test/functional/data/invalid_txs.py +++ b/test/functional/data/invalid_txs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ @@ -46,18 +46,19 @@ from test_framework.script import ( OP_MOD, OP_MUL, OP_OR, + OP_RETURN, OP_RIGHT, OP_RSHIFT, OP_SUBSTR, - OP_TRUE, OP_XOR, ) from test_framework.script_util import ( + MIN_PADDING, + MIN_STANDARD_TX_NONWITNESS_SIZE, script_to_p2sh_script, ) basic_p2sh = script_to_p2sh_script(CScript([OP_0])) - class BadTxTemplate: """Allows simple construction of a certain kind of invalid tx. Base class to be subclassed.""" __metaclass__ = abc.ABCMeta @@ -122,7 +123,9 @@ class SizeTooSmall(BadTxTemplate): def get_tx(self): tx = CTransaction() tx.vin.append(self.valid_txin) - tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) + tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2))))) + assert len(tx.serialize_without_witness()) == 64 + assert MIN_STANDARD_TX_NONWITNESS_SIZE - 1 == 64 tx.calc_sha256() return tx diff --git a/test/functional/data/rpc_getblockstats.json b/test/functional/data/rpc_getblockstats.json index 16dbc5fe60..7d7460aacc 100644 --- a/test/functional/data/rpc_getblockstats.json +++ b/test/functional/data/rpc_getblockstats.json @@ -102,8 +102,8 @@ "00000020f44e7a48b9f221af95f3295c8dcefc5358934a68dc79e2933dc0794b350cad0a90fad2cd50b41d4ef45e76c2a456b98c180632bb4b44e0cd18ce90679fe54e552b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401630101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", "0000002087454276cce83f4d19e0120f6e9728ac5905f7adaf6b27e3f5bbe43ab823f85db7d1f44666531483df3d67c15f2c231718ad93b63b851dce5ff4c4a67f524ffa2b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401640101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", "000000202cdc3e99f07a80252dd6097faa0eddf3f2dde5ae390610e0bca94ecc25931551d31fceb8fe0a682f6017ca3dbb582f3a2f06e5d99ec99c42c8a744dd4c9216b82b4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000209b3ace9bd510918d20e87518c0cf5976cab3e28cc7af41259a89c6dd7668a32922808b8a082be71bcd6152cb8fd223650b5579a41344ba749e4d17b9bf211a9e2b4ae75affff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff026c03062a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9edb85d8f3c122c43a72f1e0dd122c8f7af040aa0b0a46001621110fb37818021510120000000000000000000000000000000000000000000000000000000000000000000000000020000000128394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3000000006a47304402201c16d06a5c4353168b3881071aea7d1eb4d88eedfea53a9d6af9abb56da9060002205abf3ae535f1f1b5cfe8ba955535c2b20ac003e7d7720c5b7d2640ac2a04d19001210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0294b89a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac00286bee0000000017a91452bab4f229415d0dc5c6d30b162f93a1a0cac5958765000000", - "000000200fa168b50a79ad24378a6b0f96e4c9f4ccb657a2663320d5fc1efd8ee7caa10ab42a31c444f2153387530a0979d4dc3dcc134b394c821227b8abff930c03c8412b4ae75affff7f200200000004020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff02e015072a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ed20376d4bc90f9c689850eec3603cda658ba6295241730473ceb0e970b8d594150120000000000000000000000000000000000000000000000000000000000000000000000000020000000191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a6000000006a47304402200bf62021c0a9a47ced8eba1e0998f5c71b2950763198d83ad284bd791241dbb00220446a05b7c35e7458924de88a8dcccab1ec6a106aa005345e55b482d8eb66337301210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff02acdbf405000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94d7a4350000000017a914dfa6f0b17d2c64962c94203e744a9d4179ed22c18766000000020000000112d2f07672102dc6f099c4be308f598e4c4da1a7e0cb462ae14f0444525a1332000000006a47304402200a6a2f544f3f9d299608a7c745e2326de176fb1cac03ae3e74943f4250b8896e02205023a5b4faff99865bf91f1263605a502c723628be9240c0b7bec81d2ed106f101210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0200ca9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94166bee0000000017a914152cc82f7944f5c416de7dbffb052f7081765d7987660000000200000000010191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a601000000171600147cc872ad7350c37fecab9c4c6d9f08aceb53bdb8feffffff02005ed0b20000000017a914aab1c8c53fe62e283a53efa28097709f4f2ed37b87e0bc9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0247304402201b4476f238ed5d515bfcd6927d0d008a4993770763eca73e3ee66f69971831d902200f5215a6dfd90391dd63462cfdf69804fe31224c309ec9c38d33a04dce71c0ee0121028c9d2955a95301b699db62e97d54bf0a91feb44e5cd94bbf5b62f1df57fb643966000000" + "000000209b3ace9bd510918d20e87518c0cf5976cab3e28cc7af41259a89c6dd7668a329f03ef4716ad5d88bccfd71088bf2ec3eb5b32e0ff60f35f9becd73052bfa8af12b4ae75affff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff025803062a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9edb11910e4e0ee6ee6d6bad42736999d1eba649243dc781438e5ef845c7227aaad0120000000000000000000000000000000000000000000000000000000000000000000000000020000000128394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3000000006a47304402200650c6c50bd4952ca13b7aa37d458a36628434bbb968701063cdd36d0725e36c02202e059ccf7a4a049de028c4f140e543baa7e69ea3663e3d1fdfbc8ba7247e82f901210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff02a8b89a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac00286bee0000000016001423838e991caedd69289d9dac88ca423cca683a2265000000", + "0000002061597bf3305ee2334b5d7fec136c2064b69d14955b50cd0b81f49ac33d88e506d80731ce60c2f275d29539a4d04c7e8c72aa4ade3c9baec24881a581fc524c6a2b4ae75affff7f200000000005020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff023840072a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ed89a3c65f40921b14168368cf4775a710ad17b613cedcff001f1f1ca3c863cc11012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101bb475ac72ba1a45a96be584a689d6d0ace820d9587b0db53dc40a15555b9be770100000000feffffff02c0be9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac005ed0b200000000160014a57f6871c70569e0543322614c5c85438b796a900247304402207893b5466cdbf9cdedcc73fb8e10e01c4dd9aac4345031ef0c35d91e82ff5fd602207f0e1d7e4270a532060fd1e6ad7881d18acb173fd4fd1d61f3c8ff6707bdb972012103bb4c79ca594b19bbec7ee6302af0ef4191345fa7f03a30ed4e042aeed680924b6600000002000000000101e6a996cbac10b2d6b2bb2796a4ebf639ee21b136e06c7d8c6bc62b7cb4a311870100000000feffffff0200ca9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88acc088357700000000160014c48ea35298422796eb75ee9a04ebada66780083902473044022062963ff9f1f0d2c885060c083b97ddd67bd6e8a7daaed6578a62c1f905fd31a6022001836efe75bbce64d29700f5568aed78ce68f098ef0b8efdad0679e2f6c0ceb5012102228c4d459ce647b63b2681597a6e8391e4b5afab147f90747184a0893e4934c26600000002000000000101c654a35d86b4c3112ae9ec75e3bc271e0b8f928620386fdaf9517e8a9b511d850100000000feffffff024038f505000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88acc0a73f7100000000160014cb1049e20cebfe756d657af0d47a3357c1db3c9702473044022024728eb27e884d08b2b95e670fd58c0e10106a18bc9e01f753f9ae474aa2c95e02201d5abe91302b373507dce1fd2f4b95ddc36e21d23eda6c476cc9efea80338ef90121036be02fd68622ce6740f0d028059af96a310c23c675f044732171df6f64f0fcb2660000000200000000010135c4ee1a780d8279ea7c79d3ad6fbb39315a13e6b51dd51f49db6e2f4796bada0100000000feffffff020000000000000000036a0121c8183f71000000001600147ea4d830ca77c20a23155a176a1472613dc4e7840247304402202db3527431e09ca8034d207134d79fc063939bd402286dd8b3872de3b2a746b402207faae5fb8838e6877822a9209fe2e81d4be4a69ce8164215e03f9b92d75e94f90121024d456d37df6f3436ee1685b78d90d2d24c4dd8c602d5f41405fe7f449b43415f00000000" ], "mocktime": 1525107225, "stats": [ @@ -142,13 +142,15 @@ "totalfee": 0, "txs": 1, "utxo_increase": 2, - "utxo_size_inc": 163 + "utxo_increase_actual": 1, + "utxo_size_inc": 163, + "utxo_size_inc_actual": 75 }, { - "avgfee": 4460, + "avgfee": 4440, "avgfeerate": 20, - "avgtxsize": 223, - "blockhash": "0aa1cae78efd1efcd5203366a257b6ccf4c9e4960f6b8a3724ad790ab568a10f", + "avgtxsize": 222, + "blockhash": "06e5883dc39af4810bcd505b95149db664206c13ec7f5d4b33e25e30f37b5961", "feerate_percentiles": [ 20, 20, @@ -158,65 +160,69 @@ ], "height": 102, "ins": 1, - "maxfee": 4460, + "maxfee": 4440, "maxfeerate": 20, - "maxtxsize": 223, - "medianfee": 4460, + "maxtxsize": 222, + "medianfee": 4440, "mediantime": 1525107242, - "mediantxsize": 223, - "minfee": 4460, + "mediantxsize": 222, + "minfee": 4440, "minfeerate": 20, - "mintxsize": 223, + "mintxsize": 222, "outs": 4, "subsidy": 5000000000, "swtotal_size": 0, "swtotal_weight": 0, "swtxs": 0, "time": 1525107243, - "total_out": 4999995540, - "total_size": 223, - "total_weight": 892, - "totalfee": 4460, + "total_out": 4999995560, + "total_size": 222, + "total_weight": 888, + "totalfee": 4440, "txs": 2, "utxo_increase": 3, - "utxo_size_inc": 236 + "utxo_increase_actual": 2, + "utxo_size_inc": 235, + "utxo_size_inc_actual": 147 }, { - "avgfee": 24906, - "avgfeerate": 121, - "avgtxsize": 231, - "blockhash": "53e416e2538bc783c42a7aea566e884321afed893e9e58cf356d6429759dfa46", + "avgfee": 21390, + "avgfeerate": 155, + "avgtxsize": 219, + "blockhash": "7474991c2ae3c94c4813d75b4c752028304b773dd4dce8d460dfa2d1e7b542a3", "feerate_percentiles": [ 20, 20, 20, - 300, - 300 + 301, + 301 ], "height": 103, - "ins": 3, - "maxfee": 66900, - "maxfeerate": 300, - "maxtxsize": 249, - "medianfee": 4460, + "ins": 4, + "maxfee": 43200, + "maxfeerate": 301, + "maxtxsize": 225, + "medianfee": 19740, "mediantime": 1525107243, - "mediantxsize": 223, - "minfee": 3360, + "mediantxsize": 225, + "minfee": 2880, "minfeerate": 20, - "mintxsize": 223, - "outs": 8, + "mintxsize": 203, + "outs": 10, "subsidy": 5000000000, - "swtotal_size": 249, - "swtotal_weight": 669, - "swtxs": 1, + "swtotal_size": 878, + "swtotal_weight": 2204, + "swtxs": 4, "time": 1525107243, - "total_out": 9999920820, - "total_size": 695, - "total_weight": 2453, - "totalfee": 74720, - "txs": 4, - "utxo_increase": 5, - "utxo_size_inc": 384 + "total_out": 10899908680, + "total_size": 878, + "total_weight": 2204, + "totalfee": 85560, + "txs": 5, + "utxo_increase": 6, + "utxo_increase_actual": 4, + "utxo_size_inc": 441, + "utxo_size_inc_actual": 300 } ] }
\ No newline at end of file diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 9cf756060e..7f7aa065ad 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 @@ -79,6 +79,9 @@ class ExampleTest(BitcoinTestFramework): # 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 add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): """Override test parameters for your individual test. diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py index 63abf0d9f8..28c3880513 100755 --- a/test/functional/feature_addrman.py +++ b/test/functional/feature_addrman.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 addrman functionality""" diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 67cacaa9ce..36ee79dab9 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -83,8 +83,6 @@ class AssumeValidTest(BitcoinTestFramework): break def run_test(self): - p2p0 = self.nodes[0].add_p2p_connection(BaseNode()) - # Build the blockchain self.tip = int(self.nodes[0].getbestblockhash(), 16) self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1 @@ -139,28 +137,23 @@ class AssumeValidTest(BitcoinTestFramework): self.block_time += 1 height += 1 - self.nodes[0].disconnect_p2ps() - # 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)]) self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)]) p2p0 = self.nodes[0].add_p2p_connection(BaseNode()) - p2p1 = self.nodes[1].add_p2p_connection(BaseNode()) - p2p2 = self.nodes[2].add_p2p_connection(BaseNode()) - - # send header lists to all three nodes p2p0.send_header_for_blocks(self.blocks[0:2000]) p2p0.send_header_for_blocks(self.blocks[2000:]) - p2p1.send_header_for_blocks(self.blocks[0:2000]) - p2p1.send_header_for_blocks(self.blocks[2000:]) - p2p2.send_header_for_blocks(self.blocks[0:200]) # Send blocks to node0. Block 102 will be rejected. self.send_blocks_until_disconnected(p2p0) self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1) assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1) + p2p1 = self.nodes[1].add_p2p_connection(BaseNode()) + p2p1.send_header_for_blocks(self.blocks[0:2000]) + p2p1.send_header_for_blocks(self.blocks[2000:]) + # Send all blocks to node1. All blocks will be accepted. for i in range(2202): p2p1.send_message(msg_block(self.blocks[i])) @@ -168,6 +161,9 @@ class AssumeValidTest(BitcoinTestFramework): p2p1.sync_with_ping(960) assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202) + p2p2 = self.nodes[2].add_p2p_connection(BaseNode()) + p2p2.send_header_for_blocks(self.blocks[0:200]) + # Send blocks to node2. Block 102 will be rejected. self.send_blocks_until_disconnected(p2p2) self.wait_until(lambda: self.nodes[2].getblockcount() >= COINBASE_MATURITY + 1) diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py index 5de9ff203c..4a94d2ce7b 100755 --- a/test/functional/feature_bind_extra.py +++ b/test/functional/feature_bind_extra.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index 5b43fe4f8e..894afffc79 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -32,6 +32,7 @@ from test_framework.util import ( assert_raises_rpc_error, softfork_active, ) +from test_framework.wallet import MiniWallet SCRIPT_W0_SH_OP_TRUE = script_to_p2wsh_script(CScript([OP_TRUE])) @@ -44,6 +45,9 @@ SEQUENCE_LOCKTIME_MASK = 0x0000ffff NOT_FINAL_ERROR = "non-BIP68-final" class BIP68Test(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.extra_args = [ @@ -55,14 +59,9 @@ class BIP68Test(BitcoinTestFramework): ], ] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] - - # Generate some coins - self.generate(self.nodes[0], 110) + self.wallet = MiniWallet(self.nodes[0]) self.log.info("Running test disable flag") self.test_disable_flag() @@ -89,16 +88,10 @@ class BIP68Test(BitcoinTestFramework): # the first sequence bit is set. def test_disable_flag(self): # Create some unconfirmed inputs - new_addr = self.nodes[0].getnewaddress() - self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC - - utxos = self.nodes[0].listunspent(0, 0) - assert len(utxos) > 0 - - utxo = utxos[0] + utxo = self.wallet.send_self_transfer(from_node=self.nodes[0])["new_utxo"] tx1 = CTransaction() - value = int((utxo["amount"] - self.relayfee) * COIN) + value = int((utxo["value"] - self.relayfee) * COIN) # Check that the disable flag disables relative locktime. # If sequence locks were used, this would require 1 block for the @@ -107,8 +100,8 @@ class BIP68Test(BitcoinTestFramework): tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)] tx1.vout = [CTxOut(value, SCRIPT_W0_SH_OP_TRUE)] - tx1_signed = self.nodes[0].signrawtransactionwithwallet(tx1.serialize().hex())["hex"] - tx1_id = self.nodes[0].sendrawtransaction(tx1_signed) + self.wallet.sign_tx(tx=tx1) + tx1_id = self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx1.serialize().hex()) tx1_id = int(tx1_id, 16) # This transaction will enable sequence-locks, so this transaction should @@ -122,13 +115,13 @@ class BIP68Test(BitcoinTestFramework): tx2.vout = [CTxOut(int(value - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] tx2.rehash() - assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx2.serialize().hex()) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx2.serialize().hex()) # Setting the version back down to 1 should disable the sequence lock, # so this should be accepted. tx2.nVersion = 1 - self.nodes[0].sendrawtransaction(tx2.serialize().hex()) + self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2.serialize().hex()) # Calculate the median time past of a prior block ("confirmations" before # the current tip). @@ -141,20 +134,13 @@ class BIP68Test(BitcoinTestFramework): # Create lots of confirmed utxos, and use them to generate lots of random # transactions. max_outputs = 50 - addresses = [] - while len(addresses) < max_outputs: - addresses.append(self.nodes[0].getnewaddress()) - while len(self.nodes[0].listunspent()) < 200: + while len(self.wallet.get_utxos(include_immature_coinbase=False, mark_as_spent=False)) < 200: import random - random.shuffle(addresses) num_outputs = random.randint(1, max_outputs) - outputs = {} - for i in range(num_outputs): - outputs[addresses[i]] = random.randint(1, 20)*0.01 - self.nodes[0].sendmany("", outputs) - self.generate(self.nodes[0], 1) + self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=num_outputs) + self.generate(self.wallet, 1) - utxos = self.nodes[0].listunspent() + utxos = self.wallet.get_utxos(include_immature_coinbase=False) # Try creating a lot of random transactions. # Each time, choose a random number of inputs, and randomly set @@ -211,19 +197,20 @@ class BIP68Test(BitcoinTestFramework): sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1 sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value)) - value += utxos[j]["amount"]*COIN + value += utxos[j]["value"]*COIN # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output tx_size = len(tx.serialize().hex())//2 + 120*num_inputs + 50 tx.vout.append(CTxOut(int(value - self.relayfee * tx_size * COIN / 1000), SCRIPT_W0_SH_OP_TRUE)) - rawtx = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())["hex"] + self.wallet.sign_tx(tx=tx) if (using_sequence_locks and not should_pass): # This transaction should be rejected - assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx.serialize().hex()) else: # This raw transaction should be accepted - self.nodes[0].sendrawtransaction(rawtx) - utxos = self.nodes[0].listunspent() + self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx.serialize().hex()) + self.wallet.rescan_utxos() + utxos = self.wallet.get_utxos(include_immature_coinbase=False) # Test that sequence locks on unconfirmed inputs must have nSequence # height or time of 0 to be accepted. @@ -234,8 +221,8 @@ class BIP68Test(BitcoinTestFramework): cur_height = self.nodes[0].getblockcount() # Create a mempool tx. - txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) - tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid)) + self.wallet.rescan_utxos() + tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0])["tx"] tx1.rehash() # Anyone-can-spend mempool tx. @@ -244,11 +231,11 @@ class BIP68Test(BitcoinTestFramework): tx2.nVersion = 2 tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)] tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] - tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"] - tx2 = tx_from_hex(tx2_raw) + self.wallet.sign_tx(tx=tx2) + tx2_raw = tx2.serialize().hex() tx2.rehash() - self.nodes[0].sendrawtransaction(tx2_raw) + self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2_raw) # Create a spend of the 0th output of orig_tx with a sequence lock # of 1, and test what happens when submitting. @@ -268,10 +255,10 @@ class BIP68Test(BitcoinTestFramework): if (orig_tx.hash in node.getrawmempool()): # sendrawtransaction should fail if the tx is in the mempool - assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, tx.serialize().hex()) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=node, tx_hex=tx.serialize().hex()) else: # sendrawtransaction should succeed if the tx is not in the mempool - node.sendrawtransaction(tx.serialize().hex()) + self.wallet.sendrawtransaction(from_node=node, tx_hex=tx.serialize().hex()) return tx @@ -284,7 +271,7 @@ class BIP68Test(BitcoinTestFramework): cur_time = int(time.time()) for _ in range(10): self.nodes[0].setmocktime(cur_time + 600) - self.generate(self.nodes[0], 1, sync_fun=self.no_op) + self.generate(self.wallet, 1, sync_fun=self.no_op) cur_time += 600 assert tx2.hash in self.nodes[0].getrawmempool() @@ -318,12 +305,12 @@ class BIP68Test(BitcoinTestFramework): tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True) assert tx5.hash not in self.nodes[0].getrawmempool() - utxos = self.nodes[0].listunspent() - tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1)) - tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN) - raw_tx5 = self.nodes[0].signrawtransactionwithwallet(tx5.serialize().hex())["hex"] + utxo = self.wallet.get_utxo() + tx5.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=1)) + tx5.vout[0].nValue += int(utxo["value"]*COIN) + self.wallet.sign_tx(tx=tx5) - assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx5.serialize().hex()) # Test mempool-BIP68 consistency after reorg # @@ -359,7 +346,7 @@ class BIP68Test(BitcoinTestFramework): # Reset the chain and get rid of the mocktimed-blocks self.nodes[0].setmocktime(0) self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1)) - self.generate(self.nodes[0], 10, sync_fun=self.no_op) + self.generate(self.wallet, 10, sync_fun=self.no_op) # Make sure that BIP68 isn't being used to validate blocks prior to # activation height. If more blocks are mined prior to this test @@ -367,9 +354,8 @@ class BIP68Test(BitcoinTestFramework): # this test should be moved to run earlier, or deleted. def test_bip68_not_consensus(self): assert not softfork_active(self.nodes[0], 'csv') - txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) - tx1 = tx_from_hex(self.nodes[0].getrawtransaction(txid)) + tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0])["tx"] tx1.rehash() # Make an anyone-can-spend transaction @@ -379,11 +365,12 @@ class BIP68Test(BitcoinTestFramework): tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] # sign tx2 - tx2_raw = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())["hex"] + self.wallet.sign_tx(tx=tx2) + tx2_raw = tx2.serialize().hex() tx2 = tx_from_hex(tx2_raw) tx2.rehash() - self.nodes[0].sendrawtransaction(tx2.serialize().hex()) + self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2_raw) # Now make an invalid spend of tx2 according to BIP68 sequence_value = 100 # 100 block relative locktime @@ -396,7 +383,7 @@ class BIP68Test(BitcoinTestFramework): tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)] tx3.rehash() - assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx3.serialize().hex()) + assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx3.serialize().hex()) # make a block that violates bip68; ensure that the tip updates block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[tx1, tx2, tx3]) @@ -412,22 +399,19 @@ class BIP68Test(BitcoinTestFramework): min_activation_height = 432 height = self.nodes[0].getblockcount() assert_greater_than(min_activation_height - height, 2) - self.generate(self.nodes[0], min_activation_height - height - 2, sync_fun=self.no_op) + self.generate(self.wallet, min_activation_height - height - 2, sync_fun=self.no_op) assert not softfork_active(self.nodes[0], 'csv') - self.generate(self.nodes[0], 1, sync_fun=self.no_op) + self.generate(self.wallet, 1, sync_fun=self.no_op) assert softfork_active(self.nodes[0], 'csv') self.sync_blocks() # Use self.nodes[1] to test that version 2 transactions are standard. def test_version2_relay(self): - inputs = [ ] - outputs = { self.nodes[1].getnewaddress() : 1.0 } - rawtx = self.nodes[1].createrawtransaction(inputs, outputs) - rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] - tx = tx_from_hex(rawtxfund) + mini_wallet = MiniWallet(self.nodes[1]) + mini_wallet.rescan_utxos() + tx = mini_wallet.create_self_transfer()["tx"] tx.nVersion = 2 - tx_signed = self.nodes[1].signrawtransactionwithwallet(tx.serialize().hex())["hex"] - self.nodes[1].sendrawtransaction(tx_signed) + mini_wallet.sendrawtransaction(from_node=self.nodes[1], tx_hex=tx.serialize().hex()) if __name__ == '__main__': BIP68Test().main() diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 850cb8334c..22b1918b85 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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.""" diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 9d32749a08..7730db9672 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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,6 +8,7 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates. """ from test_framework.blocktools import ( + TIME_GENESIS_BLOCK, create_block, create_coinbase, ) @@ -61,7 +62,7 @@ def cltv_invalidate(tx, failure_reason): # +-------------------------------------------------+------------+--------------+ [[OP_CHECKLOCKTIMEVERIFY], None, None], [[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None], - [[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block + [[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, TIME_GENESIS_BLOCK], [[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 50], [[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], SEQUENCE_FINAL, 50], ][failure_reason] diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py index 2e21638f80..eff4d9b149 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 coinstatsindex across nodes. @@ -221,7 +221,7 @@ class CoinStatsIndexTest(BitcoinTestFramework): self.generate(index_node, 1, sync_fun=self.no_op) res10 = index_node.gettxoutsetinfo('muhash') - assert(res8['txouts'] < res10['txouts']) + assert res8['txouts'] < res10['txouts'] self.log.info("Test that the index works with -reindex") @@ -268,12 +268,12 @@ class CoinStatsIndexTest(BitcoinTestFramework): res2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=112) assert_equal(res["bestblock"], block) assert_equal(res["muhash"], res2["muhash"]) - assert(res["muhash"] != res_invalid["muhash"]) + assert res["muhash"] != res_invalid["muhash"] # Test that requesting reorged out block by hash is still returning correct results res_invalid2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=reorg_block) assert_equal(res_invalid2["muhash"], res_invalid["muhash"]) - assert(res["muhash"] != res_invalid2["muhash"]) + assert res["muhash"] != res_invalid2["muhash"] # Add another block, so we don't depend on reconsiderblock remembering which # blocks were touched by invalidateblock diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 112dbb9e6a..d5e5ed47d6 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-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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.""" @@ -12,6 +12,9 @@ from test_framework import util class ConfArgsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index bff95c3b94..a88a97c813 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-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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 CSV soft fork activation. diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py index f606f26e70..e2bc566f53 100755 --- a/test/functional/feature_dbcrash.py +++ b/test/functional/feature_dbcrash.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. @@ -202,7 +202,6 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[3]) - self.wallet.rescan_utxos() initial_height = self.nodes[3].getblockcount() self.generate(self.nodes[3], COINBASE_MATURITY, sync_fun=self.no_op) diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 9a46839969..4a66863d91 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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). diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index b0cbcf4edf..05ee556ece 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -23,7 +23,7 @@ from test_framework.wallet import MiniWallet def small_txpuzzle_randfee( - wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment + wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs ): """Create and send a transaction with a random fee using MiniWallet. @@ -57,12 +57,15 @@ def small_txpuzzle_randfee( tx.vout[0].nValue = int((total_in - amount - fee) * COIN) tx.vout.append(deepcopy(tx.vout[0])) tx.vout[1].nValue = int(amount * COIN) + tx.rehash() + txid = tx.hash + tx_hex = tx.serialize().hex() - txid = from_node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0) + batch_reqs.append(from_node.sendrawtransaction.get_request(hexstring=tx_hex, maxfeerate=0)) unconflist.append({"txid": txid, "vout": 0, "value": total_in - amount - fee}) unconflist.append({"txid": txid, "vout": 1, "value": amount}) - return (tx.serialize().hex(), fee) + return (tx.get_vsize(), fee) def check_raw_estimates(node, fees_seen): @@ -115,13 +118,12 @@ def check_estimates(node, fees_seen): check_smart_estimates(node, fees_seen) -def send_tx(wallet, node, utxo, feerate): - """Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb).""" - return wallet.send_self_transfer( - from_node=node, +def make_tx(wallet, utxo, feerate): + """Create a 1in-1out transaction with a specific input and feerate (sat/vb).""" + return wallet.create_self_transfer( utxo_to_spend=utxo, fee_rate=Decimal(feerate * 1000) / COIN, - )['txid'] + ) class EstimateFeeTest(BitcoinTestFramework): @@ -156,9 +158,10 @@ class EstimateFeeTest(BitcoinTestFramework): # resorting to tx's that depend on the mempool when those run out for _ in range(numblocks): random.shuffle(self.confutxo) + batch_sendtx_reqs = [] for _ in range(random.randrange(100 - 50, 100 + 50)): from_index = random.randint(1, 2) - (txhex, fee) = small_txpuzzle_randfee( + (tx_bytes, fee) = small_txpuzzle_randfee( self.wallet, self.nodes[from_index], self.confutxo, @@ -166,9 +169,12 @@ class EstimateFeeTest(BitcoinTestFramework): Decimal("0.005"), min_fee, min_fee, + batch_sendtx_reqs, ) - tx_kbytes = (len(txhex) // 2) / 1000.0 + tx_kbytes = tx_bytes / 1000.0 self.fees_per_kb.append(float(fee) / tx_kbytes) + for node in self.nodes: + node.batch(batch_sendtx_reqs) self.sync_mempools(wait=0.1) mined = mining_node.getblock(self.generate(mining_node, 1)[0], True)["tx"] # update which txouts are confirmed @@ -245,14 +251,20 @@ class EstimateFeeTest(BitcoinTestFramework): assert_greater_than_or_equal(len(utxos), 250) for _ in range(5): # Broadcast 45 low fee transactions that will need to be RBF'd + txs = [] for _ in range(45): u = utxos.pop(0) - txid = send_tx(self.wallet, node, u, low_feerate) + tx = make_tx(self.wallet, u, low_feerate) utxos_to_respend.append(u) - txids_to_replace.append(txid) + txids_to_replace.append(tx["txid"]) + txs.append(tx) # Broadcast 5 low fee transaction which don't need to for _ in range(5): - send_tx(self.wallet, node, utxos.pop(0), low_feerate) + tx = make_tx(self.wallet, utxos.pop(0), low_feerate) + txs.append(tx) + batch_send_tx = [node.sendrawtransaction.get_request(tx["hex"]) for tx in txs] + for n in self.nodes: + n.batch(batch_send_tx) # Mine the transactions on another node self.sync_mempools(wait=0.1, nodes=[node, miner]) for txid in txids_to_replace: @@ -261,7 +273,12 @@ class EstimateFeeTest(BitcoinTestFramework): # RBF the low-fee transactions while len(utxos_to_respend) > 0: u = utxos_to_respend.pop(0) - send_tx(self.wallet, node, u, high_feerate) + tx = make_tx(self.wallet, u, high_feerate) + node.sendrawtransaction(tx["hex"]) + txs.append(tx) + dec_txs = [res["result"] for res in node.batch([node.decoderawtransaction.get_request(tx["hex"]) for tx in txs])] + self.wallet.scan_txs(dec_txs) + # Mine the last replacement txs self.sync_mempools(wait=0.1, nodes=[node, miner]) @@ -280,7 +297,6 @@ class EstimateFeeTest(BitcoinTestFramework): # Split two coinbases into many small utxos self.start_node(0) self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() self.initial_split(self.nodes[0]) self.log.info("Finished splitting") diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py index 945ece6a33..bb4104bf8e 100755 --- a/test/functional/feature_filelock.py +++ b/test/functional/feature_filelock.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 that it's not possible to start a second bitcoind instance using the same datadir or wallet.""" @@ -11,6 +11,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.test_node import ErrorMatch class FilelockTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 4b7a50c1c7..77a056346a 100755 --- a/test/functional/feature_index_prune.py +++ b/test/functional/feature_index_prune.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 indices in conjunction with prune.""" @@ -62,7 +62,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework): for node in filter_nodes: assert_greater_than(len(node.getblockfilter(tip)['filter']), 0) for node in stats_nodes: - assert(node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']) + assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash'] self.mine_batches(500) self.sync_index(height=700) @@ -80,14 +80,14 @@ class FeatureIndexPruneTest(BitcoinTestFramework): for node in filter_nodes: assert_greater_than(len(node.getblockfilter(tip)['filter']), 0) for node in stats_nodes: - assert(node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']) + assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash'] self.log.info("check if we can access the blockfilter and coinstats of a pruned block") height_hash = self.nodes[0].getblockhash(2) for node in filter_nodes: assert_greater_than(len(node.getblockfilter(height_hash)['filter']), 0) for node in stats_nodes: - assert(node.gettxoutsetinfo(hash_type="muhash", hash_or_height=height_hash)['muhash']) + assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=height_hash)['muhash'] # mine and sync index up to a height that will later be the pruneheight self.generate(self.nodes[0], 51) diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index 56d093c396..70a802dc58 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Stress tests related to node initialization.""" @@ -17,6 +17,9 @@ class InitStressTest(BitcoinTestFramework): subsequent starts. """ + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = False self.num_nodes = 1 diff --git a/test/functional/feature_maxtipage.py b/test/functional/feature_maxtipage.py index ddc2102542..51f37ef1e0 100755 --- a/test/functional/feature_maxtipage.py +++ b/test/functional/feature_maxtipage.py @@ -22,23 +22,24 @@ class MaxTipAgeTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 2 - def test_maxtipage(self, maxtipage, set_parameter=True): + def test_maxtipage(self, maxtipage, set_parameter=True, test_deltas=True): node_miner = self.nodes[0] node_ibd = self.nodes[1] self.restart_node(1, [f'-maxtipage={maxtipage}'] if set_parameter else None) self.connect_nodes(0, 1) - - # tips older than maximum age -> stay in IBD cur_time = int(time.time()) - node_ibd.setmocktime(cur_time) - for delta in [5, 4, 3, 2, 1]: - node_miner.setmocktime(cur_time - maxtipage - delta) - self.generate(node_miner, 1) - assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], True) + + if test_deltas: + # tips older than maximum age -> stay in IBD + node_ibd.setmocktime(cur_time) + for delta in [5, 4, 3, 2, 1]: + node_miner.setmocktime(cur_time - maxtipage - delta) + self.generate(node_miner, 1) + assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], True) # tip within maximum age -> leave IBD - node_miner.setmocktime(cur_time - maxtipage) + node_miner.setmocktime(max(cur_time - maxtipage, 0)) self.generate(node_miner, 1) assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], False) @@ -51,6 +52,10 @@ class MaxTipAgeTest(BitcoinTestFramework): self.log.info(f"Test IBD with maximum tip age of {hours} hours (-maxtipage={maxtipage}).") self.test_maxtipage(maxtipage) + max_long_val = 9223372036854775807 + self.log.info(f"Test IBD with highest allowable maximum tip age ({max_long_val}).") + self.test_maxtipage(max_long_val, test_deltas=False) + if __name__ == '__main__': MaxTipAgeTest().main() diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index 3ea412002a..28a8959e93 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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. diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py index fb4024b1b0..078d2ef63c 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index e038afa1ad..8cb633d454 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -24,11 +24,14 @@ def notify_outputname(walletname, txid): class NotificationsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True # The experimental syscall sandbox feature (-sandbox) is not compatible with -alertnotify, - # -blocknotify or -walletnotify (which all invoke execve). + # -blocknotify, -walletnotify or -shutdownnotify (which all invoke execve). self.disable_syscall_sandbox = True def setup_network(self): @@ -36,14 +39,18 @@ class NotificationsTest(BitcoinTestFramework): self.alertnotify_dir = os.path.join(self.options.tmpdir, "alertnotify") self.blocknotify_dir = os.path.join(self.options.tmpdir, "blocknotify") self.walletnotify_dir = os.path.join(self.options.tmpdir, "walletnotify") + self.shutdownnotify_dir = os.path.join(self.options.tmpdir, "shutdownnotify") + self.shutdownnotify_file = os.path.join(self.shutdownnotify_dir, "shutdownnotify.txt") os.mkdir(self.alertnotify_dir) os.mkdir(self.blocknotify_dir) os.mkdir(self.walletnotify_dir) + os.mkdir(self.shutdownnotify_dir) # -alertnotify and -blocknotify on node0, walletnotify on node1 self.extra_args = [[ f"-alertnotify=echo > {os.path.join(self.alertnotify_dir, '%s')}", f"-blocknotify=echo > {os.path.join(self.blocknotify_dir, '%s')}", + f"-shutdownnotify=echo > {self.shutdownnotify_file}", ], [ f"-walletnotify=echo %h_%b > {os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))}", ]] @@ -159,6 +166,10 @@ class NotificationsTest(BitcoinTestFramework): # TODO: add test for `-alertnotify` large fork notifications + self.log.info("test -shutdownnotify") + self.stop_nodes() + self.wait_until(lambda: os.path.isfile(self.shutdownnotify_file), timeout=10) + def expect_wallet_notify(self, tx_details): self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_details), timeout=10) # Should have no more and no less files than expected diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index 9bfb79057e..d7558c830e 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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. diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py index 18b079cd71..662007d65e 100755 --- a/test/functional/feature_proxy.py +++ b/test/functional/feature_proxy.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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 7dbeccbc09..664ed779db 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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,8 +10,11 @@ This test takes 30 mins or more (up to 2 hours) """ import os -from test_framework.blocktools import create_coinbase -from test_framework.messages import CBlock +from test_framework.blocktools import ( + MIN_BLOCKS_TO_KEEP, + create_block, + create_coinbase, +) from test_framework.script import ( CScript, OP_NOP, @@ -48,21 +51,7 @@ def mine_large_blocks(node, n): previousblockhash = int(best_block["hash"], 16) for _ in range(n): - # Build the coinbase transaction (with large scriptPubKey) - coinbase_tx = create_coinbase(height) - coinbase_tx.vin[0].nSequence = 2 ** 32 - 1 - coinbase_tx.vout[0].scriptPubKey = big_script - coinbase_tx.rehash() - - # Build the block - block = CBlock() - block.nVersion = best_block["version"] - block.hashPrevBlock = previousblockhash - block.nTime = mine_large_blocks.nTime - block.nBits = int('207fffff', 16) - block.nNonce = 0 - block.vtx = [coinbase_tx] - block.hashMerkleRoot = block.calc_merkle_root() + block = create_block(hashprev=previousblockhash, ntime=mine_large_blocks.nTime, coinbase=create_coinbase(height, script_pubkey=big_script)) block.solve() # Submit to the node @@ -76,6 +65,9 @@ def calc_usage(blockdir): return sum(os.path.getsize(blockdir + f) for f in os.listdir(blockdir) if os.path.isfile(os.path.join(blockdir, f))) / (1024. * 1024.) class PruneTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 6 @@ -92,7 +84,7 @@ class PruneTest(BitcoinTestFramework): ["-maxreceivebuffer=20000", "-prune=550"], ["-maxreceivebuffer=20000"], ["-maxreceivebuffer=20000"], - ["-prune=550"], + ["-prune=550", "-blockfilterindex=1"], ] self.rpc_timeout = 120 @@ -342,7 +334,7 @@ class PruneTest(BitcoinTestFramework): assert has_block(2), "blk00002.dat is still there, should be pruned by now" # advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat) - self.generate(node, 288, sync_fun=self.no_op) + self.generate(node, MIN_BLOCKS_TO_KEEP, sync_fun=self.no_op) prune(1000) assert not has_block(2), "blk00002.dat is still there, should be pruned by now" assert not has_block(3), "blk00003.dat is still there, should be pruned by now" @@ -364,7 +356,7 @@ class PruneTest(BitcoinTestFramework): self.connect_nodes(0, 5) nds = [self.nodes[0], self.nodes[5]] self.sync_blocks(nds, wait=5, timeout=300) - self.restart_node(5, extra_args=["-prune=550"]) # restart to trigger rescan + self.restart_node(5, extra_args=["-prune=550", "-blockfilterindex=1"]) # restart to trigger rescan self.log.info("Success") def run_test(self): @@ -480,7 +472,20 @@ class PruneTest(BitcoinTestFramework): self.log.info("Test invalid pruning command line options") self.test_invalid_command_line_options() + self.test_scanblocks_pruned() + self.log.info("Done") + def test_scanblocks_pruned(self): + node = self.nodes[5] + genesis_blockhash = node.getblockhash(0) + false_positive_spk = bytes.fromhex("001400000000000000000000000000000000000cadcb") + + assert genesis_blockhash in node.scanblocks( + "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0)['relevant_blocks'] + + assert_raises_rpc_error(-1, "Block not available (pruned data)", node.scanblocks, + "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0, "basic", {"filter_false_positives": True}) + if __name__ == '__main__': PruneTest().main() diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 7603248ae5..0a84a66a8f 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -21,6 +21,9 @@ from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE MAX_REPLACEMENT_LIMIT = 100 class ReplaceByFeeTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.extra_args = [ @@ -39,10 +42,6 @@ class ReplaceByFeeTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - # the pre-mined test framework chain contains coinbase outputs to the - # MiniWallet's default address in blocks 76-100 (see method - # BitcoinTestFramework._initialize_chain()) - self.wallet.rescan_utxos() self.log.info("Running test simple doublespend...") self.test_simple_doublespend() @@ -395,7 +394,6 @@ class ReplaceByFeeTest(BitcoinTestFramework): """ normal_node = self.nodes[1] wallet = MiniWallet(normal_node) - wallet.rescan_utxos() # Clear mempools to avoid cross-node sync failure. for node in self.nodes: self.generate(node, 1) diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 7f2a615be1..77f3e4feda 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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.""" @@ -78,6 +78,9 @@ txs_mined = {} # txindex from txid to blockhash class SegWitTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py index 4c1e48af6d..b41fe378af 100755 --- a/test/functional/feature_signet.py +++ b/test/functional/feature_signet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 basic signet functionality""" diff --git a/test/functional/feature_startupnotify.py b/test/functional/feature_startupnotify.py index c6aa837768..ff5272b281 100755 --- a/test/functional/feature_startupnotify.py +++ b/test/functional/feature_startupnotify.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 -startupnotify.""" @@ -29,9 +29,14 @@ class StartupNotifyTest(BitcoinTestFramework): self.wait_until(lambda: os.path.exists(tmpdir_file)) self.log.info("Test -startupnotify is executed once") - with open(tmpdir_file, "r", encoding="utf8") as f: - file_content = f.read() - assert_equal(file_content.count(FILE_NAME), 1) + + def get_count(): + with open(tmpdir_file, "r", encoding="utf8") as f: + file_content = f.read() + return file_content.count(FILE_NAME) + + self.wait_until(lambda: get_count() > 0) + assert_equal(get_count(), 1) self.log.info("Test node is fully started") assert_equal(self.nodes[0].getblockcount(), 200) diff --git a/test/functional/feature_syscall_sandbox.py b/test/functional/feature_syscall_sandbox.py index e430542845..2200f6c2e6 100755 --- a/test/functional/feature_syscall_sandbox.py +++ b/test/functional/feature_syscall_sandbox.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 aborts if a disallowed syscall is used when compiled with the syscall sandbox.""" diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index cbb2e0338b..144e01c367 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 Taproot softfork (BIPs 340-342) @@ -96,7 +96,14 @@ from test_framework.util import ( assert_equal, random_bytes, ) -from test_framework.key import generate_privkey, compute_xonly_pubkey, sign_schnorr, tweak_add_privkey, ECKey +from test_framework.key import ( + generate_privkey, + compute_xonly_pubkey, + sign_schnorr, + tweak_add_privkey, + ECKey, + SECP256K1 +) from test_framework.address import ( hash160, program_to_witness, @@ -661,6 +668,44 @@ def spenders_taproot_active(): # Test with signature with bit flipped. add_spender(spenders, "sig/bitflip", tap=tap, key=secs[0], failure={"signature": bitflipper(default_signature)}, **ERR_SIG_SCHNORR) + # == Test involving an internal public key not on the curve == + + # X-only public keys are 32 bytes, but not every 32-byte array is a valid public key; only + # around 50% of them are. This does not affect users using correct software; these "keys" have + # no corresponding private key, and thus will never appear as output of key + # generation/derivation/tweaking. + # + # Using an invalid public key as P2TR output key makes the UTXO unspendable. Revealing an + # invalid public key as internal key in a P2TR script path spend also makes the spend invalid. + # These conditions are explicitly spelled out in BIP341. + # + # It is however hard to create test vectors for this, because it involves "guessing" how a + # hypothetical incorrect implementation deals with an obviously-invalid condition, and making + # sure that guessed behavior (accepting it in certain condition) doesn't occur. + # + # The test case added here tries to detect a very specific bug a verifier could have: if they + # don't verify whether or not a revealed internal public key in a script path spend is valid, + # and (correctly) implement output_key == tweak(internal_key, tweakval) but (incorrectly) treat + # tweak(invalid_key, tweakval) as equal the public key corresponding to private key tweakval. + # This may seem like a far-fetched edge condition to test for, but in fact, the BIP341 wallet + # pseudocode did exactly that (but obviously only triggerable by someone invoking the tweaking + # function with an invalid public key, which shouldn't happen). + + # Generate an invalid public key + while True: + invalid_pub = random_bytes(32) + if not SECP256K1.is_x_coord(int.from_bytes(invalid_pub, 'big')): + break + + # Implement a test case that detects validation logic which maps invalid public keys to the + # point at infinity in the tweaking logic. + tap = taproot_construct(invalid_pub, [("true", CScript([OP_1]))], treat_internal_as_infinity=True) + add_spender(spenders, "output/invalid_x", tap=tap, key_tweaked=tap.tweak, failure={"leaf": "true", "inputs": []}, **ERR_WITNESS_PROGRAM_MISMATCH) + + # Do the same thing without invalid point, to make sure there is no mistake in the test logic. + tap = taproot_construct(pubs[0], [("true", CScript([OP_1]))]) + add_spender(spenders, "output/invalid_x_mock", tap=tap, key=secs[0], leaf="true", inputs=[]) + # == Tests for signature hashing == # Run all tests once with no annex, and once with a valid random annex. @@ -1229,6 +1274,7 @@ UTXOData = namedtuple('UTXOData', 'outpoint,output,spender') class TaprootTest(BitcoinTestFramework): def add_options(self, parser): + self.add_wallet_options(parser) parser.add_argument("--dumptests", dest="dump_tests", default=False, action="store_true", help="Dump generated test cases to directory set by TEST_DUMP_DIR environment variable") @@ -1246,7 +1292,7 @@ class TaprootTest(BitcoinTestFramework): # It is not impossible to fit enough tapscript sigops to hit the old 80k limit without # busting txin-level limits. We simply have to account for the p2pk outputs in all # transactions. - extra_output_script = CScript([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR)) + extra_output_script = CScript(bytes([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR))) coinbase_tx = create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees) block = create_block(self.tip, coinbase_tx, self.lastblocktime + 1, txlist=txs) diff --git a/test/functional/feature_txindex_compatibility.py b/test/functional/feature_txindex_compatibility.py index 20b023d82c..48fefaa0ba 100755 --- a/test/functional/feature_txindex_compatibility.py +++ b/test/functional/feature_txindex_compatibility.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 legacy txindex will be disabled on upgrade. @@ -14,7 +14,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.wallet import MiniWallet -class MempoolCompatibilityTest(BitcoinTestFramework): +class TxindexCompatibilityTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 self.extra_args = [ @@ -33,7 +33,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework): versions=[ 160300, # Last release with legacy txindex None, # For MiniWallet, without migration code - 200100, # Any release with migration code (0.17.x - 22.x) + 220000, # Last release with migration code (0.17.x - 22.x) ], ) self.start_nodes() @@ -42,7 +42,6 @@ class MempoolCompatibilityTest(BitcoinTestFramework): def run_test(self): mini_wallet = MiniWallet(self.nodes[1]) - mini_wallet.rescan_utxos() spend_utxo = mini_wallet.get_utxo() mini_wallet.send_self_transfer(from_node=self.nodes[1], utxo_to_spend=spend_utxo) self.generate(self.nodes[1], 1) @@ -89,4 +88,4 @@ class MempoolCompatibilityTest(BitcoinTestFramework): if __name__ == "__main__": - MempoolCompatibilityTest().main() + TxindexCompatibilityTest().main() diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py index 4d486bc6f4..0f510ced89 100755 --- a/test/functional/feature_utxo_set_hash.py +++ b/test/functional/feature_utxo_set_hash.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 UTXO set hash value calculation in gettxoutsetinfo.""" diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 1572463308..0a9e1d4448 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-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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. diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index db5564ac50..25ea557217 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-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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""" @@ -66,11 +66,12 @@ def cli_get_info_string_to_dict(cli_get_info_string): class TestBitcoinCli(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - if self.is_specified_wallet_compiled(): - self.requires_wallet = True def skip_test_if_missing_module(self): self.skip_if_no_cli() @@ -84,6 +85,15 @@ class TestBitcoinCli(BitcoinTestFramework): rpc_response = self.nodes[0].getblockchaininfo() assert_equal(cli_response, rpc_response) + self.log.info("Test named arguments") + assert_equal(self.nodes[0].cli.echo(0, 1, arg3=3, arg5=5), ['0', '1', None, '3', None, '5']) + assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", self.nodes[0].cli.echo, 0, 1, arg1=1) + assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", self.nodes[0].cli.echo, 0, None, 2, arg1=1) + + self.log.info("Test that later cli named arguments values silently overwrite earlier ones") + assert_equal(self.nodes[0].cli("-named", "echo", "arg0=0", "arg1=1", "arg2=2", "arg1=3").send_cli(), ['0', '3', '2']) + assert_raises_rpc_error(-8, "Parameter args specified multiple times", self.nodes[0].cli("-named", "echo", "args=[0,1,2,3]", "4", "5", "6", ).send_cli) + user, password = get_auth_cookie(self.nodes[0].datadir, self.chain) self.log.info("Test -stdinrpcpass option") @@ -114,6 +124,7 @@ class TestBitcoinCli(BitcoinTestFramework): self.log.info("Test -getinfo returns expected network and blockchain info") if self.is_specified_wallet_compiled(): + self.import_deterministic_coinbase_privkeys() self.nodes[0].encryptwallet(password) cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli() cli_get_info = cli_get_info_string_to_dict(cli_get_info_string) diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index 24252610be..0dddc8946a 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -96,7 +96,6 @@ class RESTTest (BitcoinTestFramework): def run_test(self): self.url = urllib.parse.urlparse(self.nodes[0].url) self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() self.log.info("Broadcast test transaction and sync nodes") txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN)) diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py index 48082f3a17..3725c89719 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 some generic aspects of the RPC interface.""" @@ -25,7 +25,7 @@ def expect_http_status(expected_http_status, expected_rpc_code, def test_work_queue_getblock(node, got_exceeded_error): while not got_exceeded_error: try: - node.cli('getrpcinfo').send_cli() + node.cli("waitfornewblock", "500").send_cli() except subprocess.CalledProcessError as e: assert_equal(e.output, 'error: Server response: Work queue depth exceeded\n') got_exceeded_error.append(True) diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py index ef32feda99..a3c830bb51 100755 --- a/test/functional/interface_usdt_coinselection.py +++ b/test/functional/interface_usdt_coinselection.py @@ -97,6 +97,9 @@ int trace_aps_create_tx(struct pt_regs *ctx) { class CoinSelectionTracepointTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py index 2280de1479..23785b1e8a 100755 --- a/test/functional/interface_usdt_utxocache.py +++ b/test/functional/interface_usdt_utxocache.py @@ -144,7 +144,6 @@ class UTXOCacheTracepointTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.generate(self.wallet, 101) self.test_uncache() self.test_add_spent() @@ -357,8 +356,8 @@ class UTXOCacheTracepointTest(BitcoinTestFramework): "size": event.size }) # sanity checks only - assert(event.memory > 0) - assert(event.duration > 0) + assert event.memory > 0 + assert event.duration > 0 handle_flush_succeeds += 1 bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush) diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py index 8953dd023b..4323aef771 100755 --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -112,7 +112,7 @@ class ValidationTracepointTest(BitcoinTestFramework): assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs) assert_equal(0, event.sigops) # no sigops in coinbase tx # only plausibility checks - assert(event.duration > 0) + assert event.duration > 0 del expected_blocks[block_hash] blocks_checked += 1 diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 7d8d10589b..2f41f9aa53 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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.""" @@ -22,6 +22,7 @@ from test_framework.messages import ( from test_framework.util import ( assert_equal, assert_raises_rpc_error, + p2p_port, ) from test_framework.wallet import ( MiniWallet, @@ -106,6 +107,7 @@ class ZMQTest (BitcoinTestFramework): # This test isn't testing txn relay/timing, so set whitelist on the # peers for instant txn relay. This speeds up the test run time 2-3x. self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes + self.zmq_port_base = p2p_port(self.num_nodes + 1) def skip_test_if_missing_module(self): self.skip_if_no_py3_zmq() @@ -179,7 +181,7 @@ class ZMQTest (BitcoinTestFramework): # Invalid zmq arguments don't take down the node, see #17185. self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"]) - address = 'tcp://127.0.0.1:28332' + address = f"tcp://127.0.0.1:{self.zmq_port_base}" subs = self.setup_zmq_test([(topic, address) for topic in ["hashblock", "hashtx", "rawblock", "rawtx"]]) hashblock = subs[0] @@ -213,7 +215,6 @@ class ZMQTest (BitcoinTestFramework): assert_equal([txid.hex()], self.nodes[1].getblock(hash)["tx"]) - self.wallet.rescan_utxos() self.log.info("Wait for tx from second node") payment_tx = self.wallet.send_self_transfer(from_node=self.nodes[1]) payment_txid = payment_tx['txid'] @@ -246,7 +247,7 @@ class ZMQTest (BitcoinTestFramework): def test_reorg(self): - address = 'tcp://127.0.0.1:28333' + address = f"tcp://127.0.0.1:{self.zmq_port_base}" # Should only notify the tip if a reorg occurs hashblock, hashtx = self.setup_zmq_test( @@ -300,7 +301,7 @@ class ZMQTest (BitcoinTestFramework): <32-byte hash>A<8-byte LE uint> : Transactionhash added mempool """ self.log.info("Testing 'sequence' publisher") - [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")]) + [seq] = self.setup_zmq_test([("sequence", f"tcp://127.0.0.1:{self.zmq_port_base}")]) self.disconnect_nodes(0, 1) # Mempool sequence number starts at 1 @@ -444,7 +445,7 @@ class ZMQTest (BitcoinTestFramework): """ self.log.info("Testing 'mempool sync' usage of sequence notifier") - [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")]) + [seq] = self.setup_zmq_test([("sequence", f"tcp://127.0.0.1:{self.zmq_port_base}")]) # In-memory counter, should always start at 1 next_mempool_seq = self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"] @@ -549,8 +550,8 @@ class ZMQTest (BitcoinTestFramework): # chain lengths on node0 and node1; for this test we only need node0, so # we can disable syncing blocks on the setup) subscribers = self.setup_zmq_test([ - ("hashblock", "tcp://127.0.0.1:28334"), - ("hashblock", "tcp://127.0.0.1:28335"), + ("hashblock", f"tcp://127.0.0.1:{self.zmq_port_base + 1}"), + ("hashblock", f"tcp://127.0.0.1:{self.zmq_port_base + 2}"), ], sync_blocks=False) # Generate 1 block in nodes[0] and receive all notifications @@ -567,7 +568,7 @@ class ZMQTest (BitcoinTestFramework): self.log.info("Testing IPv6") # Set up subscriber using IPv6 loopback address subscribers = self.setup_zmq_test([ - ("hashblock", "tcp://[::1]:28332") + ("hashblock", f"tcp://[::1]:{self.zmq_port_base}") ], ipv6=True) # Generate 1 block in nodes[0] diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 02ec18140c..362b407062 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 acceptance of raw transactions.""" @@ -14,7 +14,9 @@ from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, COIN, COutPoint, + CTransaction, CTxIn, + CTxInWitness, CTxOut, MAX_BLOCK_WEIGHT, MAX_MONEY, @@ -26,13 +28,19 @@ from test_framework.script import ( OP_0, OP_HASH160, OP_RETURN, + OP_TRUE, ) from test_framework.script_util import ( + DUMMY_MIN_OP_RETURN_SCRIPT, keys_to_multisig_script, + MIN_PADDING, + MIN_STANDARD_TX_NONWITNESS_SIZE, script_to_p2sh_script, + script_to_p2wsh_script, ) from test_framework.util import ( assert_equal, + assert_greater_than, assert_raises_rpc_error, ) from test_framework.wallet import MiniWallet @@ -50,14 +58,17 @@ class MempoolAcceptanceTest(BitcoinTestFramework): """Wrapper to check result of testmempoolaccept on node_0's mempool""" result_test = self.nodes[0].testmempoolaccept(*args, **kwargs) for r in result_test: - r.pop('wtxid') # Skip check for now + # Skip these checks for now + r.pop('wtxid') + if "fees" in r: + r["fees"].pop("effective-feerate") + r["fees"].pop("effective-includes") assert_equal(result_expected, result_test) assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state def run_test(self): node = self.nodes[0] self.wallet = MiniWallet(node) - self.wallet.rescan_utxos() self.log.info('Start with empty mempool, and 200 blocks') self.mempool_size = 0 @@ -333,6 +344,35 @@ class MempoolAcceptanceTest(BitcoinTestFramework): maxfeerate=0, ) + # Prep for tiny-tx tests with wsh(OP_TRUE) output + seed_tx = self.wallet.send_to(from_node=node, scriptPubKey=script_to_p2wsh_script(CScript([OP_TRUE])), amount=COIN) + self.generate(node, 1) + + self.log.info('A tiny transaction(in non-witness bytes) that is disallowed') + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(int(seed_tx[0], 16), seed_tx[1]), b"", SEQUENCE_FINAL)) + tx.wit.vtxinwit = [CTxInWitness()] + tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2))))) + # Note it's only non-witness size that matters! + assert_equal(len(tx.serialize_without_witness()), 64) + assert_equal(MIN_STANDARD_TX_NONWITNESS_SIZE - 1, 64) + assert_greater_than(len(tx.serialize()), 64) + + self.check_mempool_result( + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size-small'}], + rawtxs=[tx.serialize().hex()], + maxfeerate=0, + ) + + self.log.info('Minimally-small transaction(in non-witness bytes) that is allowed') + tx.vout[0] = CTxOut(COIN - 1000, DUMMY_MIN_OP_RETURN_SCRIPT) + assert_equal(len(tx.serialize_without_witness()), MIN_STANDARD_TX_NONWITNESS_SIZE) + self.check_mempool_result( + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}], + rawtxs=[tx.serialize().hex()], + maxfeerate=0, + ) if __name__ == '__main__': MempoolAcceptanceTest().main() diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index c545a7f68d..a7bdc49695 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 mempool.dat is both backward and forward compatible between versions @@ -7,7 +7,7 @@ NOTE: The test is designed to prevent cases when compatibility is broken accidentally. In case we need to break mempool compatibility we can continue to use the test by just bumping the version number. -The previous release v0.19.1 is required by this test, see test/README.md. +Previous releases are required by this test, see test/README.md. """ import os @@ -23,23 +23,22 @@ from test_framework.wallet import ( class MempoolCompatibilityTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.wallet_names = [None] def skip_test_if_missing_module(self): self.skip_if_no_previous_releases() def setup_network(self): self.add_nodes(self.num_nodes, versions=[ - 190100, # oldest version with getmempoolinfo.loaded (used to avoid intermittent issues) + 200100, # Last release with previous mempool format None, ]) self.start_nodes() - self.import_deterministic_coinbase_privkeys() def run_test(self): self.log.info("Test that mempool.dat is compatible between versions") old_node, new_node = self.nodes + assert "unbroadcastcount" not in old_node.getmempoolinfo() new_wallet = MiniWallet(new_node, mode=MiniWalletMode.RAW_P2PK) self.generate(new_wallet, 1, sync_fun=self.no_op) self.generate(new_node, COINBASE_MATURITY, sync_fun=self.no_op) @@ -48,11 +47,10 @@ class MempoolCompatibilityTest(BitcoinTestFramework): # unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`. self.connect_nodes(0, 1) self.sync_blocks() - recipient = old_node.getnewaddress() self.stop_node(1) self.log.info("Add a transaction to mempool on old node and shutdown") - old_tx_hash = old_node.sendtoaddress(recipient, 0.0001) + old_tx_hash = new_wallet.send_self_transfer(from_node=old_node)["txid"] assert old_tx_hash in old_node.getrawmempool() self.stop_node(0) diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py index 13df564a37..c370d8fa91 100755 --- a/test/functional/mempool_datacarrier.py +++ b/test/functional/mempool_datacarrier.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 datacarrier functionality""" @@ -44,7 +44,6 @@ class DataCarrierTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() # By default, only 80 bytes are used for data (+1 for OP_RETURN, +2 for the pushdata opcodes). default_size_data = random_bytes(MAX_OP_RETURN_RELAY - 3) diff --git a/test/functional/mempool_dust.py b/test/functional/mempool_dust.py new file mode 100755 index 0000000000..41a26e82da --- /dev/null +++ b/test/functional/mempool_dust.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 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 dust limit mempool policy (`-dustrelayfee` parameter)""" +from decimal import Decimal + +from test_framework.key import ECKey +from test_framework.messages import ( + COIN, + CTxOut, +) +from test_framework.script import ( + CScript, + OP_RETURN, + OP_TRUE, +) +from test_framework.script_util import ( + key_to_p2pk_script, + key_to_p2pkh_script, + key_to_p2wpkh_script, + keys_to_multisig_script, + output_key_to_p2tr_script, + program_to_witness_script, + script_to_p2sh_script, + script_to_p2wsh_script, +) +from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_node import TestNode +from test_framework.util import ( + assert_equal, + get_fee, +) +from test_framework.wallet import MiniWallet + + +DUST_RELAY_TX_FEE = 3000 # default setting [sat/kvB] + + +class DustRelayFeeTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def test_dust_output(self, node: TestNode, dust_relay_fee: Decimal, + output_script: CScript, type_desc: str) -> None: + # determine dust threshold (see `GetDustThreshold`) + if output_script[0] == OP_RETURN: + dust_threshold = 0 + else: + tx_size = len(CTxOut(nValue=0, scriptPubKey=output_script).serialize()) + tx_size += 67 if output_script.IsWitnessProgram() else 148 + dust_threshold = int(get_fee(tx_size, dust_relay_fee) * COIN) + self.log.info(f"-> Test {type_desc} output (size {len(output_script)}, limit {dust_threshold})") + + # amount right on the dust threshold should pass + tx = self.wallet.create_self_transfer()["tx"] + tx.vout.append(CTxOut(nValue=dust_threshold, scriptPubKey=output_script)) + tx.vout[0].nValue -= dust_threshold # keep total output value constant + tx_good_hex = tx.serialize().hex() + res = node.testmempoolaccept([tx_good_hex])[0] + assert_equal(res['allowed'], True) + + # amount just below the dust threshold should fail + if dust_threshold > 0: + tx.vout[1].nValue -= 1 + res = node.testmempoolaccept([tx.serialize().hex()])[0] + assert_equal(res['allowed'], False) + assert_equal(res['reject-reason'], 'dust') + + # finally send the transaction to avoid running out of MiniWallet UTXOs + self.wallet.sendrawtransaction(from_node=node, tx_hex=tx_good_hex) + + def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + + # prepare output scripts of each standard type + key = ECKey() + key.generate(compressed=False) + uncompressed_pubkey = key.get_pubkey().get_bytes() + key.generate(compressed=True) + pubkey = key.get_pubkey().get_bytes() + + output_scripts = ( + (key_to_p2pk_script(uncompressed_pubkey), "P2PK (uncompressed)"), + (key_to_p2pk_script(pubkey), "P2PK (compressed)"), + (key_to_p2pkh_script(pubkey), "P2PKH"), + (script_to_p2sh_script(CScript([OP_TRUE])), "P2SH"), + (key_to_p2wpkh_script(pubkey), "P2WPKH"), + (script_to_p2wsh_script(CScript([OP_TRUE])), "P2WSH"), + (output_key_to_p2tr_script(pubkey[1:]), "P2TR"), + # witness programs for segwitv2+ can be between 2 and 40 bytes + (program_to_witness_script(2, b'\x66' * 2), "P2?? (future witness version 2)"), + (program_to_witness_script(16, b'\x77' * 40), "P2?? (future witness version 16)"), + # largest possible output script considered standard + (keys_to_multisig_script([uncompressed_pubkey]*3), "bare multisig (m-of-3)"), + (CScript([OP_RETURN, b'superimportanthash']), "null data (OP_RETURN)"), + ) + + # test default (no parameter), disabled (=0) and a bunch of arbitrary dust fee rates [sat/kvB] + for dustfee_sat_kvb in (DUST_RELAY_TX_FEE, 0, 1, 66, 500, 1337, 12345, 21212, 333333): + dustfee_btc_kvb = dustfee_sat_kvb / Decimal(COIN) + if dustfee_sat_kvb == DUST_RELAY_TX_FEE: + self.log.info(f"Test default dust limit setting ({dustfee_sat_kvb} sat/kvB)...") + else: + dust_parameter = f"-dustrelayfee={dustfee_btc_kvb:.8f}" + self.log.info(f"Test dust limit setting {dust_parameter} ({dustfee_sat_kvb} sat/kvB)...") + self.restart_node(0, extra_args=[dust_parameter]) + + for output_script, description in output_scripts: + self.test_dust_output(self.nodes[0], dustfee_btc_kvb, output_script, description) + self.generate(self.nodes[0], 1) + + +if __name__ == '__main__': + DustRelayFeeTest().main() diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py index 21721177e6..15a5f765df 100755 --- a/test/functional/mempool_expiry.py +++ b/test/functional/mempool_expiry.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 that a mempool transaction expires after a given timeout and that its @@ -12,7 +12,6 @@ definable expiry timeout via the '-mempoolexpiry=<n>' command line argument from datetime import timedelta -from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import DEFAULT_MEMPOOL_EXPIRY_HOURS from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -27,17 +26,11 @@ CUSTOM_MEMPOOL_EXPIRY = 10 # hours class MempoolExpiryTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = True def test_transaction_expiry(self, timeout): """Tests that a transaction expires after the expiry timeout and its children are removed as well.""" node = self.nodes[0] - self.wallet = MiniWallet(node) - - # Add enough mature utxos to the wallet so that all txs spend confirmed coins. - self.generate(self.wallet, 4) - self.generate(node, COINBASE_MATURITY) # Send a parent transaction that will expire. parent_txid = self.wallet.send_self_transfer(from_node=node)['txid'] @@ -97,6 +90,8 @@ class MempoolExpiryTest(BitcoinTestFramework): assert_equal(half_expiry_time, node.getmempoolentry(independent_txid)['time']) def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + self.log.info('Test default mempool expiry timeout of %d hours.' % DEFAULT_MEMPOOL_EXPIRY_HOURS) self.test_transaction_expiry(DEFAULT_MEMPOOL_EXPIRY_HOURS) diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 7080662b49..d38a37f952 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -25,7 +25,6 @@ class MempoolLimitTest(BitcoinTestFramework): self.extra_args = [[ "-datacarriersize=100000", "-maxmempool=5", - "-spendzeroconfchange=0", ]] self.supports_cli = False diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py index 1f12e93982..63f5a3e3d3 100755 --- a/test/functional/mempool_package_limits.py +++ b/test/functional/mempool_package_limits.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 limiting mempool and package ancestors/descendants.""" @@ -45,7 +45,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): assert_equal(0, node.getmempoolinfo()["size"]) chain_hex = [] - chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count) + chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)[-1]["new_utxo"] # in-package transactions for _ in range(package_count): tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo) @@ -100,13 +100,13 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): package_hex = [] # Chain A (M2a... M12a) - chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0]) + chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0])[-1]["new_utxo"] # Pa pa_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_a_tip_utxo)["hex"] package_hex.append(pa_hex) # Chain B (M2b... M13b) - chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1]) + chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1])[-1]["new_utxo"] # Pb pb_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_b_tip_utxo)["hex"] package_hex.append(pb_hex) @@ -145,7 +145,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos'] # Chain M2...M24 - self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0]) + self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0])[-1]["new_utxo"] # P1 p1_tx = self.wallet.create_self_transfer(utxo_to_spend=m1_utxos[1]) @@ -191,7 +191,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): # Two chains of 13 transactions each for _ in range(2): - chain_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12) + chain_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)[-1]["new_utxo"] # Save the 13th transaction for the package tx = self.wallet.create_self_transfer(utxo_to_spend=chain_tip_utxo) package_hex.append(tx["hex"]) @@ -234,7 +234,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages") # Two chains of 12 transactions each for _ in range(2): - chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12) + chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)[-1]["new_utxo"] # last 2 transactions will be the parents of Pc pc_parent_utxos.append(chaintip_utxo) diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py index 9a981bd5a5..921c190668 100755 --- a/test/functional/mempool_package_onemore.py +++ b/test/functional/mempool_package_onemore.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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 carve-out allowing one final transaction in @@ -31,7 +31,6 @@ class MempoolPackagesTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() # DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine chain = [] diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index def0b1fce4..0387282862 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.blocktools import COINBASE_MATURITY from test_framework.messages import ( COIN, DEFAULT_ANCESTOR_LIMIT, @@ -17,9 +16,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, - chain_transaction, ) - +from test_framework.wallet import MiniWallet # custom limits for node1 CUSTOM_ANCESTOR_LIMIT = 5 @@ -28,6 +26,9 @@ assert CUSTOM_DESCENDANT_LIMIT >= CUSTOM_ANCESTOR_LIMIT class MempoolPackagesTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.extra_args = [ @@ -42,43 +43,33 @@ class MempoolPackagesTest(BitcoinTestFramework): ], ] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): - # Mine some blocks and have them mature. + self.wallet = MiniWallet(self.nodes[0]) + self.wallet.rescan_utxos() + + if self.is_specified_wallet_compiled(): + self.nodes[0].createwallet("watch_wallet", disable_private_keys=True) + self.nodes[0].importaddress(self.wallet.get_address()) + peer_inv_store = self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs - self.generate(self.nodes[0], COINBASE_MATURITY + 1) - utxo = self.nodes[0].listunspent(10) - txid = utxo[0]['txid'] - vout = utxo[0]['vout'] - value = utxo[0]['amount'] - assert 'ancestorcount' not in utxo[0] - assert 'ancestorsize' not in utxo[0] - assert 'ancestorfees' not in utxo[0] - - fee = Decimal("0.0001") + # DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine - chain = [] - witness_chain = [] + chain = self.wallet.create_self_transfer_chain(chain_length=DEFAULT_ANCESTOR_LIMIT) + witness_chain = [t["wtxid"] for t in chain] ancestor_vsize = 0 ancestor_fees = Decimal(0) - for i in range(DEFAULT_ANCESTOR_LIMIT): - (txid, sent_value) = chain_transaction(self.nodes[0], [txid], [0], value, fee, 1) - value = sent_value - chain.append(txid) - # We need the wtxids to check P2P announcements - witnesstx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded'] - witness_chain.append(witnesstx['hash']) + for i, t in enumerate(chain): + ancestor_vsize += t["tx"].get_vsize() + ancestor_fees += t["fee"] + self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=t["hex"]) # Check that listunspent ancestor{count, size, fees} yield the correct results - wallet_unspent = self.nodes[0].listunspent(minconf=0) - this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info['txid'] == txid) - assert_equal(this_unspent['ancestorcount'], i + 1) - ancestor_vsize += self.nodes[0].getrawtransaction(txid=txid, verbose=True)['vsize'] - assert_equal(this_unspent['ancestorsize'], ancestor_vsize) - ancestor_fees -= self.nodes[0].gettransaction(txid=txid)['fee'] - assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN) + if self.is_specified_wallet_compiled(): + wallet_unspent = self.nodes[0].listunspent(minconf=0) + this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info["txid"] == t["txid"]) + assert_equal(this_unspent['ancestorcount'], i + 1) + assert_equal(this_unspent['ancestorsize'], ancestor_vsize) + assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN) # Wait until mempool transactions have passed initial broadcast (sent inv and received getdata) # Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between @@ -96,15 +87,20 @@ class MempoolPackagesTest(BitcoinTestFramework): ancestor_count = DEFAULT_ANCESTOR_LIMIT assert_equal(ancestor_fees, sum([mempool[tx]['fees']['base'] for tx in mempool])) + # Adding one more transaction on to the chain should fail. + next_hop = self.wallet.create_self_transfer(utxo_to_spend=chain[-1]["new_utxo"])["hex"] + assert_raises_rpc_error(-26, "too-long-mempool-chain", lambda: self.nodes[0].sendrawtransaction(next_hop)) + descendants = [] - ancestors = list(chain) + ancestors = [t["txid"] for t in chain] + chain = [t["txid"] for t in chain] for x in reversed(chain): # Check that getmempoolentry is consistent with getrawmempool entry = self.nodes[0].getmempoolentry(x) assert_equal(entry, mempool[x]) # Check that gettxspendingprevout is consistent with getrawmempool - witnesstx = self.nodes[0].gettransaction(txid=x, verbose=True)['decoded'] + witnesstx = self.nodes[0].getrawtransaction(txid=x, verbose=True) for tx_in in witnesstx["vin"]: spending_result = self.nodes[0].gettxspendingprevout([ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"]} ]) assert_equal(spending_result, [ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"], 'spendingtxid' : x} ]) @@ -190,9 +186,6 @@ class MempoolPackagesTest(BitcoinTestFramework): descendant_fees += entry['fees']['base'] assert_equal(entry['fees']['descendant'], descendant_fees + Decimal('0.00001')) - # Adding one more transaction on to the chain should fail. - assert_raises_rpc_error(-26, "too-long-mempool-chain", chain_transaction, self.nodes[0], [txid], [vout], value, fee, 1) - # Check that prioritising a tx before it's added to the mempool works # First clear the mempool by mining a block. self.generate(self.nodes[0], 1) @@ -229,28 +222,23 @@ class MempoolPackagesTest(BitcoinTestFramework): # TODO: test ancestor size limits # Now test descendant chain limits - txid = utxo[1]['txid'] - value = utxo[1]['amount'] - vout = utxo[1]['vout'] - transaction_package = [] tx_children = [] # First create one parent tx with 10 children - (txid, sent_value) = chain_transaction(self.nodes[0], [txid], [vout], value, fee, 10) - parent_transaction = txid - for i in range(10): - transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value}) + tx_with_children = self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=10) + parent_transaction = tx_with_children["txid"] + transaction_package = tx_with_children["new_utxos"] # Sign and send up to MAX_DESCENDANT transactions chained off the parent tx chain = [] # save sent txs for the purpose of checking node1's mempool later (see below) for _ in range(DEFAULT_DESCENDANT_LIMIT - 1): utxo = transaction_package.pop(0) - (txid, sent_value) = chain_transaction(self.nodes[0], [utxo['txid']], [utxo['vout']], utxo['amount'], fee, 10) + new_tx = self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=10, utxos_to_spend=[utxo]) + txid = new_tx["txid"] chain.append(txid) if utxo['txid'] is parent_transaction: tx_children.append(txid) - for j in range(10): - transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) + transaction_package.extend(new_tx["new_utxos"]) mempool = self.nodes[0].getrawmempool(True) assert_equal(mempool[parent_transaction]['descendantcount'], DEFAULT_DESCENDANT_LIMIT) @@ -260,8 +248,8 @@ class MempoolPackagesTest(BitcoinTestFramework): assert_equal(mempool[child]['depends'], [parent_transaction]) # Sending one more chained transaction will fail - utxo = transaction_package.pop(0) - assert_raises_rpc_error(-26, "too-long-mempool-chain", chain_transaction, self.nodes[0], [utxo['txid']], [utxo['vout']], utxo['amount'], fee, 10) + next_hop = self.wallet.create_self_transfer(utxo_to_spend=transaction_package.pop(0))["hex"] + assert_raises_rpc_error(-26, "too-long-mempool-chain", lambda: self.nodes[0].sendrawtransaction(next_hop)) # Check that node1's mempool is as expected, containing: # - txs from previous ancestor test (-> custom ancestor limit) @@ -301,42 +289,19 @@ class MempoolPackagesTest(BitcoinTestFramework): # last block. # Create tx0 with 2 outputs - utxo = self.nodes[0].listunspent() - txid = utxo[0]['txid'] - value = utxo[0]['amount'] - vout = utxo[0]['vout'] - - send_value = (value - fee) / 2 - inputs = [ {'txid' : txid, 'vout' : vout} ] - outputs = {} - for _ in range(2): - outputs[self.nodes[0].getnewaddress()] = send_value - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) - txid = self.nodes[0].sendrawtransaction(signedtx['hex']) - tx0_id = txid - value = send_value + tx0 = self.wallet.send_self_transfer_multi(from_node=self.nodes[0], num_outputs=2) # Create tx1 - tx1_id, _ = chain_transaction(self.nodes[0], [tx0_id], [0], value, fee, 1) + tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=tx0["new_utxos"][0]) # Create tx2-7 - vout = 1 - txid = tx0_id - for _ in range(6): - (txid, sent_value) = chain_transaction(self.nodes[0], [txid], [vout], value, fee, 1) - vout = 0 - value = sent_value + tx7 = self.wallet.send_self_transfer_chain(from_node=self.nodes[0], utxo_to_spend=tx0["new_utxos"][1], chain_length=6)[-1] # Mine these in a block self.generate(self.nodes[0], 1) # Now generate tx8, with a big fee - inputs = [ {'txid' : tx1_id, 'vout': 0}, {'txid' : txid, 'vout': 0} ] - outputs = { self.nodes[0].getnewaddress() : send_value + value - 4*fee } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) - txid = self.nodes[0].sendrawtransaction(signedtx['hex']) + self.wallet.send_self_transfer_multi(from_node=self.nodes[0], utxos_to_spend=[tx1["new_utxo"], tx7["new_utxo"]], fee_per_output=40000) self.sync_mempools() # Now try to disconnect the tip on each node... diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index b6fa7fbd91..f818801136 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -50,13 +50,15 @@ from test_framework.wallet import MiniWallet class MempoolPersistTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 3 self.extra_args = [[], ["-persistmempool=0"], []] def run_test(self): self.mini_wallet = MiniWallet(self.nodes[2]) - self.mini_wallet.rescan_utxos() if self.is_sqlite_compiled(): self.nodes[2].createwallet( wallet_name="watch", diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 47ff520713..3a5bc1ebcd 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -31,7 +31,6 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.log.info("Add 4 coinbase utxos to the miniwallet") # Block 76 contains the first spendable coinbase txs. first_block = 76 - wallet.rescan_utxos() # Three scenarios for re-orging coinbase spends in the memory pool: # 1. Direct coinbase spend : spend_1 diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py index 3e610d02ac..c10052372d 100755 --- a/test/functional/mempool_resurrect.py +++ b/test/functional/mempool_resurrect.py @@ -4,7 +4,6 @@ # 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 COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal from test_framework.wallet import MiniWallet @@ -13,16 +12,11 @@ from test_framework.wallet import MiniWallet class MempoolCoinbaseTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = True def run_test(self): node = self.nodes[0] wallet = MiniWallet(node) - # Add enough mature utxos to the wallet so that all txs spend confirmed coins - self.generate(wallet, 3) - self.generate(node, COINBASE_MATURITY) - # Spend block 1/2/3's coinbase transactions # Mine a block # Create three more transactions, spending the spends diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py index 3585871350..a7cb2ba602 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -28,7 +28,6 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): chain_height = 198 self.nodes[0].invalidateblock(self.nodes[0].getblockhash(chain_height + 1)) assert_equal(chain_height, self.nodes[0].getblockcount()) - wallet.rescan_utxos() # Coinbase at height chain_height-100+1 ok in mempool, should # get mined. Coinbase at height chain_height-100+2 is diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py index 7587adc257..12de750731 100755 --- a/test/functional/mempool_unbroadcast.py +++ b/test/functional/mempool_unbroadcast.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 mempool ensures transaction delivery by periodically sending @@ -15,14 +15,14 @@ from test_framework.wallet import MiniWallet MAX_INITIAL_BROADCAST_DELAY = 15 * 60 # 15 minutes in seconds class MempoolUnbroadcastTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 - if self.is_wallet_compiled(): - self.requires_wallet = True def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() self.test_broadcast() self.test_txn_removal() @@ -35,6 +35,7 @@ class MempoolUnbroadcastTest(BitcoinTestFramework): self.log.info("Generate transactions that only node 0 knows about") if self.is_wallet_compiled(): + self.import_deterministic_coinbase_privkeys() # generate a wallet txn addr = node.getnewaddress() wallet_tx_hsh = node.sendtoaddress(addr, 0.0001) diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py index f97c2223a6..68cbb5dbed 100755 --- a/test/functional/mempool_updatefromblock.py +++ b/test/functional/mempool_updatefromblock.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 descendants/ancestors information update. diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index ac7eb96ac1..332099516c 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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 diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py index e928ee4936..ec492f9e72 100755 --- a/test/functional/mining_getblocktemplate_longpoll.py +++ b/test/functional/mining_getblocktemplate_longpoll.py @@ -8,7 +8,6 @@ from decimal import Decimal import random import threading -from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import get_rpc_proxy from test_framework.wallet import MiniWallet @@ -62,9 +61,6 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): thr.join(5) # wait 5 seconds or until thread exits assert not thr.is_alive() - # Add enough mature utxos to the wallets, so that all txs spend confirmed coins - self.generate(self.nodes[0], COINBASE_MATURITY) - self.log.info("Test that introducing a new transaction into the mempool will terminate the longpoll") thr = LongpollThread(self.nodes[0]) thr.start() diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index 581cf5896e..a4481c15a0 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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.""" @@ -106,7 +106,6 @@ class PrioritiseTransactionTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() # Test `prioritisetransaction` required parameters assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction) diff --git a/test/functional/mocks/invalid_signer.py b/test/functional/mocks/invalid_signer.py index 14f9fed72e..7bfa9051ac 100755 --- a/test/functional/mocks/invalid_signer.py +++ b/test/functional/mocks/invalid_signer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,7 @@ import json def perform_pre_checks(): mock_result_path = os.path.join(os.getcwd(), "mock_result") - if(os.path.isfile(mock_result_path)): + if os.path.isfile(mock_result_path): with open(mock_result_path, "r", encoding="utf8") as f: mock_result = f.read() if mock_result[0]: diff --git a/test/functional/mocks/signer.py b/test/functional/mocks/signer.py index 6699914249..5f4fad6380 100755 --- a/test/functional/mocks/signer.py +++ b/test/functional/mocks/signer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,7 @@ import json def perform_pre_checks(): mock_result_path = os.path.join(os.getcwd(), "mock_result") - if(os.path.isfile(mock_result_path)): + if os.path.isfile(mock_result_path): with open(mock_result_path, "r", encoding="utf8") as f: mock_result = f.read() if mock_result[0]: diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index e2e9b6dcb2..e002a520c6 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -49,7 +49,7 @@ class AddrReceiver(P2PInterface): def on_addr(self, message): for addr in message.addrs: self.num_ipv4_received += 1 - if(self.test_addr_contents): + if self.test_addr_contents: # relay_tests checks the content of the addr messages match # expectations based on the message creation in setup_addr_msg assert_equal(addr.nServices, 9) diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index ef12b5f6b7..2da9037a69 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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_COMPACT_FILTERS (BIP 157/158). diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 231d2e12c9..110a1bd03f 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 blocksonly mode & block-relay-only connections.""" @@ -20,8 +20,6 @@ class P2PBlocksOnly(BitcoinTestFramework): def run_test(self): self.miniwallet = MiniWallet(self.nodes[0]) - # Add enough mature utxos to the wallet, so that all txs spend confirmed coins - self.miniwallet.rescan_utxos() self.blocksonly_mode_tests() self.blocks_relay_conn_tests() @@ -104,7 +102,7 @@ class P2PBlocksOnly(BitcoinTestFramework): self.nodes[0].setmocktime(int(time.time()) + 60) conn.sync_send_with_ping() - assert(int(txid, 16) not in conn.get_invs()) + assert int(txid, 16) not in conn.get_invs() def check_p2p_inv_violation(self, peer): self.log.info("Check that tx-invs from P2P are rejected and result in disconnect") diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 3cbb948e3c..23eeea50bc 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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).""" diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py index 7284ecde83..b2f0659eda 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-2020 The Bitcoin Core developers +# Copyright (c) 2014-2022 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""" @@ -46,6 +46,9 @@ class DisconnectBanTest(BitcoinTestFramework): assert_raises_rpc_error(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add") assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 + self.log.info("setban: fail to ban with past absolute timestamp") + assert_raises_rpc_error(-8, "Error: Absolute timestamp is in the past", self.nodes[1].setban, "127.27.0.1", "add", 123, True) + self.log.info("setban remove: fail to unban a non-banned subnet") assert_raises_rpc_error(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[1].listbanned()), 1) @@ -66,9 +69,13 @@ class DisconnectBanTest(BitcoinTestFramework): self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[1].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) + + self.log.info("setban: test banning with absolute timestamp") + self.nodes[1].setban("192.168.0.2", "add", old_time + 120, True) + # Move time forward by 3 seconds so the third ban has expired self.nodes[1].setmocktime(old_time + 3) - assert_equal(len(self.nodes[1].listbanned()), 3) + assert_equal(len(self.nodes[1].listbanned()), 4) self.log.info("Test ban_duration and time_remaining") for ban in self.nodes[1].listbanned(): @@ -78,13 +85,17 @@ class DisconnectBanTest(BitcoinTestFramework): elif ban["address"] == "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19": assert_equal(ban["ban_duration"], 1000) assert_equal(ban["time_remaining"], 997) + elif ban["address"] == "192.168.0.2/32": + assert_equal(ban["ban_duration"], 120) + assert_equal(ban["time_remaining"], 117) self.restart_node(1) listAfterShutdown = self.nodes[1].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) - assert_equal("/19" in listAfterShutdown[2]['address'], True) + assert_equal("192.168.0.2/32", listAfterShutdown[2]['address']) + assert_equal("/19" in listAfterShutdown[3]['address'], True) # Clear ban lists self.nodes[1].clearbanned() @@ -96,7 +107,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("disconnectnode: fail to disconnect when calling with address and nodeid") address1 = self.nodes[0].getpeerinfo()[0]['addr'] - node1 = self.nodes[0].getpeerinfo()[0]['addr'] + node1 = self.nodes[0].getpeerinfo()[0]["id"] assert_raises_rpc_error(-32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1) self.log.info("disconnectnode: fail to disconnect when calling with junk address") diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py index 1f904644fc..4b4346af49 100755 --- a/test/functional/p2p_dos_header_tree.py +++ b/test/functional/p2p_dos_header_tree.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 we reject low difficulty headers to prevent our block tree from filling up with useless bloat""" diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py index b65e927d5b..6b03cdf877 100755 --- a/test/functional/p2p_feefilter.py +++ b/test/functional/p2p_feefilter.py @@ -6,7 +6,6 @@ from decimal import Decimal -from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter from test_framework.p2p import P2PInterface, p2p_lock from test_framework.test_framework import BitcoinTestFramework @@ -80,9 +79,6 @@ class FeeFilterTest(BitcoinTestFramework): node1 = self.nodes[1] node0 = self.nodes[0] miniwallet = MiniWallet(node1) - # Add enough mature utxos to the wallet, so that all txs spend confirmed coins - self.generate(miniwallet, 5) - self.generate(node1, COINBASE_MATURITY) conn = self.nodes[0].add_p2p_connection(TestP2PConn()) diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index 3cf92b0316..b3e68ca536 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -214,7 +214,6 @@ class FilterTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() filter_peer = self.nodes[0].add_p2p_connection(P2PBloomFilter()) self.log.info('Test filter size limits') diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py index 8907c34a89..1c9ad7289b 100755 --- a/test/functional/p2p_getaddr_caching.py +++ b/test/functional/p2p_getaddr_caching.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 addr response caching""" @@ -60,7 +60,7 @@ class AddrTest(BitcoinTestFramework): # Need to make sure we hit MAX_ADDR_TO_SEND records in the addr response later because # only a fraction of all known addresses can be cached and returned. - assert(len(self.nodes[0].getnodeaddresses(0)) > int(MAX_ADDR_TO_SEND / (MAX_PCT_ADDR_TO_SEND / 100))) + assert len(self.nodes[0].getnodeaddresses(0)) > int(MAX_ADDR_TO_SEND / (MAX_PCT_ADDR_TO_SEND / 100)) last_response_on_local_bind = None last_response_on_onion_bind1 = None @@ -85,9 +85,9 @@ class AddrTest(BitcoinTestFramework): if i > 0: # Responses from different binds should be unique - assert(last_response_on_local_bind != addr_receiver_onion1.get_received_addrs()) - assert(last_response_on_local_bind != addr_receiver_onion2.get_received_addrs()) - assert(last_response_on_onion_bind1 != addr_receiver_onion2.get_received_addrs()) + assert last_response_on_local_bind != addr_receiver_onion1.get_received_addrs() + assert last_response_on_local_bind != addr_receiver_onion2.get_received_addrs() + assert last_response_on_onion_bind1 != addr_receiver_onion2.get_received_addrs() # Responses on from the same bind should be the same assert_equal(last_response_on_local_bind, addr_receiver_local.get_received_addrs()) assert_equal(last_response_on_onion_bind1, addr_receiver_onion1.get_received_addrs()) @@ -119,9 +119,9 @@ class AddrTest(BitcoinTestFramework): addr_receiver_onion2.wait_until(addr_receiver_onion2.addr_received) # new response is different - assert(set(last_response_on_local_bind) != set(addr_receiver_local.get_received_addrs())) - assert(set(last_response_on_onion_bind1) != set(addr_receiver_onion1.get_received_addrs())) - assert(set(last_response_on_onion_bind2) != set(addr_receiver_onion2.get_received_addrs())) + assert set(last_response_on_local_bind) != set(addr_receiver_local.get_received_addrs()) + assert set(last_response_on_onion_bind1) != set(addr_receiver_onion1.get_received_addrs()) + assert set(last_response_on_onion_bind2) != set(addr_receiver_onion2.get_received_addrs()) if __name__ == '__main__': AddrTest().main() diff --git a/test/functional/p2p_headers_sync_with_minchainwork.py b/test/functional/p2p_headers_sync_with_minchainwork.py index 991e3348ed..b07077c668 100755 --- a/test/functional/p2p_headers_sync_with_minchainwork.py +++ b/test/functional/p2p_headers_sync_with_minchainwork.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 we reject low difficulty headers to prevent our block tree from filling up with useless bloat""" @@ -57,7 +57,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): def check_node3_chaintips(num_tips, tip_hash, height): node3_chaintips = self.nodes[3].getchaintips() - assert(len(node3_chaintips) == num_tips) + assert len(node3_chaintips) == num_tips assert { 'height': height, 'hash': tip_hash, @@ -69,7 +69,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): for node in self.nodes[1:3]: chaintips = node.getchaintips() - assert(len(chaintips) == 1) + assert len(chaintips) == 1 assert { 'height': 0, 'hash': '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', @@ -89,7 +89,7 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): 'status': 'active', } in self.nodes[2].getchaintips() - assert(len(self.nodes[2].getchaintips()) == 1) + assert len(self.nodes[2].getchaintips()) == 1 self.log.info("Check that node3 accepted these headers as well") check_node3_chaintips(2, self.nodes[0].getbestblockhash(), NODE1_BLOCKS_REQUIRED) diff --git a/test/functional/p2p_i2p_sessions.py b/test/functional/p2p_i2p_sessions.py index 4e52522b81..9e7fdc6e14 100755 --- a/test/functional/p2p_i2p_sessions.py +++ b/test/functional/p2p_i2p_sessions.py @@ -23,12 +23,12 @@ class I2PSessions(BitcoinTestFramework): self.log.info("Ensure we create a persistent session when -i2pacceptincoming=1") node0 = self.nodes[0] - with node0.assert_debug_log(expected_msgs=[f"Creating persistent SAM session"]): + with node0.assert_debug_log(expected_msgs=["Creating persistent SAM session"]): node0.addnode(node=addr, command="onetry") self.log.info("Ensure we create a transient session when -i2pacceptincoming=0") node1 = self.nodes[1] - with node1.assert_debug_log(expected_msgs=[f"Creating transient SAM session"]): + with node1.assert_debug_log(expected_msgs=["Creating transient SAM session"]): node1.addnode(node=addr, command="onetry") diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index 28efd5a81e..ae9dc816ab 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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. diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 936c22197c..645488f24d 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py index 4c064b359e..6283dd89ac 100755 --- a/test/functional/p2p_leak_tx.py +++ b/test/functional/p2p_leak_tx.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test that we don't leak txs to inbound peers that we haven't yet announced to""" -from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import msg_getdata, CInv, MSG_TX from test_framework.p2p import p2p_lock, P2PDataStore from test_framework.test_framework import BitcoinTestFramework @@ -26,9 +25,6 @@ class P2PLeakTxTest(BitcoinTestFramework): def run_test(self): gen_node = self.nodes[0] # The block and tx generating node miniwallet = MiniWallet(gen_node) - # Add enough mature utxos to the wallet, so that all txs spend confirmed coins - self.generate(miniwallet, 1) - self.generate(gen_node, COINBASE_MATURITY) inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer diff --git a/test/functional/p2p_message_capture.py b/test/functional/p2p_message_capture.py index 87c77f4540..3ab0b79ba2 100755 --- a/test/functional/p2p_message_capture.py +++ b/test/functional/p2p_message_capture.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 per-peer message capture capability. @@ -36,7 +36,7 @@ def mini_parser(dat_file): """ with open(dat_file, 'rb') as f_in: # This should have at least one message in it - assert(os.fstat(f_in.fileno()).st_size >= TIME_SIZE + LENGTH_SIZE + MSGTYPE_SIZE) + assert os.fstat(f_in.fileno()).st_size >= TIME_SIZE + LENGTH_SIZE + MSGTYPE_SIZE while True: tmp_header_raw = f_in.read(TIME_SIZE + LENGTH_SIZE + MSGTYPE_SIZE) if not tmp_header_raw: @@ -44,7 +44,7 @@ def mini_parser(dat_file): tmp_header = BytesIO(tmp_header_raw) tmp_header.read(TIME_SIZE) # skip the timestamp field msgtype = tmp_header.read(MSGTYPE_SIZE).rstrip(b'\x00') - assert(msgtype in MESSAGEMAP) + assert msgtype in MESSAGEMAP length: int = int.from_bytes(tmp_header.read(LENGTH_SIZE), "little") data = f_in.read(length) assert_equal(len(data), length) diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index 453a0920cc..41324682fc 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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 permission message. @@ -7,30 +7,26 @@ Test that permissions are correctly calculated and applied """ -from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE from test_framework.messages import ( - CTxInWitness, - tx_from_hex, + SEQUENCE_FINAL, ) from test_framework.p2p import P2PDataStore -from test_framework.script import ( - CScript, - OP_TRUE, -) from test_framework.test_node import ErrorMatch from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, p2p_port, ) +from test_framework.wallet import MiniWallet class P2PPermissionsTests(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = True def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + self.check_tx_relay() self.checkpermission( @@ -94,8 +90,6 @@ class P2PPermissionsTests(BitcoinTestFramework): self.nodes[1].assert_start_raises_init_error(["-whitebind=noban@127.0.0.1", "-bind=127.0.0.1", "-listen=0"], "Cannot set -bind or -whitebind together with -listen=0", match=ErrorMatch.PARTIAL_REGEX) def check_tx_relay(self): - block_op_true = self.nodes[0].getblock(self.generatetoaddress(self.nodes[0], 100, ADDRESS_BCRT1_P2WSH_OP_TRUE)[0]) - self.log.debug("Create a connection from a forcerelay peer that rebroadcasts raw txs") # A test framework p2p connection is needed to send the raw transaction directly. If a full node was used, it could only # rebroadcast via the inv-getdata mechanism. However, even for forcerelay connections, a full node would @@ -104,18 +98,7 @@ class P2PPermissionsTests(BitcoinTestFramework): p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection(P2PDataStore()) self.log.debug("Send a tx from the wallet initially") - tx = tx_from_hex( - self.nodes[0].createrawtransaction( - inputs=[{ - 'txid': block_op_true['tx'][0], - 'vout': 0, - }], outputs=[{ - ADDRESS_BCRT1_P2WSH_OP_TRUE: 5, - }], - replaceable=False), - ) - tx.wit.vtxinwit = [CTxInWitness()] - tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] + tx = self.wallet.create_self_transfer(sequence=SEQUENCE_FINAL)['tx'] txid = tx.rehash() self.log.debug("Wait until tx is in node[1]'s mempool") diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py index 2919f7aa7b..3ba30a42b1 100755 --- a/test/functional/p2p_ping.py +++ b/test/functional/p2p_ping.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 ping message diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 311b0b67db..b0900e49b8 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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.""" @@ -622,8 +622,10 @@ class SegWitTest(BitcoinTestFramework): if not self.segwit_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([tx3.serialize_with_witness().hex()]), + testres3 = self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]) + testres3[0]["fees"].pop("effective-feerate") + testres3[0]["fees"].pop("effective-includes") + assert_equal(testres3, [{ 'txid': tx3.hash, 'wtxid': tx3.getwtxid(), @@ -639,8 +641,10 @@ class SegWitTest(BitcoinTestFramework): tx3 = tx tx3.vout = [tx3_out] tx3.rehash() - assert_equal( - self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), + testres3_replaced = self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]) + testres3_replaced[0]["fees"].pop("effective-feerate") + testres3_replaced[0]["fees"].pop("effective-includes") + assert_equal(testres3_replaced, [{ 'txid': tx3.hash, 'wtxid': tx3.getwtxid(), diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py index fed9832a7d..0e349ef70c 100755 --- a/test/functional/p2p_sendtxrcncl.py +++ b/test/functional/p2p_sendtxrcncl.py @@ -10,6 +10,7 @@ from test_framework.messages import ( msg_verack, msg_version, msg_wtxidrelay, + NODE_BLOOM, ) from test_framework.p2p import ( P2PInterface, @@ -54,10 +55,8 @@ class PeerTrackMsgOrder(P2PInterface): super().on_message(message) self.messages.append(message) -def create_sendtxrcncl_msg(initiator=True): +def create_sendtxrcncl_msg(): sendtxrcncl_msg = msg_sendtxrcncl() - sendtxrcncl_msg.initiator = initiator - sendtxrcncl_msg.responder = not initiator sendtxrcncl_msg.version = 1 sendtxrcncl_msg.salt = 2 return sendtxrcncl_msg @@ -68,11 +67,11 @@ class SendTxRcnclTest(BitcoinTestFramework): self.extra_args = [['-txreconciliation']] def run_test(self): + # Check everything concerning *sending* SENDTXRCNCL + # First, *sending* to *inbound*. self.log.info('SENDTXRCNCL sent to an inbound') peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True) assert peer.sendtxrcncl_msg_received - assert not peer.sendtxrcncl_msg_received.initiator - assert peer.sendtxrcncl_msg_received.responder assert_equal(peer.sendtxrcncl_msg_received.version, 1) self.nodes[0].disconnect_p2ps() @@ -81,7 +80,7 @@ class SendTxRcnclTest(BitcoinTestFramework): peer.wait_for_verack() verack_index = [i for i, msg in enumerate(peer.messages) if msg.msgtype == b'verack'][0] sendtxrcncl_index = [i for i, msg in enumerate(peer.messages) if msg.msgtype == b'sendtxrcncl'][0] - assert(sendtxrcncl_index < verack_index) + assert sendtxrcncl_index < verack_index self.nodes[0].disconnect_p2ps() self.log.info('SENDTXRCNCL on pre-WTXID version should not be sent') @@ -108,30 +107,77 @@ class SendTxRcnclTest(BitcoinTestFramework): assert not peer.sendtxrcncl_msg_received self.nodes[0].disconnect_p2ps() + self.log.info('SENDTXRCNCL for fRelay=false should not be sent (with NODE_BLOOM offered)') + self.restart_node(0, ["-peerbloomfilters", "-txreconciliation"]) + peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=False, wait_for_verack=False) + no_txrelay_version_msg = msg_version() + no_txrelay_version_msg.nVersion = P2P_VERSION + no_txrelay_version_msg.strSubVer = P2P_SUBVERSION + no_txrelay_version_msg.nServices = P2P_SERVICES + no_txrelay_version_msg.relay = 0 + peer.send_message(no_txrelay_version_msg) + peer.wait_for_verack() + assert peer.nServices & NODE_BLOOM != 0 + assert not peer.sendtxrcncl_msg_received + self.nodes[0].disconnect_p2ps() + + # Now, *sending* to *outbound*. + self.log.info('SENDTXRCNCL sent to an outbound') + peer = self.nodes[0].add_outbound_p2p_connection( + SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="outbound-full-relay") + assert peer.sendtxrcncl_msg_received + assert_equal(peer.sendtxrcncl_msg_received.version, 1) + self.nodes[0].disconnect_p2ps() + + self.log.info('SENDTXRCNCL should not be sent if block-relay-only') + peer = self.nodes[0].add_outbound_p2p_connection( + SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="block-relay-only") + assert not peer.sendtxrcncl_msg_received + self.nodes[0].disconnect_p2ps() + + self.log.info("SENDTXRCNCL should not be sent if feeler") + peer = self.nodes[0].add_outbound_p2p_connection(P2PFeelerReceiver(), p2p_idx=0, connection_type="feeler") + assert not peer.sendtxrcncl_msg_received + self.nodes[0].disconnect_p2ps() + + self.log.info("SENDTXRCNCL should not be sent if addrfetch") + peer = self.nodes[0].add_outbound_p2p_connection( + SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="addr-fetch") + assert not peer.sendtxrcncl_msg_received + self.nodes[0].disconnect_p2ps() + + self.log.info('SENDTXRCNCL not sent if -txreconciliation flag is not set') + self.restart_node(0, []) + peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True) + assert not peer.sendtxrcncl_msg_received + self.nodes[0].disconnect_p2ps() + + self.log.info('SENDTXRCNCL not sent if blocksonly is set') + self.restart_node(0, ["-txreconciliation", "-blocksonly"]) + peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True) + assert not peer.sendtxrcncl_msg_received + self.nodes[0].disconnect_p2ps() + + # Check everything concerning *receiving* SENDTXRCNCL + # First, receiving from *inbound*. + self.restart_node(0, ["-txreconciliation"]) self.log.info('valid SENDTXRCNCL received') peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) - peer.send_message(create_sendtxrcncl_msg()) - self.wait_until(lambda : "sendtxrcncl" in self.nodes[0].getpeerinfo()[-1]["bytesrecv_per_msg"]) + with self.nodes[0].assert_debug_log(["received: sendtxrcncl"]): + peer.send_message(create_sendtxrcncl_msg()) self.log.info('second SENDTXRCNCL triggers a disconnect') with self.nodes[0].assert_debug_log(["(sendtxrcncl received from already registered peer); disconnecting"]): peer.send_message(create_sendtxrcncl_msg()) peer.wait_for_disconnect() - self.log.info('SENDTXRCNCL with initiator=responder=0 triggers a disconnect') - sendtxrcncl_no_role = create_sendtxrcncl_msg() - sendtxrcncl_no_role.initiator = False - sendtxrcncl_no_role.responder = False + self.restart_node(0, []) + self.log.info('SENDTXRCNCL if no txreconciliation supported is ignored') peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) - with self.nodes[0].assert_debug_log(["txreconciliation protocol violation"]): - peer.send_message(sendtxrcncl_no_role) - peer.wait_for_disconnect() + with self.nodes[0].assert_debug_log(['ignored, as our node does not have txreconciliation enabled']): + peer.send_message(create_sendtxrcncl_msg()) + self.nodes[0].disconnect_p2ps() - self.log.info('SENDTXRCNCL with initiator=0 and responder=1 from inbound triggers a disconnect') - sendtxrcncl_wrong_role = create_sendtxrcncl_msg(initiator=False) - peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) - with self.nodes[0].assert_debug_log(["txreconciliation protocol violation"]): - peer.send_message(sendtxrcncl_wrong_role) - peer.wait_for_disconnect() + self.restart_node(0, ["-txreconciliation"]) self.log.info('SENDTXRCNCL with version=0 triggers a disconnect') sendtxrcncl_low_version = create_sendtxrcncl_msg() @@ -141,6 +187,26 @@ class SendTxRcnclTest(BitcoinTestFramework): peer.send_message(sendtxrcncl_low_version) peer.wait_for_disconnect() + self.log.info('SENDTXRCNCL with version=2 is valid') + sendtxrcncl_higher_version = create_sendtxrcncl_msg() + sendtxrcncl_higher_version.version = 2 + peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) + with self.nodes[0].assert_debug_log(['Register peer=1']): + peer.send_message(sendtxrcncl_higher_version) + self.nodes[0].disconnect_p2ps() + + self.log.info('unexpected SENDTXRCNCL is ignored') + peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=False, wait_for_verack=False) + old_version_msg = msg_version() + old_version_msg.nVersion = 70015 + old_version_msg.strSubVer = P2P_SUBVERSION + old_version_msg.nServices = P2P_SERVICES + old_version_msg.relay = 1 + peer.send_message(old_version_msg) + with self.nodes[0].assert_debug_log(['Ignore unexpected txreconciliation signal']): + peer.send_message(create_sendtxrcncl_msg()) + self.nodes[0].disconnect_p2ps() + self.log.info('sending SENDTXRCNCL after sending VERACK triggers a disconnect') peer = self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(["sendtxrcncl received after verack"]): @@ -154,53 +220,14 @@ class SendTxRcnclTest(BitcoinTestFramework): peer.send_message(msg_verack()) self.nodes[0].disconnect_p2ps() - self.log.info('SENDTXRCNCL sent to an outbound') - peer = self.nodes[0].add_outbound_p2p_connection( - SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="outbound-full-relay") - assert peer.sendtxrcncl_msg_received - assert peer.sendtxrcncl_msg_received.initiator - assert not peer.sendtxrcncl_msg_received.responder - assert_equal(peer.sendtxrcncl_msg_received.version, 1) - self.nodes[0].disconnect_p2ps() - - self.log.info('SENDTXRCNCL should not be sent if block-relay-only') - peer = self.nodes[0].add_outbound_p2p_connection( - SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=0, connection_type="block-relay-only") - assert not peer.sendtxrcncl_msg_received - self.nodes[0].disconnect_p2ps() - - self.log.info("SENDTXRCNCL should not be sent if feeler") - peer = self.nodes[0].add_outbound_p2p_connection(P2PFeelerReceiver(), p2p_idx=0, connection_type="feeler") - assert not peer.sendtxrcncl_msg_received - self.nodes[0].disconnect_p2ps() - + # Now, *receiving* from *outbound*. self.log.info('SENDTXRCNCL if block-relay-only triggers a disconnect') peer = self.nodes[0].add_outbound_p2p_connection( PeerNoVerack(), wait_for_verack=False, p2p_idx=0, connection_type="block-relay-only") with self.nodes[0].assert_debug_log(["we indicated no tx relay; disconnecting"]): - peer.send_message(create_sendtxrcncl_msg(initiator=False)) - peer.wait_for_disconnect() - - self.log.info('SENDTXRCNCL with initiator=1 and responder=0 from outbound triggers a disconnect') - sendtxrcncl_wrong_role = create_sendtxrcncl_msg(initiator=True) - peer = self.nodes[0].add_outbound_p2p_connection( - PeerNoVerack(), wait_for_verack=False, p2p_idx=0, connection_type="outbound-full-relay") - with self.nodes[0].assert_debug_log(["txreconciliation protocol violation"]): - peer.send_message(sendtxrcncl_wrong_role) + peer.send_message(create_sendtxrcncl_msg()) peer.wait_for_disconnect() - self.log.info('SENDTXRCNCL not sent if -txreconciliation flag is not set') - self.restart_node(0, []) - peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True) - assert not peer.sendtxrcncl_msg_received - self.nodes[0].disconnect_p2ps() - - self.log.info('SENDTXRCNCL not sent if blocksonly is set') - self.restart_node(0, ["-txreconciliation", "-blocksonly"]) - peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True) - assert not peer.sendtxrcncl_msg_received - self.nodes[0].disconnect_p2ps() - if __name__ == '__main__': SendTxRcnclTest().main() diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py index 15a879ae3c..a308577c02 100755 --- a/test/functional/p2p_timeouts.py +++ b/test/functional/p2p_timeouts.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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. diff --git a/test/functional/p2p_tx_privacy.py b/test/functional/p2p_tx_privacy.py new file mode 100755 index 0000000000..e674f6c3eb --- /dev/null +++ b/test/functional/p2p_tx_privacy.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 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 transaction announcements are only queued for peers that have +successfully completed the version handshake. + +Topology: + + tx_originator ----> node[0] <---- spy + +We test that a transaction sent by tx_originator is only relayed to spy +if it was received after spy's version handshake completed. + +1. Fully connect tx_originator +2. Connect spy (no version handshake) +3. tx_originator sends tx1 +4. spy completes the version handshake +5. tx_originator sends tx2 +6. We check that only tx2 is announced on the spy interface +""" +from test_framework.messages import ( + msg_wtxidrelay, + msg_verack, + msg_tx, + CInv, + MSG_WTX, +) +from test_framework.p2p import ( + P2PInterface, +) +from test_framework.test_framework import BitcoinTestFramework +from test_framework.wallet import MiniWallet + +class P2PTxSpy(P2PInterface): + def __init__(self): + super().__init__() + self.all_invs = [] + + def on_version(self, message): + self.send_message(msg_wtxidrelay()) + + def on_inv(self, message): + self.all_invs += message.inv + + def wait_for_inv_match(self, expected_inv): + self.wait_until(lambda: len(self.all_invs) == 1 and self.all_invs[0] == expected_inv) + +class TxPrivacyTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + + tx_originator = self.nodes[0].add_p2p_connection(P2PInterface()) + spy = self.nodes[0].add_p2p_connection(P2PTxSpy(), wait_for_verack=False) + spy.wait_for_verack() + + # tx_originator sends tx1 + tx1 = self.wallet.create_self_transfer()["tx"] + tx_originator.send_and_ping(msg_tx(tx1)) + + # Spy sends the verack + spy.send_and_ping(msg_verack()) + + # tx_originator sends tx2 + tx2 = self.wallet.create_self_transfer()["tx"] + tx_originator.send_and_ping(msg_tx(tx2)) + + # Spy should only get an inv for the second transaction as the first + # one was received pre-verack with the spy + spy.wait_for_inv_match(CInv(MSG_WTX, tx2.calc_sha256(True))) + +if __name__ == '__main__': + TxPrivacyTest().main() diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 5030e7af26..f368434895 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-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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. diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 80e8fe55a3..19c73eebf0 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -370,7 +370,7 @@ class BlockchainTest(BitcoinTestFramework): # hash_type muhash should return a different UTXO set hash. res6 = node.gettxoutsetinfo(hash_type='muhash') assert 'muhash' in res6 - assert(res['hash_serialized_2'] != res6['muhash']) + assert res['hash_serialized_2'] != res6['muhash'] # muhash should not be returned unless requested. for r in [res, res2, res3, res4, res5]: diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 1ad3fc24c9..7d03ed2951 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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 multisig RPCs""" @@ -24,12 +24,13 @@ from test_framework.wallet import ( ) class RpcCreateMultiSigTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 self.supports_cli = False - if self.is_bdb_compiled(): - self.requires_wallet = True def get_keys(self): self.pub = [] @@ -50,6 +51,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.wallet = MiniWallet(test_node=node0) if self.is_bdb_compiled(): + self.import_deterministic_coinbase_privkeys() self.check_addmultisigaddress_errors() self.log.info('Generating blocks ...') diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py index 343cb73989..a61710b739 100755 --- a/test/functional/rpc_decodescript.py +++ b/test/functional/rpc_decodescript.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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.""" diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py index a69326736d..e96b6bda90 100755 --- a/test/functional/rpc_deriveaddresses.py +++ b/test/functional/rpc_deriveaddresses.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2019 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 deriveaddresses rpc call.""" diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py index 672c9a53dc..39a931be03 100755 --- a/test/functional/rpc_dumptxoutset.py +++ b/test/functional/rpc_dumptxoutset.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 generation of UTXO snapshots using `dumptxoutset`. diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py index b057400887..dad3cbcf0c 100755 --- a/test/functional/rpc_estimatefee.py +++ b/test/functional/rpc_estimatefee.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2020 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 estimatefee RPCs. diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 2b1dd20ea1..8948ccb48d 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 generate* RPCs.""" @@ -28,7 +28,6 @@ class RPCGenerateTest(BitcoinTestFramework): def test_generateblock(self): node = self.nodes[0] miniwallet = MiniWallet(node) - miniwallet.rescan_utxos() self.log.info('Generate an empty block to address') address = miniwallet.get_address() diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py index 8bd3366e36..dddc779763 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 getblockfrompeer RPC.""" diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index 1ea1ee5659..bf261befcc 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -43,6 +43,10 @@ class GetblockstatsTest(BitcoinTestFramework): def generate_test_data(self, filename): mocktime = 1525107225 self.nodes[0].setmocktime(mocktime) + self.nodes[0].createwallet(wallet_name='test') + privkey = self.nodes[0].get_deterministic_priv_key().key + self.nodes[0].importprivkey(privkey) + self.generate(self.nodes[0], COINBASE_MATURITY + 1) address = self.nodes[0].get_deterministic_priv_key().address @@ -53,6 +57,8 @@ class GetblockstatsTest(BitcoinTestFramework): self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=False) self.nodes[0].settxfee(amount=0.003) self.nodes[0].sendtoaddress(address=address, amount=1, subtractfeefromamount=True) + # Send to OP_RETURN output to test its exclusion from statistics + self.nodes[0].send(outputs={"data": "21"}) self.sync_all() self.generate(self.nodes[0], 1) @@ -161,6 +167,20 @@ class GetblockstatsTest(BitcoinTestFramework): assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, '00', 1, 2) assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats) + self.log.info('Test block height 0') + genesis_stats = self.nodes[0].getblockstats(0) + assert_equal(genesis_stats["blockhash"], "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206") + assert_equal(genesis_stats["utxo_increase"], 1) + assert_equal(genesis_stats["utxo_size_inc"], 117) + assert_equal(genesis_stats["utxo_increase_actual"], 0) + assert_equal(genesis_stats["utxo_size_inc_actual"], 0) + + self.log.info('Test tip including OP_RETURN') + tip_stats = self.nodes[0].getblockstats(tip) + assert_equal(tip_stats["utxo_increase"], 6) + assert_equal(tip_stats["utxo_size_inc"], 441) + assert_equal(tip_stats["utxo_increase_actual"], 4) + assert_equal(tip_stats["utxo_size_inc_actual"], 300) if __name__ == '__main__': GetblockstatsTest().main() diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py index f683577c47..7acc3cbbd5 100755 --- a/test/functional/rpc_help.py +++ b/test/functional/rpc_help.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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.""" @@ -43,6 +43,9 @@ def process_mapping(fname): class HelpRpcTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 self.supports_cli = False diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py index fcc49d0a75..0c29efb85a 100755 --- a/test/functional/rpc_invalid_address_message.py +++ b/test/functional/rpc_invalid_address_message.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 error messages for 'getaddressinfo' and 'validateaddress' RPC commands.""" @@ -39,6 +39,9 @@ INVALID_ADDRESS = 'asfah14i8fajz0123f' INVALID_ADDRESS_2 = '1q049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv' class InvalidAddressErrorMessageTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -92,15 +95,19 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework): self.check_invalid(INVALID_ADDRESS, 'Not a valid Bech32 or Base58 encoding') self.check_invalid(INVALID_ADDRESS_2, 'Not a valid Bech32 or Base58 encoding') + node = self.nodes[0] + + # Missing arg returns the help text + assert_raises_rpc_error(-1, "Return information about the given bitcoin address.", node.validateaddress) + # Explicit None is not allowed for required parameters + assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", node.validateaddress, None) + def test_getaddressinfo(self): node = self.nodes[0] assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE) - assert_raises_rpc_error(-5, "Not a valid Bech32 or Base58 encoding", node.getaddressinfo, BECH32_INVALID_PREFIX) - assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX) - assert_raises_rpc_error(-5, "Not a valid Bech32 or Base58 encoding", node.getaddressinfo, INVALID_ADDRESS) def run_test(self): diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index 1e33e7ca9c..69c5397ce2 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" diff --git a/test/functional/rpc_mempool_info.py b/test/functional/rpc_mempool_info.py index ae9c6572cf..246af22e50 100755 --- a/test/functional/rpc_mempool_info.py +++ b/test/functional/rpc_mempool_info.py @@ -18,7 +18,6 @@ class RPCMempoolInfoTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() confirmed_utxo = self.wallet.get_utxo() # Create a tree of unconfirmed transactions in the mempool: diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index f6ee6a5215..43d1e2c731 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 misc output.""" diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py index 41b9312969..46d9ffceae 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-2019 The Bitcoin Core developers +# Copyright (c) 2016-2020 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.""" @@ -30,6 +30,9 @@ class NamedArgumentTest(BitcoinTestFramework): assert_equal(node.echo(arg1=1), [None, 1]) assert_equal(node.echo(arg9=None), [None]*10) assert_equal(node.echo(arg0=0,arg3=3,arg9=9), [0] + [None]*2 + [3] + [None]*5 + [9]) + assert_equal(node.echo(0, 1, arg3=3, arg5=5), [0, 1, None, 3, None, 5]) + assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", node.echo, 0, 1, arg1=1) + assert_raises_rpc_error(-8, "Parameter arg1 specified twice both as positional and named argument", node.echo, 0, None, 2, arg1=1) if __name__ == '__main__': NamedArgumentTest().main() diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 65e3c82c87..5fdd5daddf 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. @@ -11,7 +11,6 @@ from decimal import Decimal from itertools import product import time -from test_framework.blocktools import COINBASE_MATURITY import test_framework.messages from test_framework.p2p import ( P2PInterface, @@ -43,7 +42,6 @@ def assert_net_servicesnames(servicesflag, servicenames): 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"]] self.supports_cli = False @@ -51,9 +49,6 @@ class NetTest(BitcoinTestFramework): def run_test(self): # We need miniwallet to make a transaction self.wallet = MiniWallet(self.nodes[0]) - self.generate(self.wallet, 1) - # Get out of IBD for the minfeefilter and getpeerinfo tests. - self.generate(self.nodes[0], COINBASE_MATURITY + 1) # By default, the test framework sets up an addnode connection from # node 1 --> node0. By connecting node0 --> node 1, we're left with @@ -112,7 +107,7 @@ class NetTest(BitcoinTestFramework): no_version_peer_conntime = int(time.time()) self.nodes[0].setmocktime(no_version_peer_conntime) with self.nodes[0].assert_debug_log([f"Added connection peer={no_version_peer_id}"]): - self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) + no_version_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) self.nodes[0].setmocktime(0) peer_info = self.nodes[0].getpeerinfo()[no_version_peer_id] peer_info.pop("addr") @@ -153,7 +148,8 @@ class NetTest(BitcoinTestFramework): "version": 0, }, ) - self.nodes[0].disconnect_p2ps() + no_version_peer.peer_disconnect() + self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 2) def test_getnettotals(self): self.log.info("Test getnettotals") @@ -184,7 +180,8 @@ class NetTest(BitcoinTestFramework): self.nodes[0].setnetworkactive(state=False) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False) # Wait a bit for all sockets to close - self.wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3) + for n in self.nodes: + self.wait_until(lambda: n.getnetworkinfo()['connections'] == 0, timeout=3) with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']): self.nodes[0].setnetworkactive(state=True) @@ -305,6 +302,9 @@ class NetTest(BitcoinTestFramework): assert_equal(node.addpeeraddress(address="", port=8333), {"success": False}) assert_equal(node.getnodeaddresses(count=0), []) + self.log.debug("Test that non-bool tried fails") + assert_raises_rpc_error(-3, "JSON value of type string is not of expected type bool", self.nodes[0].addpeeraddress, address="1.2.3.4", tried="True", port=1234) + self.log.debug("Test that adding an address with invalid port fails") assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=-1) assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress,address="1.2.3.4", port=65536) diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index 9a563cbf5f..6cb9760b3d 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """RPCs that handle raw transaction packages.""" @@ -7,35 +7,30 @@ from decimal import Decimal import random -from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE -from test_framework.test_framework import BitcoinTestFramework +from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, - COIN, - CTxInWitness, tx_from_hex, ) from test_framework.p2p import P2PTxInvStore -from test_framework.script import ( - CScript, - OP_TRUE, -) +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_fee_amount, assert_raises_rpc_error, ) from test_framework.wallet import ( - create_child_with_parents, - create_raw_chain, + COIN, DEFAULT_FEE, - make_chain, + MiniWallet, ) + class RPCPackagesTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True + self.extra_args = [["-whitelist=noban@127.0.0.1"]] # noban speeds up tx relay def assert_testres_equal(self, package_hex, testres_expected): """Shuffle package_hex and assert that the testmempoolaccept result matches testres_expected. This should only @@ -49,38 +44,38 @@ class RPCPackagesTest(BitcoinTestFramework): assert_equal(shuffled_testres, self.nodes[0].testmempoolaccept(shuffled_package)) def run_test(self): - self.log.info("Generate blocks to create UTXOs") node = self.nodes[0] - self.privkeys = [node.get_deterministic_priv_key().key] - self.address = node.get_deterministic_priv_key().address - self.coins = [] - # The last 100 coinbase transactions are premature - for b in self.generatetoaddress(node, 220, self.address)[:-100]: - coinbase = node.getblock(blockhash=b, verbosity=2)["tx"][0] - self.coins.append({ + + # get an UTXO that requires signature to be spent + deterministic_address = node.get_deterministic_priv_key().address + blockhash = self.generatetoaddress(node, 1, deterministic_address)[0] + coinbase = node.getblock(blockhash=blockhash, verbosity=2)["tx"][0] + coin = { "txid": coinbase["txid"], "amount": coinbase["vout"][0]["value"], "scriptPubKey": coinbase["vout"][0]["scriptPubKey"], - }) + "vout": 0, + "height": 0 + } + + self.wallet = MiniWallet(self.nodes[0]) + self.generate(self.wallet, COINBASE_MATURITY + 100) # blocks generated for inputs + self.log.info("Create some transactions") # Create some transactions that can be reused throughout the test. Never submit these to mempool. self.independent_txns_hex = [] self.independent_txns_testres = [] for _ in range(3): - coin = self.coins.pop() - rawtx = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}], - {self.address : coin["amount"] - Decimal("0.0001")}) - signedtx = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys) - assert signedtx["complete"] - testres = node.testmempoolaccept([signedtx["hex"]]) + tx_hex = self.wallet.create_self_transfer(fee_rate=Decimal("0.0001"))["hex"] + testres = self.nodes[0].testmempoolaccept([tx_hex]) assert testres[0]["allowed"] - self.independent_txns_hex.append(signedtx["hex"]) + self.independent_txns_hex.append(tx_hex) # testmempoolaccept returns a list of length one, avoid creating a 2D list self.independent_txns_testres.append(testres[0]) self.independent_txns_testres_blank = [{ "txid": res["txid"], "wtxid": res["wtxid"]} for res in self.independent_txns_testres] - self.test_independent() + self.test_independent(coin) self.test_chain() self.test_multiple_children() self.test_multiple_parents() @@ -88,14 +83,15 @@ class RPCPackagesTest(BitcoinTestFramework): self.test_rbf() self.test_submitpackage() - def test_independent(self): + def test_independent(self, coin): self.log.info("Test multiple independent transactions in a package") node = self.nodes[0] # For independent transactions, order doesn't matter. self.assert_testres_equal(self.independent_txns_hex, self.independent_txns_testres) self.log.info("Test an otherwise valid package with an extra garbage tx appended") - garbage_tx = node.createrawtransaction([{"txid": "00" * 32, "vout": 5}], {self.address: 1}) + address = node.get_deterministic_priv_key().address + garbage_tx = node.createrawtransaction([{"txid": "00" * 32, "vout": 5}], {address: 1}) tx = tx_from_hex(garbage_tx) # Only the txid and wtxids are returned because validation is incomplete for the independent txns. # Package validation is atomic: if the node cannot find a UTXO for any single tx in the package, @@ -105,9 +101,8 @@ class RPCPackagesTest(BitcoinTestFramework): self.assert_testres_equal(package_bad, testres_bad) self.log.info("Check testmempoolaccept tells us when some transactions completed validation successfully") - coin = self.coins.pop() tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}], - {self.address : coin["amount"] - Decimal("0.0001")}) + {address : coin["amount"] - Decimal("0.0001")}) tx_bad_sig = tx_from_hex(tx_bad_sig_hex) testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex + [tx_bad_sig_hex]) # By the time the signature for the last transaction is checked, all the other transactions @@ -120,23 +115,22 @@ class RPCPackagesTest(BitcoinTestFramework): }]) self.log.info("Check testmempoolaccept reports txns in packages that exceed max feerate") - coin = self.coins.pop() - tx_high_fee_raw = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}], - {self.address : coin["amount"] - Decimal("0.999")}) - tx_high_fee_signed = node.signrawtransactionwithkey(hexstring=tx_high_fee_raw, privkeys=self.privkeys) - assert tx_high_fee_signed["complete"] - tx_high_fee = tx_from_hex(tx_high_fee_signed["hex"]) - testres_high_fee = node.testmempoolaccept([tx_high_fee_signed["hex"]]) + tx_high_fee = self.wallet.create_self_transfer(fee=Decimal("0.999")) + testres_high_fee = node.testmempoolaccept([tx_high_fee["hex"]]) assert_equal(testres_high_fee, [ - {"txid": tx_high_fee.rehash(), "wtxid": tx_high_fee.getwtxid(), "allowed": False, "reject-reason": "max-fee-exceeded"} + {"txid": tx_high_fee["txid"], "wtxid": tx_high_fee["wtxid"], "allowed": False, "reject-reason": "max-fee-exceeded"} ]) - package_high_fee = [tx_high_fee_signed["hex"]] + self.independent_txns_hex + package_high_fee = [tx_high_fee["hex"]] + self.independent_txns_hex testres_package_high_fee = node.testmempoolaccept(package_high_fee) assert_equal(testres_package_high_fee, testres_high_fee + self.independent_txns_testres_blank) def test_chain(self): node = self.nodes[0] - (chain_hex, chain_txns) = create_raw_chain(node, self.coins.pop(), self.address, self.privkeys) + + chain = self.wallet.create_self_transfer_chain(chain_length=25) + chain_hex = [t["hex"] for t in chain] + chain_txns = [t["tx"] for t in chain] + self.log.info("Check that testmempoolaccept requires packages to be sorted by dependency") assert_equal(node.testmempoolaccept(rawtxs=chain_hex[::-1]), [{"txid": tx.rehash(), "wtxid": tx.getwtxid(), "package-error": "package-not-sorted"} for tx in chain_txns[::-1]]) @@ -158,78 +152,57 @@ class RPCPackagesTest(BitcoinTestFramework): def test_multiple_children(self): node = self.nodes[0] - self.log.info("Testmempoolaccept a package in which a transaction has two children within the package") - first_coin = self.coins.pop() - value = (first_coin["amount"] - Decimal("0.0002")) / 2 # Deduct reasonable fee and make 2 outputs - inputs = [{"txid": first_coin["txid"], "vout": 0}] - outputs = [{self.address : value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : value}] - rawtx = node.createrawtransaction(inputs, outputs) - - parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys) - assert parent_signed["complete"] - parent_tx = tx_from_hex(parent_signed["hex"]) - parent_txid = parent_tx.rehash() - assert node.testmempoolaccept([parent_signed["hex"]])[0]["allowed"] - parent_locking_script_a = parent_tx.vout[0].scriptPubKey.hex() - child_value = value - Decimal("0.0001") + parent_tx = self.wallet.create_self_transfer_multi(num_outputs=2) + assert node.testmempoolaccept([parent_tx["hex"]])[0]["allowed"] # Child A - (_, tx_child_a_hex, _, _) = make_chain(node, self.address, self.privkeys, parent_txid, child_value, 0, parent_locking_script_a) - assert not node.testmempoolaccept([tx_child_a_hex])[0]["allowed"] + child_a_tx = self.wallet.create_self_transfer(utxo_to_spend=parent_tx["new_utxos"][0]) + assert not node.testmempoolaccept([child_a_tx["hex"]])[0]["allowed"] # Child B - rawtx_b = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], {self.address : child_value}) - tx_child_b = tx_from_hex(rawtx_b) - tx_child_b.wit.vtxinwit = [CTxInWitness()] - tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] - tx_child_b_hex = tx_child_b.serialize().hex() - assert not node.testmempoolaccept([tx_child_b_hex])[0]["allowed"] + child_b_tx = self.wallet.create_self_transfer(utxo_to_spend=parent_tx["new_utxos"][1]) + assert not node.testmempoolaccept([child_b_tx["hex"]])[0]["allowed"] self.log.info("Testmempoolaccept with entire package, should work with children in either order") - testres_multiple_ab = node.testmempoolaccept(rawtxs=[parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]) - testres_multiple_ba = node.testmempoolaccept(rawtxs=[parent_signed["hex"], tx_child_b_hex, tx_child_a_hex]) + testres_multiple_ab = node.testmempoolaccept(rawtxs=[parent_tx["hex"], child_a_tx["hex"], child_b_tx["hex"]]) + testres_multiple_ba = node.testmempoolaccept(rawtxs=[parent_tx["hex"], child_b_tx["hex"], child_a_tx["hex"]]) assert all([testres["allowed"] for testres in testres_multiple_ab + testres_multiple_ba]) testres_single = [] # Test accept and then submit each one individually, which should be identical to package testaccept - for rawtx in [parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]: + for rawtx in [parent_tx["hex"], child_a_tx["hex"], child_b_tx["hex"]]: testres = node.testmempoolaccept([rawtx]) testres_single.append(testres[0]) # Submit the transaction now so its child should have no problem validating node.sendrawtransaction(rawtx) assert_equal(testres_single, testres_multiple_ab) - def test_multiple_parents(self): node = self.nodes[0] - self.log.info("Testmempoolaccept a package in which a transaction has multiple parents within the package") + for num_parents in [2, 10, 24]: # Test a package with num_parents parents and 1 child transaction. + parent_coins = [] package_hex = [] - parents_tx = [] - values = [] - parent_locking_scripts = [] + for _ in range(num_parents): - parent_coin = self.coins.pop() - value = parent_coin["amount"] - (tx, txhex, value, parent_locking_script) = make_chain(node, self.address, self.privkeys, parent_coin["txid"], value) - package_hex.append(txhex) - parents_tx.append(tx) - values.append(value) - parent_locking_scripts.append(parent_locking_script) - child_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, parent_locking_scripts) - # Package accept should work with the parents in any order (as long as parents come before child) + # Package accept should work with the parents in any order (as long as parents come before child) + parent_tx = self.wallet.create_self_transfer() + parent_coins.append(parent_tx["new_utxo"]) + package_hex.append(parent_tx["hex"]) + + child_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_coins, fee_per_output=2000) for _ in range(10): random.shuffle(package_hex) - testres_multiple = node.testmempoolaccept(rawtxs=package_hex + [child_hex]) + testres_multiple = node.testmempoolaccept(rawtxs=package_hex + [child_tx['hex']]) assert all([testres["allowed"] for testres in testres_multiple]) testres_single = [] # Test accept and then submit each one individually, which should be identical to package testaccept - for rawtx in package_hex + [child_hex]: + for rawtx in package_hex + [child_tx["hex"]]: testres_single.append(node.testmempoolaccept([rawtx])[0]) # Submit the transaction now so its child should have no problem validating node.sendrawtransaction(rawtx) @@ -237,77 +210,63 @@ class RPCPackagesTest(BitcoinTestFramework): def test_conflicting(self): node = self.nodes[0] - prevtx = self.coins.pop() - inputs = [{"txid": prevtx["txid"], "vout": 0}] - output1 = {node.get_deterministic_priv_key().address: 50 - 0.00125} - output2 = {ADDRESS_BCRT1_P2WSH_OP_TRUE: 50 - 0.00125} + coin = self.wallet.get_utxo() # tx1 and tx2 share the same inputs - rawtx1 = node.createrawtransaction(inputs, output1) - rawtx2 = node.createrawtransaction(inputs, output2) - signedtx1 = node.signrawtransactionwithkey(hexstring=rawtx1, privkeys=self.privkeys) - signedtx2 = node.signrawtransactionwithkey(hexstring=rawtx2, privkeys=self.privkeys) - tx1 = tx_from_hex(signedtx1["hex"]) - tx2 = tx_from_hex(signedtx2["hex"]) - assert signedtx1["complete"] - assert signedtx2["complete"] + tx1 = self.wallet.create_self_transfer(utxo_to_spend=coin) + tx2 = self.wallet.create_self_transfer(utxo_to_spend=coin) # Ensure tx1 and tx2 are valid by themselves - assert node.testmempoolaccept([signedtx1["hex"]])[0]["allowed"] - assert node.testmempoolaccept([signedtx2["hex"]])[0]["allowed"] + assert node.testmempoolaccept([tx1["hex"]])[0]["allowed"] + assert node.testmempoolaccept([tx2["hex"]])[0]["allowed"] self.log.info("Test duplicate transactions in the same package") - testres = node.testmempoolaccept([signedtx1["hex"], signedtx1["hex"]]) + testres = node.testmempoolaccept([tx1["hex"], tx1["hex"]]) assert_equal(testres, [ - {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"}, - {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"} + {"txid": tx1["txid"], "wtxid": tx1["wtxid"], "package-error": "conflict-in-package"}, + {"txid": tx1["txid"], "wtxid": tx1["wtxid"], "package-error": "conflict-in-package"} ]) self.log.info("Test conflicting transactions in the same package") - testres = node.testmempoolaccept([signedtx1["hex"], signedtx2["hex"]]) + testres = node.testmempoolaccept([tx1["hex"], tx2["hex"]]) assert_equal(testres, [ - {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"}, - {"txid": tx2.rehash(), "wtxid": tx2.getwtxid(), "package-error": "conflict-in-package"} + {"txid": tx1["txid"], "wtxid": tx1["wtxid"], "package-error": "conflict-in-package"}, + {"txid": tx2["txid"], "wtxid": tx2["wtxid"], "package-error": "conflict-in-package"} ]) def test_rbf(self): node = self.nodes[0] - coin = self.coins.pop() - inputs = [{"txid": coin["txid"], "vout": 0, "sequence": MAX_BIP125_RBF_SEQUENCE}] - fee = Decimal('0.00125000') - output = {node.get_deterministic_priv_key().address: 50 - fee} - raw_replaceable_tx = node.createrawtransaction(inputs, output) - signed_replaceable_tx = node.signrawtransactionwithkey(hexstring=raw_replaceable_tx, privkeys=self.privkeys) - testres_replaceable = node.testmempoolaccept([signed_replaceable_tx["hex"]]) - replaceable_tx = tx_from_hex(signed_replaceable_tx["hex"]) - assert_equal(testres_replaceable, [ - {"txid": replaceable_tx.rehash(), "wtxid": replaceable_tx.getwtxid(), - "allowed": True, "vsize": replaceable_tx.get_vsize(), "fees": { "base": fee }} - ]) - # Replacement transaction is identical except has double the fee - replacement_tx = tx_from_hex(signed_replaceable_tx["hex"]) - replacement_tx.vout[0].nValue -= int(fee * COIN) # Doubled fee - signed_replacement_tx = node.signrawtransactionwithkey(replacement_tx.serialize().hex(), self.privkeys) - replacement_tx = tx_from_hex(signed_replacement_tx["hex"]) + coin = self.wallet.get_utxo() + fee = Decimal("0.00125000") + replaceable_tx = self.wallet.create_self_transfer(utxo_to_spend=coin, sequence=MAX_BIP125_RBF_SEQUENCE, fee = fee) + testres_replaceable = node.testmempoolaccept([replaceable_tx["hex"]])[0] + assert_equal(testres_replaceable["txid"], replaceable_tx["txid"]) + assert_equal(testres_replaceable["wtxid"], replaceable_tx["wtxid"]) + assert testres_replaceable["allowed"] + assert_equal(testres_replaceable["vsize"], replaceable_tx["tx"].get_vsize()) + assert_equal(testres_replaceable["fees"]["base"], fee) + assert_fee_amount(fee, replaceable_tx["tx"].get_vsize(), testres_replaceable["fees"]["effective-feerate"]) + assert_equal(testres_replaceable["fees"]["effective-includes"], [replaceable_tx["wtxid"]]) - self.log.info("Test that transactions within a package cannot replace each other") - testres_rbf_conflicting = node.testmempoolaccept([signed_replaceable_tx["hex"], signed_replacement_tx["hex"]]) + # Replacement transaction is identical except has double the fee + replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=coin, sequence=MAX_BIP125_RBF_SEQUENCE, fee = 2 * fee) + testres_rbf_conflicting = node.testmempoolaccept([replaceable_tx["hex"], replacement_tx["hex"]]) assert_equal(testres_rbf_conflicting, [ - {"txid": replaceable_tx.rehash(), "wtxid": replaceable_tx.getwtxid(), "package-error": "conflict-in-package"}, - {"txid": replacement_tx.rehash(), "wtxid": replacement_tx.getwtxid(), "package-error": "conflict-in-package"} + {"txid": replaceable_tx["txid"], "wtxid": replaceable_tx["wtxid"], "package-error": "conflict-in-package"}, + {"txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "package-error": "conflict-in-package"} ]) self.log.info("Test that packages cannot conflict with mempool transactions, even if a valid BIP125 RBF") - node.sendrawtransaction(signed_replaceable_tx["hex"]) - testres_rbf_single = node.testmempoolaccept([signed_replacement_tx["hex"]]) # This transaction is a valid BIP125 replace-by-fee + self.wallet.sendrawtransaction(from_node=node, tx_hex=replaceable_tx["hex"]) + testres_rbf_single = node.testmempoolaccept([replacement_tx["hex"]]) assert testres_rbf_single[0]["allowed"] testres_rbf_package = self.independent_txns_testres_blank + [{ - "txid": replacement_tx.rehash(), "wtxid": replacement_tx.getwtxid(), "allowed": False, + "txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "allowed": False, "reject-reason": "bip125-replacement-disallowed" }] - self.assert_testres_equal(self.independent_txns_hex + [signed_replacement_tx["hex"]], testres_rbf_package) + self.assert_testres_equal(self.independent_txns_hex + [replacement_tx["hex"]], testres_rbf_package) def assert_equal_package_results(self, node, testmempoolaccept_result, submitpackage_result): """Assert that a successful submitpackage result is consistent with testmempoolaccept @@ -330,90 +289,78 @@ class RPCPackagesTest(BitcoinTestFramework): def test_submit_child_with_parents(self, num_parents, partial_submit): node = self.nodes[0] peer = node.add_p2p_connection(P2PTxInvStore()) - # Test a package with num_parents parents and 1 child transaction. - package_hex = [] + package_txns = [] - values = [] - scripts = [] + presubmitted_wtxids = set() for _ in range(num_parents): - parent_coin = self.coins.pop() - value = parent_coin["amount"] - (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, parent_coin["txid"], value) - package_hex.append(txhex) - package_txns.append(tx) - values.append(value) - scripts.append(spk) + parent_tx = self.wallet.create_self_transfer(fee=DEFAULT_FEE) + package_txns.append(parent_tx) if partial_submit and random.choice([True, False]): - node.sendrawtransaction(txhex) - child_hex = create_child_with_parents(node, self.address, self.privkeys, package_txns, values, scripts) - package_hex.append(child_hex) - package_txns.append(tx_from_hex(child_hex)) + node.sendrawtransaction(parent_tx["hex"]) + presubmitted_wtxids.add(parent_tx["wtxid"]) + child_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=[tx["new_utxo"] for tx in package_txns], fee_per_output=10000) #DEFAULT_FEE + package_txns.append(child_tx) - testmempoolaccept_result = node.testmempoolaccept(rawtxs=package_hex) - submitpackage_result = node.submitpackage(package=package_hex) + testmempoolaccept_result = node.testmempoolaccept(rawtxs=[tx["hex"] for tx in package_txns]) + submitpackage_result = node.submitpackage(package=[tx["hex"] for tx in package_txns]) # Check that each result is present, with the correct size and fees - for i in range(num_parents + 1): - tx = package_txns[i] + for package_txn in package_txns: + tx = package_txn["tx"] + assert tx.getwtxid() in submitpackage_result["tx-results"] wtxid = tx.getwtxid() assert wtxid in submitpackage_result["tx-results"] tx_result = submitpackage_result["tx-results"][wtxid] - assert_equal(tx_result, { - "txid": tx.rehash(), - "vsize": tx.get_vsize(), - "fees": { - "base": DEFAULT_FEE, - } - }) + assert_equal(tx_result["txid"], tx.rehash()) + assert_equal(tx_result["vsize"], tx.get_vsize()) + assert_equal(tx_result["fees"]["base"], DEFAULT_FEE) + if wtxid not in presubmitted_wtxids: + assert_fee_amount(DEFAULT_FEE, tx.get_vsize(), tx_result["fees"]["effective-feerate"]) + assert_equal(tx_result["fees"]["effective-includes"], [wtxid]) # submitpackage result should be consistent with testmempoolaccept and getmempoolentry self.assert_equal_package_results(node, testmempoolaccept_result, submitpackage_result) - # Package feerate is calculated for the remaining transactions after deduplication and - # individual submission. If only 0 or 1 transaction is left, e.g. because all transactions - # had high-feerates or were already in the mempool, no package feerate is provided. - # In this case, since all of the parents have high fees, each is accepted individually. - assert "package-feerate" not in submitpackage_result - # The node should announce each transaction. No guarantees for propagation. - peer.wait_for_broadcast([tx.getwtxid() for tx in package_txns]) + peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns]) self.generate(node, 1) - def test_submit_cpfp(self): node = self.nodes[0] peer = node.add_p2p_connection(P2PTxInvStore()) - # 2 parent 1 child CPFP. First parent pays high fees, second parent pays 0 fees and is - # fee-bumped by the child. - coin_rich = self.coins.pop() - coin_poor = self.coins.pop() - tx_rich, hex_rich, value_rich, spk_rich = make_chain(node, self.address, self.privkeys, coin_rich["txid"], coin_rich["amount"]) - tx_poor, hex_poor, value_poor, spk_poor = make_chain(node, self.address, self.privkeys, coin_poor["txid"], coin_poor["amount"], fee=0) + # Package with 2 parents and 1 child. One parent pays for itself using modified fees, and + # another has 0 fees but is bumped by child. + tx_poor = self.wallet.create_self_transfer(fee=0, fee_rate=0) + tx_rich = self.wallet.create_self_transfer(fee=0, fee_rate=0) + node.prioritisetransaction(tx_rich["txid"], 0, int(DEFAULT_FEE * COIN)) package_txns = [tx_rich, tx_poor] - hex_child = create_child_with_parents(node, self.address, self.privkeys, package_txns, [value_rich, value_poor], [spk_rich, spk_poor]) - tx_child = tx_from_hex(hex_child) + coins = [tx["new_utxo"] for tx in package_txns] + tx_child = self.wallet.create_self_transfer_multi(utxos_to_spend=coins, fee_per_output=10000) #DEFAULT_FEE package_txns.append(tx_child) - submitpackage_result = node.submitpackage([hex_rich, hex_poor, hex_child]) + submitpackage_result = node.submitpackage([tx["hex"] for tx in package_txns]) - rich_parent_result = submitpackage_result["tx-results"][tx_rich.getwtxid()] - poor_parent_result = submitpackage_result["tx-results"][tx_poor.getwtxid()] - child_result = submitpackage_result["tx-results"][tx_child.getwtxid()] - assert_equal(rich_parent_result["fees"]["base"], DEFAULT_FEE) + rich_parent_result = submitpackage_result["tx-results"][tx_rich["wtxid"]] + poor_parent_result = submitpackage_result["tx-results"][tx_poor["wtxid"]] + child_result = submitpackage_result["tx-results"][tx_child["tx"].getwtxid()] + assert_equal(rich_parent_result["fees"]["base"], 0) assert_equal(poor_parent_result["fees"]["base"], 0) assert_equal(child_result["fees"]["base"], DEFAULT_FEE) - # Package feerate is calculated for the remaining transactions after deduplication and - # individual submission. Since this package had a 0-fee parent, package feerate must have - # been used and returned. - assert "package-feerate" in submitpackage_result - assert_fee_amount(DEFAULT_FEE, rich_parent_result["vsize"] + child_result["vsize"], submitpackage_result["package-feerate"]) + # The "rich" parent does not require CPFP so its effective feerate. + assert_fee_amount(DEFAULT_FEE, tx_rich["tx"].get_vsize(), rich_parent_result["fees"]["effective-feerate"]) + assert_equal(rich_parent_result["fees"]["effective-includes"], [tx_rich["wtxid"]]) + # The "poor" parent and child's effective feerates are the same, composed of the child's fee + # divided by their combined vsize. + assert_fee_amount(DEFAULT_FEE, tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize(), poor_parent_result["fees"]["effective-feerate"]) + assert_fee_amount(DEFAULT_FEE, tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize(), child_result["fees"]["effective-feerate"]) + assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], poor_parent_result["fees"]["effective-includes"]) + assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], child_result["fees"]["effective-includes"]) # The node will broadcast each transaction, still abiding by its peer's fee filter - peer.wait_for_broadcast([tx.getwtxid() for tx in package_txns]) + peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns]) self.generate(node, 1) - def test_submitpackage(self): node = self.nodes[0] @@ -427,7 +374,7 @@ class RPCPackagesTest(BitcoinTestFramework): self.log.info("Submitpackage only allows packages of 1 child with its parents") # Chain of 3 transactions has too many generations - chain_hex, _ = create_raw_chain(node, self.coins.pop(), self.address, self.privkeys, 3) + chain_hex = [t["hex"] for t in self.wallet.create_self_transfer_chain(chain_length=25)] assert_raises_rpc_error(-25, "not-child-with-parents", node.submitpackage, chain_hex) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 8243f43736..58a80e37a2 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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. @@ -36,6 +36,7 @@ from test_framework.util import ( assert_approx, assert_equal, assert_greater_than, + assert_greater_than_or_equal, assert_raises_rpc_error, find_output, find_vout_for_address, @@ -47,8 +48,9 @@ import json import os -# Create one-input, one-output, no-fee transaction: class PSBTTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) def set_test_params(self): self.num_nodes = 3 @@ -105,6 +107,65 @@ class PSBTTest(BitcoinTestFramework): self.connect_nodes(0, 1) self.connect_nodes(0, 2) + def test_input_confs_control(self): + self.nodes[0].createwallet("minconf") + wallet = self.nodes[0].get_wallet_rpc("minconf") + + # Fund the wallet with different chain heights + for _ in range(2): + self.nodes[1].sendmany("", {wallet.getnewaddress():1, wallet.getnewaddress():1}) + self.generate(self.nodes[1], 1) + + unconfirmed_txid = wallet.sendtoaddress(wallet.getnewaddress(), 0.5) + + self.log.info("Crafting PSBT using an unconfirmed input") + target_address = self.nodes[1].getnewaddress() + psbtx1 = wallet.walletcreatefundedpsbt([], {target_address: 0.1}, 0, {'fee_rate': 1, 'maxconf': 0})['psbt'] + + # Make sure we only had the one input + tx1_inputs = self.nodes[0].decodepsbt(psbtx1)['tx']['vin'] + assert_equal(len(tx1_inputs), 1) + + utxo1 = tx1_inputs[0] + assert_equal(unconfirmed_txid, utxo1['txid']) + + signed_tx1 = wallet.walletprocesspsbt(psbtx1)['psbt'] + final_tx1 = wallet.finalizepsbt(signed_tx1)['hex'] + txid1 = self.nodes[0].sendrawtransaction(final_tx1) + + mempool = self.nodes[0].getrawmempool() + assert txid1 in mempool + + self.log.info("Fail to craft a new PSBT that sends more funds with add_inputs = False") + assert_raises_rpc_error(-4, "The preselected coins total amount does not cover the transaction target. Please allow other inputs to be automatically selected or include more coins manually", wallet.walletcreatefundedpsbt, [{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': False}) + + self.log.info("Fail to craft a new PSBT with minconf above highest one") + assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, [{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': True, 'minconf': 3, 'fee_rate': 10}) + + self.log.info("Fail to broadcast a new PSBT with maxconf 0 due to BIP125 rules to verify it actually chose unconfirmed outputs") + psbt_invalid = wallet.walletcreatefundedpsbt([{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': True, 'maxconf': 0, 'fee_rate': 10})['psbt'] + signed_invalid = wallet.walletprocesspsbt(psbt_invalid)['psbt'] + final_invalid = wallet.finalizepsbt(signed_invalid)['hex'] + assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, final_invalid) + + self.log.info("Craft a replacement adding inputs with highest confs possible") + psbtx2 = wallet.walletcreatefundedpsbt([{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}, 0, {'add_inputs': True, 'minconf': 2, 'fee_rate': 10})['psbt'] + tx2_inputs = self.nodes[0].decodepsbt(psbtx2)['tx']['vin'] + assert_greater_than_or_equal(len(tx2_inputs), 2) + for vin in tx2_inputs: + if vin['txid'] != unconfirmed_txid: + assert_greater_than_or_equal(self.nodes[0].gettxout(vin['txid'], vin['vout'])['confirmations'], 2) + + signed_tx2 = wallet.walletprocesspsbt(psbtx2)['psbt'] + final_tx2 = wallet.finalizepsbt(signed_tx2)['hex'] + txid2 = self.nodes[0].sendrawtransaction(final_tx2) + + mempool = self.nodes[0].getrawmempool() + assert txid1 not in mempool + assert txid2 in mempool + + wallet.unloadwallet() + def assert_change_type(self, psbtx, expected_type): """Assert that the given PSBT has a change output with the given type.""" @@ -119,7 +180,9 @@ class PSBTTest(BitcoinTestFramework): # If inputs are specified, do not automatically add more: utxo1 = self.nodes[0].listunspent()[0] - assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[0].walletcreatefundedpsbt, [{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90}) + assert_raises_rpc_error(-4, "The preselected coins total amount does not cover the transaction target. " + "Please allow other inputs to be automatically selected or include more coins manually", + self.nodes[0].walletcreatefundedpsbt, [{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90}) psbtx1 = self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90}, 0, {"add_inputs": True})['psbt'] assert_equal(len(self.nodes[0].decodepsbt(psbtx1)['tx']['vin']), 2) @@ -511,6 +574,8 @@ class PSBTTest(BitcoinTestFramework): # TODO: Re-enable this for segwit v1 # self.test_utxo_conversion() + self.test_input_confs_control() + # Test that psbts with p2pkh outputs are created properly p2pkh = self.nodes[0].getnewaddress(address_type='legacy') psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {"includeWatching" : True}, True) diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 930aaaa897..cdec4b2a85 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -14,8 +14,8 @@ Test the following RPCs: from collections import OrderedDict from decimal import Decimal +from itertools import product -from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, CTransaction, @@ -54,8 +54,10 @@ class multidict(dict): class RawTransactionsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): - self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [ ["-txindex"], @@ -65,8 +67,6 @@ class RawTransactionsTest(BitcoinTestFramework): # whitelist all peers to speed up tx relay / mempool sync for args in self.extra_args: args.append("-whitelist=noban@127.0.0.1") - self.requires_wallet = self.is_specified_wallet_compiled() - self.supports_cli = False def setup_network(self): @@ -75,17 +75,16 @@ class RawTransactionsTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.log.info("Prepare some coins for multiple *rawtransaction commands") - self.generate(self.wallet, 10) - self.generate(self.nodes[0], COINBASE_MATURITY + 1) self.getrawtransaction_tests() + self.getrawtransaction_verbosity_tests() self.createrawtransaction_tests() self.sendrawtransaction_tests() self.sendrawtransaction_testmempoolaccept_tests() self.decoderawtransaction_tests() self.transaction_version_number_tests() - if self.requires_wallet and not self.options.descriptors: + if self.is_specified_wallet_compiled() and not self.options.descriptors: + self.import_deterministic_coinbase_privkeys() self.raw_multisig_transaction_legacy_tests() def getrawtransaction_tests(self): @@ -114,6 +113,7 @@ class RawTransactionsTest(BitcoinTestFramework): # 4. valid parameters - supply txid and 1 for verbose. # We only check the "hex" field of the output so we don't need to update this test every time the output format changes. assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], tx['hex']) + assert_equal(self.nodes[n].getrawtransaction(txId, 2)["hex"], tx['hex']) # 5. valid parameters - supply txid and True for non-verbose assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], tx['hex']) @@ -124,13 +124,14 @@ class RawTransactionsTest(BitcoinTestFramework): # 6. invalid parameters - supply txid and invalid boolean values (strings) for verbose for value in ["True", "False"]: - assert_raises_rpc_error(-3, "not of expected type bool", self.nodes[n].getrawtransaction, txid=txId, verbose=value) + assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbose=value) + assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbosity=value) # 7. invalid parameters - supply txid and empty array - assert_raises_rpc_error(-3, "not of expected type bool", self.nodes[n].getrawtransaction, txId, []) + assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, []) # 8. invalid parameters - supply txid and empty dict - assert_raises_rpc_error(-3, "not of expected type bool", self.nodes[n].getrawtransaction, txId, {}) + assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, {}) # Make a tx by sending, then generate 2 blocks; block1 has the tx in it tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid'] @@ -143,9 +144,10 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(gottx['in_active_chain'], True) if n == 0: self.log.info("Test getrawtransaction with -txindex, without blockhash: 'in_active_chain' should be absent") - gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True) - assert_equal(gottx['txid'], tx) - assert 'in_active_chain' not in gottx + for v in [1,2]: + gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v) + assert_equal(gottx['txid'], tx) + assert 'in_active_chain' not in gottx else: self.log.info("Test getrawtransaction without -txindex, without blockhash: expect the call to raise") assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txid=tx, verbose=True) @@ -170,6 +172,70 @@ class RawTransactionsTest(BitcoinTestFramework): block = self.nodes[0].getblock(self.nodes[0].getblockhash(0)) assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction", self.nodes[0].getrawtransaction, block['merkleroot']) + def getrawtransaction_verbosity_tests(self): + tx = self.wallet.send_self_transfer(from_node=self.nodes[1])['txid'] + [block1] = self.generate(self.nodes[1], 1) + fields = [ + 'blockhash', + 'blocktime', + 'confirmations', + 'hash', + 'hex', + 'in_active_chain', + 'locktime', + 'size', + 'time', + 'txid', + 'vin', + 'vout', + 'vsize', + 'weight', + ] + prevout_fields = [ + 'generated', + 'height', + 'value', + 'scriptPubKey', + ] + script_pub_key_fields = [ + 'address', + 'asm', + 'hex', + 'type', + ] + # node 0 & 2 with verbosity 1 & 2 + for n, v in product([0, 2], [1, 2]): + self.log.info(f"Test getrawtransaction_verbosity {v} {'with' if n == 0 else 'without'} -txindex, with blockhash") + gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v, blockhash=block1) + missing_fields = set(fields).difference(gottx.keys()) + if missing_fields: + raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction") + + assert len(gottx['vin']) > 0 + if v == 1: + assert 'fee' not in gottx + assert 'prevout' not in gottx['vin'][0] + if v == 2: + assert isinstance(gottx['fee'], Decimal) + assert 'prevout' in gottx['vin'][0] + prevout = gottx['vin'][0]['prevout'] + script_pub_key = prevout['scriptPubKey'] + + missing_fields = set(prevout_fields).difference(prevout.keys()) + if missing_fields: + raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction") + + missing_fields = set(script_pub_key_fields).difference(script_pub_key.keys()) + if missing_fields: + raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction") + + # check verbosity 2 without blockhash but with txindex + assert 'fee' in self.nodes[0].getrawtransaction(txid=tx, verbosity=2) + # check that coinbase has no fee or does not throw any errors for verbosity 2 + coin_base = self.nodes[1].getblock(block1)['tx'][0] + gottx = self.nodes[1].getrawtransaction(txid=coin_base, verbosity=2, blockhash=block1) + assert 'fee' not in gottx + def createrawtransaction_tests(self): self.log.info("Test createrawtransaction") # Test `createrawtransaction` required parameters diff --git a/test/functional/rpc_scanblocks.py b/test/functional/rpc_scanblocks.py index 743cdf89ed..126e95362b 100755 --- a/test/functional/rpc_scanblocks.py +++ b/test/functional/rpc_scanblocks.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 scanblocks RPC call.""" @@ -27,7 +27,6 @@ class ScanblocksTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] wallet = MiniWallet(node) - wallet.rescan_utxos() # send 1.0, mempool only _, spk_1, addr_1 = getnewdestination() @@ -46,7 +45,7 @@ class ScanblocksTest(BitcoinTestFramework): self.wait_until(lambda: all(i["synced"] for i in node.getindexinfo().values())) out = node.scanblocks("start", [f"addr({addr_1})"]) - assert(blockhash in out['relevant_blocks']) + assert blockhash in out['relevant_blocks'] assert_equal(height, out['to_height']) assert_equal(0, out['from_height']) @@ -56,24 +55,30 @@ class ScanblocksTest(BitcoinTestFramework): # make sure the blockhash is not in the filter result if we set the start_height # to the just mined block (unlikely to hit a false positive) - assert(blockhash not in node.scanblocks( - "start", [f"addr({addr_1})"], height_new)['relevant_blocks']) + assert blockhash not in node.scanblocks( + "start", [f"addr({addr_1})"], height_new)['relevant_blocks'] # make sure the blockhash is present when using the first mined block as start_height - assert(blockhash in node.scanblocks( - "start", [f"addr({addr_1})"], height)['relevant_blocks']) + assert blockhash in node.scanblocks( + "start", [f"addr({addr_1})"], height)['relevant_blocks'] + for v in [False, True]: + assert blockhash in node.scanblocks( + action="start", + scanobjects=[f"addr({addr_1})"], + start_height=height, + options={"filter_false_positives": v})['relevant_blocks'] # also test the stop height - assert(blockhash in node.scanblocks( - "start", [f"addr({addr_1})"], height, height)['relevant_blocks']) + assert blockhash in node.scanblocks( + "start", [f"addr({addr_1})"], height, height)['relevant_blocks'] # use the stop_height to exclude the relevant block - assert(blockhash not in node.scanblocks( - "start", [f"addr({addr_1})"], 0, height - 1)['relevant_blocks']) + assert blockhash not in node.scanblocks( + "start", [f"addr({addr_1})"], 0, height - 1)['relevant_blocks'] # make sure the blockhash is present when using the first mined block as start_height - assert(blockhash in node.scanblocks( - "start", [{"desc": f"pkh({parent_key}/*)", "range": [0, 100]}], height)['relevant_blocks']) + assert blockhash in node.scanblocks( + "start", [{"desc": f"pkh({parent_key}/*)", "range": [0, 100]}], height)['relevant_blocks'] # check that false-positives are included in the result now; note that # finding a false-positive at runtime would take too long, hence we simply @@ -89,13 +94,16 @@ class ScanblocksTest(BitcoinTestFramework): false_positive_hash = bip158_basic_element_hash(false_positive_spk, 1, genesis_blockhash) assert_equal(genesis_coinbase_hash, false_positive_hash) - assert(genesis_blockhash in node.scanblocks( - "start", [{"desc": f"raw({genesis_coinbase_spk.hex()})"}], 0, 0)['relevant_blocks']) - assert(genesis_blockhash in node.scanblocks( - "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0)['relevant_blocks']) + assert genesis_blockhash in node.scanblocks( + "start", [{"desc": f"raw({genesis_coinbase_spk.hex()})"}], 0, 0)['relevant_blocks'] + assert genesis_blockhash in node.scanblocks( + "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0)['relevant_blocks'] - # TODO: after an "accurate" mode for scanblocks is implemented (e.g. PR #26325) - # check here that it filters out the false-positive + # check that the filter_false_positives option works + assert genesis_blockhash in node.scanblocks( + "start", [{"desc": f"raw({genesis_coinbase_spk.hex()})"}], 0, 0, "basic", {"filter_false_positives": True})['relevant_blocks'] + assert genesis_blockhash not in node.scanblocks( + "start", [{"desc": f"raw({false_positive_spk.hex()})"}], 0, 0, "basic", {"filter_false_positives": True})['relevant_blocks'] # test node with disabled blockfilterindex assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py index 6eb5b493b9..507a4f48e5 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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.""" @@ -31,7 +31,6 @@ class ScantxoutsetTest(BitcoinTestFramework): def run_test(self): self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() self.log.info("Test if we find coinbase outputs.") assert_equal(sum(u["coinbase"] for u in self.nodes[0].scantxoutset("start", [self.wallet.get_descriptor()])["unspents"]), 49) diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py index de17b2b929..4300190387 100755 --- a/test/functional/rpc_signer.py +++ b/test/functional/rpc_signer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 external signer. diff --git a/test/functional/rpc_signmessagewithprivkey.py b/test/functional/rpc_signmessagewithprivkey.py index 6635da150f..c5df22157d 100755 --- a/test/functional/rpc_signmessagewithprivkey.py +++ b/test/functional/rpc_signmessagewithprivkey.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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 messages with private key.""" diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index d04d05962f..60b7ce8d20 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test gettxoutproof and verifytxoutproof RPCs.""" -from test_framework.blocktools import COINBASE_MATURITY from test_framework.messages import ( CMerkleBlock, from_hex, @@ -20,7 +19,6 @@ from test_framework.wallet import MiniWallet class MerkleBlockTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = True self.extra_args = [ [], ["-txindex"], @@ -28,12 +26,9 @@ class MerkleBlockTest(BitcoinTestFramework): def run_test(self): miniwallet = MiniWallet(self.nodes[0]) - # Add enough mature utxos to the wallet, so that all txs spend confirmed coins - self.generate(miniwallet, 5) - self.generate(self.nodes[0], COINBASE_MATURITY) chain_height = self.nodes[1].getblockcount() - assert_equal(chain_height, 105) + assert_equal(chain_height, 200) txid1 = miniwallet.send_self_transfer(from_node=self.nodes[0])['txid'] txid2 = miniwallet.send_self_transfer(from_node=self.nodes[0])['txid'] diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py index 024e8aec1a..cb99e483ec 100755 --- a/test/functional/rpc_uptime.py +++ b/test/functional/rpc_uptime.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 1a35a57802..8cc3ec401e 100755 --- a/test/functional/rpc_users.py +++ b/test/functional/rpc_users.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2020 The Bitcoin Core developers +# Copyright (c) 2015-2022 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.""" @@ -53,13 +53,13 @@ class HTTPBasicsTest(BitcoinTestFramework): # Generate RPCAUTH with specified password self.rt2password = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" - p = subprocess.Popen([sys.executable, gen_rpcauth, 'rt2', self.rt2password], stdout=subprocess.PIPE, universal_newlines=True) + p = subprocess.Popen([sys.executable, gen_rpcauth, 'rt2', self.rt2password], stdout=subprocess.PIPE, text=True) lines = p.stdout.read().splitlines() rpcauth2 = lines[1] # Generate RPCAUTH without specifying password self.user = ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10)) - p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, universal_newlines=True) + p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, text=True) lines = p.stdout.read().splitlines() rpcauth3 = lines[1] self.password = lines[3] diff --git a/test/functional/test-shell.md b/test/functional/test-shell.md index 78737509cb..80f4e88109 100644 --- a/test/functional/test-shell.md +++ b/test/functional/test-shell.md @@ -93,8 +93,10 @@ We now let the first node generate 101 regtest blocks, and direct the coinbase rewards to a wallet address owned by the mining node. ``` +>>> test.nodes[0].createwallet('default') +{'name': 'default', 'warning': 'Empty string given as passphrase, wallet will not be encrypted.'} >>> address = test.nodes[0].getnewaddress() ->>> test.self.generatetoaddress(nodes[0], 101, address) +>>> test.generatetoaddress(test.nodes[0], 101, address) ['2b98dd0044aae6f1cca7f88a0acf366a4bfe053c7f7b00da3c0d115f03d67efb', ... ``` Since the two nodes are both initialized by default to establish an outbound diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index 92244b5ed8..959a2a65bd 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-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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 Bitcoin addresses. diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py index c4ffd1fbf6..dd20b28550 100644 --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -131,10 +131,12 @@ class AuthServiceProxy(): json.dumps(args or argsn, default=EncodeDecimal, ensure_ascii=self.ensure_ascii), )) if args and argsn: - raise ValueError('Cannot handle both named and positional arguments') + params = dict(args=args, **argsn) + else: + params = args or argsn return {'version': '1.1', 'method': self._service_name, - 'params': args or argsn, + 'params': params, 'id': AuthServiceProxy.__id_count} def __call__(self, *args, **argsn): diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index 574ea10356..b08cc6a3f9 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-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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.""" @@ -61,6 +61,7 @@ WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed" NORMAL_GBT_REQUEST_PARAMS = {"rules": ["segwit"]} VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4 +MIN_BLOCKS_TO_KEEP = 288 def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl=None, txlist=None): @@ -120,7 +121,7 @@ def script_BIP34_coinbase_height(height): return CScript([CScriptNum(height)]) -def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValue=50): +def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50): """Create a coinbase transaction. If pubkey is passed in, the coinbase output will be a P2PK output; @@ -138,6 +139,8 @@ def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValu coinbaseoutput.nValue += fees if pubkey is not None: coinbaseoutput.scriptPubKey = key_to_p2pk_script(pubkey) + elif script_pubkey is not None: + coinbaseoutput.scriptPubKey = script_pubkey else: coinbaseoutput.scriptPubKey = CScript([OP_TRUE]) coinbase.vout = [coinbaseoutput] diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py index 68afc1383d..ad305ce1ef 100644 --- a/test/functional/test_framework/key.py +++ b/test/functional/test_framework/key.py @@ -139,7 +139,7 @@ class EllipticCurve: See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Addition (with affine point)""" x1, y1, z1 = p1 x2, y2, z2 = p2 - assert(z2 == 1) + assert z2 == 1 # Adding to the point at infinity is a no-op if z1 == 0: return p2 @@ -262,7 +262,7 @@ class ECPubKey(): return self.valid def get_bytes(self): - assert(self.valid) + assert self.valid p = SECP256K1.affine(self.p) if p is None: return None @@ -276,7 +276,7 @@ class ECPubKey(): See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the ECDSA verifier algorithm""" - assert(self.valid) + assert self.valid # Extract r and s from the DER formatted signature. Return false for # any DER encoding errors. @@ -349,7 +349,7 @@ class ECKey(): def set(self, secret, compressed): """Construct a private key object with given 32-byte secret and compressed flag.""" - assert(len(secret) == 32) + assert len(secret) == 32 secret = int.from_bytes(secret, 'big') self.valid = (secret > 0 and secret < SECP256K1_ORDER) if self.valid: @@ -362,7 +362,7 @@ class ECKey(): def get_bytes(self): """Retrieve the 32-byte representation of this key.""" - assert(self.valid) + assert self.valid return self.secret.to_bytes(32, 'big') @property @@ -375,7 +375,7 @@ class ECKey(): def get_pubkey(self): """Compute an ECPubKey object for this secret key.""" - assert(self.valid) + assert self.valid ret = ECPubKey() p = SECP256K1.mul([(SECP256K1_G, self.secret)]) ret.p = p @@ -388,7 +388,7 @@ class ECKey(): See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the ECDSA signer algorithm.""" - assert(self.valid) + assert self.valid z = int.from_bytes(msg, 'big') # Note: no RFC6979 by default, but a simple random nonce (some tests rely on distinct transactions for the same operation) if rfc6979: diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 252b49cc6d..8c6f68cacb 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-2021 The Bitcoin Core developers +# Copyright (c) 2010-2022 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 @@ -1840,29 +1840,23 @@ class msg_cfcheckpt: self.filter_type, self.stop_hash) class msg_sendtxrcncl: - __slots__ = ("initiator", "responder", "version", "salt") + __slots__ = ("version", "salt") msgtype = b"sendtxrcncl" def __init__(self): - self.initiator = False - self.responder = False self.version = 0 self.salt = 0 def deserialize(self, f): - self.initiator = struct.unpack("<?", f.read(1))[0] - self.responder = struct.unpack("<?", f.read(1))[0] self.version = struct.unpack("<I", f.read(4))[0] self.salt = struct.unpack("<Q", f.read(8))[0] def serialize(self): r = b"" - r += struct.pack("<?", self.initiator) - r += struct.pack("<?", self.responder) r += struct.pack("<I", self.version) r += struct.pack("<Q", self.salt) return r def __repr__(self): - return "msg_sendtxrcncl(initiator=%i, responder=%i, version=%lu, salt=%lu)" %\ - (self.initiator, self.responder, self.version, self.salt) + return "msg_sendtxrcncl(version=%lu, salt=%lu)" %\ + (self.version, self.salt) diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index b64f66e69b..fcea4b2f68 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index 05b46e630c..59157f4755 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.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-2021 The Bitcoin Core developers +# Copyright (c) 2010-2022 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 objects for interacting with a bitcoind node over the p2p protocol. diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 2b70eab4e4..443cae86a1 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-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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 signature hash functions. @@ -12,7 +12,7 @@ import struct import unittest from typing import List, Dict -from .key import TaggedHash, tweak_add_pubkey +from .key import TaggedHash, tweak_add_pubkey, compute_xonly_pubkey from .messages import ( CTransaction, @@ -597,6 +597,13 @@ class CScript(bytes): lastOpcode = opcode return n + def IsWitnessProgram(self): + """A witness program is any valid CScript that consists of a 1-byte + push opcode followed by a data push between 2 and 40 bytes.""" + return ((4 <= len(self) <= 42) and + (self[0] == OP_0 or (OP_1 <= self[0] <= OP_16)) and + (self[1] + 2 == len(self))) + SIGHASH_DEFAULT = 0 # Taproot-only default, semantics same as SIGHASH_ALL SIGHASH_ALL = 1 @@ -824,10 +831,10 @@ def taproot_tree_helper(scripts): if len(scripts) == 1: # One entry: treat as a leaf script = scripts[0] - assert(not callable(script)) + assert not callable(script) if isinstance(script, list): return taproot_tree_helper(script) - assert(isinstance(script, tuple)) + assert isinstance(script, tuple) version = LEAF_VERSION_TAPSCRIPT name = script[0] code = script[1] @@ -872,7 +879,7 @@ TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,internal_pubkey,negflag,tw # - merklebranch: the merkle branch to use for this leaf (32*N bytes) TaprootLeafInfo = namedtuple("TaprootLeafInfo", "script,version,merklebranch,leaf_hash") -def taproot_construct(pubkey, scripts=None): +def taproot_construct(pubkey, scripts=None, treat_internal_as_infinity=False): """Construct a tree of Taproot spending conditions pubkey: a 32-byte xonly pubkey for the internal pubkey (bytes) @@ -891,7 +898,10 @@ def taproot_construct(pubkey, scripts=None): ret, h = taproot_tree_helper(scripts) tweak = TaggedHash("TapTweak", pubkey + h) - tweaked, negated = tweak_add_pubkey(pubkey, tweak) + if treat_internal_as_infinity: + tweaked, negated = compute_xonly_pubkey(tweak) + else: + tweaked, negated = tweak_add_pubkey(pubkey, tweak) leaves = dict((name, TaprootLeafInfo(script, version, merklebranch, leaf)) for name, version, script, merklebranch, leaf in ret) return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves, h, tweaked) diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py index b114002145..62894cc0f4 100755 --- a/test/functional/test_framework/script_util.py +++ b/test/functional/test_framework/script_util.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Useful Script constants and utils.""" @@ -13,12 +13,13 @@ from test_framework.script import ( OP_EQUAL, OP_EQUALVERIFY, OP_HASH160, + OP_RETURN, hash160, sha256, ) # To prevent a "tx-size-small" policy rule error, a transaction has to have a -# non-witness size of at least 82 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in +# non-witness size of at least 65 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in # src/policy/policy.h). Considering a Tx with the smallest possible single # input (blank, empty scriptSig), and with an output omitting the scriptPubKey, # we get to a minimum size of 60 bytes: @@ -28,15 +29,15 @@ from test_framework.script import ( # Output: 8 [Amount] + 1 [scriptPubKeyLen] = 9 bytes # # Hence, the scriptPubKey of the single output has to have a size of at -# least 22 bytes, which corresponds to the size of a P2WPKH scriptPubKey. -# The following script constant consists of a single push of 21 bytes of 'a': -# <PUSH_21> <21-bytes of 'a'> -# resulting in a 22-byte size. It should be used whenever (small) fake -# scriptPubKeys are needed, to guarantee that the minimum transaction size is -# met. -DUMMY_P2WPKH_SCRIPT = CScript([b'a' * 21]) -DUMMY_2_P2WPKH_SCRIPT = CScript([b'b' * 21]) - +# least 5 bytes. +MIN_STANDARD_TX_NONWITNESS_SIZE = 65 +MIN_PADDING = MIN_STANDARD_TX_NONWITNESS_SIZE - 10 - 41 - 9 +assert MIN_PADDING == 5 + +# This script cannot be spent, allowing dust output values under +# standardness checks +DUMMY_MIN_OP_RETURN_SCRIPT = CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 1))) +assert len(DUMMY_MIN_OP_RETURN_SCRIPT) == MIN_PADDING def key_to_p2pk_script(key): key = check_key(key) diff --git a/test/functional/test_framework/siphash.py b/test/functional/test_framework/siphash.py index 5ad245cf1b..884dbcab46 100644 --- a/test/functional/test_framework/siphash.py +++ b/test/functional/test_framework/siphash.py @@ -31,7 +31,7 @@ def siphash_round(v0, v1, v2, v3): def siphash(k0, k1, data): - assert(type(data) == bytes) + assert type(data) == bytes v0 = 0x736f6d6570736575 ^ k0 v1 = 0x646f72616e646f6d ^ k1 v2 = 0x6c7967656e657261 ^ k0 @@ -61,5 +61,5 @@ def siphash(k0, k1, data): def siphash256(k0, k1, num): - assert(type(num) == int) + assert type(num) == int return siphash(k0, k1, num.to_bytes(32, 'little')) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index b1164b98fd..823958397d 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -97,6 +97,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.chain: str = 'regtest' self.setup_clean_chain: bool = False self.nodes: List[TestNode] = [] + self.extra_args = None self.network_thread = None self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond self.supports_cli = True @@ -113,7 +114,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.wallet_names = None # By default the wallet is not required. Set to true by skip_if_no_wallet(). # When False, we ignore wallet_names regardless of what it is. - self.requires_wallet = False + self._requires_wallet = False # Disable ThreadOpenConnections by default, so that adding entries to # addrman will not result in automatic connections to them. self.disable_autoconnect = True @@ -194,12 +195,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): help="set a random seed for deterministically reproducing a previous test run") parser.add_argument('--timeout-factor', dest="timeout_factor", type=float, default=1.0, help='adjust test timeouts by a factor. Setting it to 0 disables all timeouts') - group = parser.add_mutually_exclusive_group() - group.add_argument("--descriptors", action='store_const', const=True, - help="Run test using a descriptor wallet", dest='descriptors') - group.add_argument("--legacy-wallet", action='store_const', const=False, - help="Run test using legacy wallets", dest='descriptors') - self.add_options(parser) # Running TestShell in a Jupyter notebook causes an additional -f argument # To keep TestShell from failing with an "unrecognized argument" error, we add a dummy "-f" argument @@ -212,15 +207,22 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): config.read_file(open(self.options.configfile)) self.config = config - if self.options.descriptors is None: - # Prefer BDB unless it isn't available - if self.is_bdb_compiled(): - self.options.descriptors = False - elif self.is_sqlite_compiled(): + if "descriptors" not in self.options: + # Wallet is not required by the test at all and the value of self.options.descriptors won't matter. + # It still needs to exist and be None in order for tests to work however. + # So set it to None to force -disablewallet, because the wallet is not needed. + self.options.descriptors = None + elif self.options.descriptors is None: + # Some wallet is either required or optionally used by the test. + # Prefer SQLite unless it isn't available + if self.is_sqlite_compiled(): self.options.descriptors = True + elif self.is_bdb_compiled(): + self.options.descriptors = False else: # If neither are compiled, tests requiring a wallet will be skipped and the value of self.options.descriptors won't matter # It still needs to exist and be None in order for tests to work however. + # So set it to None, which will also set -disablewallet. self.options.descriptors = None PortSeed.n = self.options.port_seed @@ -407,12 +409,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): def setup_nodes(self): """Override this method to customize test node setup""" - extra_args = [[]] * self.num_nodes - if hasattr(self, "extra_args"): - extra_args = self.extra_args - self.add_nodes(self.num_nodes, extra_args) + self.add_nodes(self.num_nodes, self.extra_args) self.start_nodes() - if self.requires_wallet: + if self._requires_wallet: self.import_deterministic_coinbase_privkeys() if not self.setup_clean_chain: for n in self.nodes: @@ -446,6 +445,21 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): # Public helper methods. These can be accessed by the subclass test scripts. + def add_wallet_options(self, parser, *, descriptors=True, legacy=True): + kwargs = {} + if descriptors + legacy == 1: + # If only one type can be chosen, set it as default + kwargs["default"] = descriptors + group = parser.add_mutually_exclusive_group( + # If only one type is allowed, require it to be set in test_runner.py + required=os.getenv("REQUIRE_WALLET_TYPE_SET") == "1" and "default" in kwargs) + if descriptors: + group.add_argument("--descriptors", action='store_const', const=True, **kwargs, + help="Run test using a descriptor wallet", dest='descriptors') + if legacy: + group.add_argument("--legacy-wallet", action='store_const', const=False, **kwargs, + help="Run test using legacy wallets", dest='descriptors') + def add_nodes(self, num_nodes: int, extra_args=None, *, rpchost=None, binary=None, binary_cli=None, versions=None): """Instantiate TestNode objects. @@ -594,6 +608,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.wait_until(lambda: sum(peer['version'] != 0 for peer in to_connection.getpeerinfo()) == to_num_peers) self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()) == from_num_peers) self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in to_connection.getpeerinfo()) == to_num_peers) + # The message bytes are counted before processing the message, so make + # sure it was fully processed by waiting for a ping. + self.wait_until(lambda: sum(peer["bytesrecv_per_msg"].pop("pong", 0) >= 32 for peer in from_connection.getpeerinfo()) == from_num_peers) + self.wait_until(lambda: sum(peer["bytesrecv_per_msg"].pop("pong", 0) >= 32 for peer in to_connection.getpeerinfo()) == to_num_peers) def disconnect_nodes(self, a, b): def disconnect_nodes_helper(node_a, node_b): @@ -836,6 +854,13 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): except ImportError: raise SkipTest("python3-zmq module not available.") + def skip_if_no_py_sqlite3(self): + """Attempt to import the sqlite3 package and skip the test if the import fails.""" + try: + import sqlite3 # noqa + except ImportError: + raise SkipTest("sqlite3 module not available.") + def skip_if_no_python_bcc(self): """Attempt to import the bcc package and skip the tests if the import fails.""" try: @@ -866,7 +891,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): def skip_if_no_wallet(self): """Skip the running test if wallet has not been compiled.""" - self.requires_wallet = True + self._requires_wallet = True if not self.is_wallet_compiled(): raise SkipTest("wallet has not been compiled.") if self.options.descriptors: diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 0075fa0996..f3d81ed7da 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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""" @@ -105,6 +105,9 @@ class TestNode(): "-debugexclude=rand", "-uacomment=testnode%d" % i, ] + if self.descriptors is None: + self.args.append("-disablewallet") + if use_valgrind: default_suppressions_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), @@ -334,7 +337,7 @@ class TestNode(): return self.log.debug("Stopping node") try: - # Do not use wait argument when testing older nodes, e.g. in feature_backwards_compatibility.py + # Do not use wait argument when testing older nodes, e.g. in wallet_backwards_compatibility.py if self.version_is_at_least(180000): self.stop(wait=wait) else: @@ -656,7 +659,8 @@ class TestNode(): return len([peer for peer in self.getpeerinfo() if peer['subver'] == P2P_SUBVERSION]) def disconnect_p2ps(self): - """Close all p2p connections to the node.""" + """Close all p2p connections to the node. + Use only after each p2p has sent a version message to ensure the wait works.""" for p in self.p2ps: p.peer_disconnect() del self.p2ps[:] @@ -719,7 +723,6 @@ class TestNodeCLI(): """Run bitcoin-cli command. Deserializes returned string as python object.""" pos_args = [arg_to_cli(arg) for arg in args] named_args = [str(key) + "=" + arg_to_cli(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 if named_args: p_args += ["-named"] @@ -727,7 +730,7 @@ class TestNodeCLI(): p_args += [command] p_args += pos_args + named_args self.log.debug("Running bitcoin-cli {}".format(p_args[2:])) - process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) cli_stdout, cli_stderr = process.communicate(input=self.input) returncode = process.poll() if returncode: diff --git a/test/functional/test_framework/test_shell.py b/test/functional/test_framework/test_shell.py index 26df128f1f..09ccec28a1 100644 --- a/test/functional/test_framework/test_shell.py +++ b/test/functional/test_framework/test_shell.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +16,9 @@ class TestShell: start a single TestShell at a time.""" class __TestShell(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): pass diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index bfc835f272..9048a915b2 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -488,28 +488,6 @@ def find_output(node, txid, amount, *, blockhash=None): raise RuntimeError("find_output txid %s : %s not found" % (txid, str(amount))) -def chain_transaction(node, parent_txids, vouts, value, fee, num_outputs): - """Build and send a transaction that spends the given inputs (specified - by lists of parent_txid:vout each), with the desired total value and fee, - equally divided up to the desired number of outputs. - - Returns a tuple with the txid and the amount sent per output. - """ - send_value = satoshi_round((value - fee)/num_outputs) - inputs = [] - for (txid, vout) in zip(parent_txids, vouts): - inputs.append({'txid' : txid, 'vout' : vout}) - outputs = {} - for _ in range(num_outputs): - outputs[node.getnewaddress()] = send_value - rawtx = node.createrawtransaction(inputs, outputs, 0, True) - signedtx = node.signrawtransactionwithwallet(rawtx) - txid = node.sendrawtransaction(signedtx['hex']) - fulltx = node.getrawtransaction(txid, 1) - assert len(fulltx['vout']) == num_outputs # make sure we didn't generate a change output - return (txid, send_value) - - # Create large OP_RETURN txouts that can be appended to a transaction # to make it large (helper for constructing large transactions). The # total serialized size of the txouts is about 66k vbytes. diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index 374fda5c23..f3253630c4 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """A limited-functionality wallet, which may replace a real wallet in tests""" @@ -32,7 +32,6 @@ from test_framework.messages import ( CTxIn, CTxInWitness, CTxOut, - tx_from_hex, ) from test_framework.script import ( CScript, @@ -56,6 +55,7 @@ from test_framework.util import ( assert_equal, assert_greater_than_or_equal, ) +from test_framework.blocktools import COINBASE_MATURITY DEFAULT_FEE = Decimal("0.0001") @@ -101,8 +101,15 @@ class MiniWallet: self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true() self._scriptPubKey = bytes.fromhex(self._test_node.validateaddress(self._address)['scriptPubKey']) - def _create_utxo(self, *, txid, vout, value, height): - return {"txid": txid, "vout": vout, "value": value, "height": height} + # When the pre-mined test framework chain is used, it contains coinbase + # outputs to the MiniWallet's default address in blocks 76-100 + # (see method BitcoinTestFramework._initialize_chain()) + # The MiniWallet needs to rescan_utxos() in order to account + # for those mature UTXOs, so that all txs spend confirmed coins + self.rescan_utxos() + + def _create_utxo(self, *, txid, vout, value, height, coinbase, confirmations): + return {"txid": txid, "vout": vout, "value": value, "height": height, "coinbase": coinbase, "confirmations": confirmations} def _bulk_tx(self, tx, target_weight): """Pad a transaction with extra outputs until it reaches a target weight (or higher). @@ -119,13 +126,25 @@ class MiniWallet: def get_balance(self): return sum(u['value'] for u in self._utxos) - def rescan_utxos(self): + def rescan_utxos(self, *, include_mempool=True): """Drop all utxos and rescan the utxo set""" self._utxos = [] res = self._test_node.scantxoutset(action="start", scanobjects=[self.get_descriptor()]) assert_equal(True, res['success']) for utxo in res['unspents']: - self._utxos.append(self._create_utxo(txid=utxo["txid"], vout=utxo["vout"], value=utxo["amount"], height=utxo["height"])) + self._utxos.append( + self._create_utxo(txid=utxo["txid"], + vout=utxo["vout"], + value=utxo["amount"], + height=utxo["height"], + coinbase=utxo["coinbase"], + confirmations=res["height"] - utxo["height"] + 1)) + if include_mempool: + mempool = self._test_node.getrawmempool(verbose=True) + # Sort tx by ancestor count. See BlockAssembler::SortForBlock in src/node/miner.cpp + sorted_mempool = sorted(mempool.items(), key=lambda item: (item[1]["ancestorcount"], int(item[0], 16))) + for txid, _ in sorted_mempool: + self.scan_tx(self._test_node.getrawtransaction(txid=txid, verbose=True)) def scan_tx(self, tx): """Scan the tx and adjust the internal list of owned utxos""" @@ -140,23 +159,35 @@ class MiniWallet: pass for out in tx['vout']: if out['scriptPubKey']['hex'] == self._scriptPubKey.hex(): - self._utxos.append(self._create_utxo(txid=tx["txid"], vout=out["n"], value=out["value"], height=0)) + self._utxos.append(self._create_utxo(txid=tx["txid"], vout=out["n"], value=out["value"], height=0, coinbase=False, confirmations=0)) + + def scan_txs(self, txs): + for tx in txs: + self.scan_tx(tx) def sign_tx(self, tx, fixed_length=True): - """Sign tx that has been created by MiniWallet in P2PK mode""" - assert_equal(self._mode, MiniWalletMode.RAW_P2PK) - (sighash, err) = LegacySignatureHash(CScript(self._scriptPubKey), tx, 0, SIGHASH_ALL) - assert err is None - # for exact fee calculation, create only signatures with fixed size by default (>49.89% probability): - # 65 bytes: high-R val (33 bytes) + low-S val (32 bytes) - # with the DER header/skeleton data of 6 bytes added, this leads to a target size of 71 bytes - der_sig = b'' - while not len(der_sig) == 71: - der_sig = self._priv_key.sign_ecdsa(sighash) - if not fixed_length: - break - tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))]) - tx.rehash() + if self._mode == MiniWalletMode.RAW_P2PK: + (sighash, err) = LegacySignatureHash(CScript(self._scriptPubKey), tx, 0, SIGHASH_ALL) + assert err is None + # for exact fee calculation, create only signatures with fixed size by default (>49.89% probability): + # 65 bytes: high-R val (33 bytes) + low-S val (32 bytes) + # with the DER header/skeleton data of 6 bytes added, this leads to a target size of 71 bytes + der_sig = b'' + while not len(der_sig) == 71: + der_sig = self._priv_key.sign_ecdsa(sighash) + if not fixed_length: + break + tx.vin[0].scriptSig = CScript([der_sig + bytes(bytearray([SIGHASH_ALL]))]) + tx.rehash() + elif self._mode == MiniWalletMode.RAW_OP_TRUE: + for i in tx.vin: + i.scriptSig = CScript([OP_NOP] * 43) # pad to identical size + elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE: + tx.wit.vtxinwit = [CTxInWitness()] * len(tx.vin) + for i in tx.wit.vtxinwit: + i.scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key] + else: + assert False def generate(self, num_blocks, **kwargs): """Generate blocks with coinbase outputs to the internal address, and call rescan_utxos""" @@ -201,9 +232,13 @@ class MiniWallet: else: return self._utxos[index] - def get_utxos(self, *, mark_as_spent=True): + def get_utxos(self, *, include_immature_coinbase=False, mark_as_spent=True): """Returns the list of all utxos and optionally mark them as spent""" - utxos = deepcopy(self._utxos) + if not include_immature_coinbase: + utxo_filter = filter(lambda utxo: not utxo['coinbase'] or COINBASE_MATURITY <= utxo['confirmations'], self._utxos) + else: + utxo_filter = self._utxos + utxos = deepcopy(list(utxo_filter)) if mark_as_spent: self._utxos = [] return utxos @@ -245,6 +280,7 @@ class MiniWallet: utxos_to_spend: Optional[List[dict]] = None, num_outputs=1, amount_per_output=0, + locktime=0, sequence=0, fee_per_output=1000, target_weight=0 @@ -257,27 +293,22 @@ class MiniWallet: utxos_to_spend = utxos_to_spend or [self.get_utxo()] sequence = [sequence] * len(utxos_to_spend) if type(sequence) is int else sequence assert_equal(len(utxos_to_spend), len(sequence)) - # create simple tx template (1 input, 1 output) - tx = self.create_self_transfer( - fee_rate=0, - utxo_to_spend=utxos_to_spend[0])["tx"] - - # duplicate inputs, witnesses and outputs - tx.vin = [deepcopy(tx.vin[0]) for _ in range(len(utxos_to_spend))] - for txin, seq in zip(tx.vin, sequence): - txin.nSequence = seq - tx.wit.vtxinwit = [deepcopy(tx.wit.vtxinwit[0]) for _ in range(len(utxos_to_spend))] - tx.vout = [deepcopy(tx.vout[0]) for _ in range(num_outputs)] - - # adapt input prevouts - for i, utxo in enumerate(utxos_to_spend): - tx.vin[i] = CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout'])) - - # adapt output amounts (use fixed fee per output) + + # calculate output amount inputs_value_total = sum([int(COIN * utxo['value']) for utxo in utxos_to_spend]) outputs_value_total = inputs_value_total - fee_per_output * num_outputs - for o in tx.vout: - o.nValue = amount_per_output or (outputs_value_total // num_outputs) + amount_per_output = amount_per_output or (outputs_value_total // num_outputs) + assert amount_per_output > 0 + outputs_value_total = amount_per_output * num_outputs + fee = Decimal(inputs_value_total - outputs_value_total) / COIN + + # create tx + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=seq) for utxo_to_spend, seq in zip(utxos_to_spend, sequence)] + tx.vout = [CTxOut(amount_per_output, bytearray(self._scriptPubKey)) for _ in range(num_outputs)] + tx.nLockTime = locktime + + self.sign_tx(tx) if target_weight: self._bulk_tx(tx, target_weight) @@ -289,8 +320,12 @@ class MiniWallet: vout=i, value=Decimal(tx.vout[i].nValue) / COIN, height=0, + coinbase=False, + confirmations=0, ) for i in range(len(tx.vout))], + "fee": fee, "txid": txid, + "wtxid": tx.getwtxid(), "hex": tx.serialize().hex(), "tx": tx, } @@ -300,6 +335,7 @@ class MiniWallet: utxo_to_spend = utxo_to_spend or self.get_utxo() assert fee_rate >= 0 assert fee >= 0 + # calculate fee if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE): vsize = Decimal(104) # anyone-can-spend elif self._mode == MiniWalletMode.RAW_P2PK: @@ -307,47 +343,45 @@ class MiniWallet: else: assert False send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000)) - assert send_value > 0 - - tx = CTransaction() - tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=sequence)] - tx.vout = [CTxOut(int(COIN * send_value), bytearray(self._scriptPubKey))] - tx.nLockTime = locktime - if self._mode == MiniWalletMode.RAW_P2PK: - self.sign_tx(tx) - elif self._mode == MiniWalletMode.RAW_OP_TRUE: - tx.vin[0].scriptSig = CScript([OP_NOP] * 43) # pad to identical size - elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE: - tx.wit.vtxinwit = [CTxInWitness()] - tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key] - else: - assert False - assert_equal(tx.get_vsize(), vsize) + # create tx + tx = self.create_self_transfer_multi(utxos_to_spend=[utxo_to_spend], locktime=locktime, sequence=sequence, amount_per_output=int(COIN * send_value), target_weight=target_weight) + if not target_weight: + assert_equal(tx["tx"].get_vsize(), vsize) + tx["new_utxo"] = tx.pop("new_utxos")[0] - if target_weight: - self._bulk_tx(tx, target_weight) - - tx_hex = tx.serialize().hex() - new_utxo = self._create_utxo(txid=tx.rehash(), vout=0, value=send_value, height=0) - - return {"txid": new_utxo["txid"], "wtxid": tx.getwtxid(), "hex": tx_hex, "tx": tx, "new_utxo": new_utxo} + return tx def sendrawtransaction(self, *, from_node, tx_hex, maxfeerate=0, **kwargs): txid = from_node.sendrawtransaction(hexstring=tx_hex, maxfeerate=maxfeerate, **kwargs) self.scan_tx(from_node.decoderawtransaction(tx_hex)) return txid - def send_self_transfer_chain(self, *, from_node, chain_length, utxo_to_spend=None): - """Create and send a "chain" of chain_length transactions. The nth transaction in + def create_self_transfer_chain(self, *, chain_length, utxo_to_spend=None): + """ + Create a "chain" of chain_length transactions. The nth transaction in the chain is a child of the n-1th transaction and parent of the n+1th transaction. - - Returns the chaintip (nth) utxo """ chaintip_utxo = utxo_to_spend or self.get_utxo() + chain = [] + for _ in range(chain_length): - chaintip_utxo = self.send_self_transfer(utxo_to_spend=chaintip_utxo, from_node=from_node)["new_utxo"] - return chaintip_utxo + tx = self.create_self_transfer(utxo_to_spend=chaintip_utxo) + chaintip_utxo = tx["new_utxo"] + chain.append(tx) + + return chain + + def send_self_transfer_chain(self, *, from_node, **kwargs): + """Create and send a "chain" of chain_length transactions. The nth transaction in + the chain is a child of the n-1th transaction and parent of the n+1th transaction. + + Returns a list of objects for each tx (see create_self_transfer_multi). + """ + chain = self.create_self_transfer_chain(**kwargs) + for t in chain: + self.sendrawtransaction(from_node=from_node, tx_hex=t["hex"]) + return chain def getnewdestination(address_type='bech32m'): @@ -388,56 +422,3 @@ def address_to_scriptpubkey(address): # TODO: also support other address formats else: assert False - - -def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, parent_locking_script=None, fee=DEFAULT_FEE): - """Build a transaction that spends parent_txid.vout[n] and produces one output with - amount = parent_value with a fee deducted. - Return tuple (CTransaction object, raw hex, nValue, scriptPubKey of the output created). - """ - inputs = [{"txid": parent_txid, "vout": n}] - my_value = parent_value - fee - outputs = {address : my_value} - rawtx = node.createrawtransaction(inputs, outputs) - prevtxs = [{ - "txid": parent_txid, - "vout": n, - "scriptPubKey": parent_locking_script, - "amount": parent_value, - }] if parent_locking_script else None - signedtx = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=privkeys, prevtxs=prevtxs) - assert signedtx["complete"] - tx = tx_from_hex(signedtx["hex"]) - return (tx, signedtx["hex"], my_value, tx.vout[0].scriptPubKey.hex()) - -def create_child_with_parents(node, address, privkeys, parents_tx, values, locking_scripts, fee=DEFAULT_FEE): - """Creates a transaction that spends the first output of each parent in parents_tx.""" - num_parents = len(parents_tx) - total_value = sum(values) - inputs = [{"txid": tx.rehash(), "vout": 0} for tx in parents_tx] - outputs = {address : total_value - fee} - rawtx_child = node.createrawtransaction(inputs, outputs) - prevtxs = [] - for i in range(num_parents): - prevtxs.append({"txid": parents_tx[i].rehash(), "vout": 0, "scriptPubKey": locking_scripts[i], "amount": values[i]}) - signedtx_child = node.signrawtransactionwithkey(hexstring=rawtx_child, privkeys=privkeys, prevtxs=prevtxs) - assert signedtx_child["complete"] - return signedtx_child["hex"] - -def create_raw_chain(node, first_coin, address, privkeys, chain_length=25): - """Helper function: create a "chain" of chain_length transactions. The nth transaction in the - chain is a child of the n-1th transaction and parent of the n+1th transaction. - """ - parent_locking_script = None - txid = first_coin["txid"] - chain_hex = [] - chain_txns = [] - value = first_coin["amount"] - - for _ in range(chain_length): - (tx, txhex, value, parent_locking_script) = make_chain(node, address, privkeys, txid, value, 0, parent_locking_script) - txid = tx.rehash() - chain_hex.append(txhex) - chain_txns.append(tx) - - return (chain_hex, chain_txns) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index e2c13a6705..569af0ee9b 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -27,6 +27,8 @@ import re import logging import unittest +os.environ["REQUIRE_WALLET_TYPE_SET"] = "1" + # Formatting. Default colors to empty strings. DEFAULT, BOLD, GREEN, RED = ("", ""), ("", ""), ("", ""), ("", "") try: @@ -83,61 +85,87 @@ EXTENDED_SCRIPTS = [ 'feature_pruning.py', 'feature_dbcrash.py', 'feature_index_prune.py', + 'wallet_pruning.py --legacy-wallet', ] BASE_SCRIPTS = [ # Scripts that are run by default. # Longest test should go first, to favor running tests in parallel - 'wallet_hd.py --legacy-wallet', - 'wallet_hd.py --descriptors', - 'wallet_backup.py --legacy-wallet', - 'wallet_backup.py --descriptors', # vv Tests less than 5m vv + 'feature_fee_estimation.py', + 'feature_taproot.py', + 'feature_block.py', + # vv Tests less than 2m vv 'mining_getblocktemplate_longpoll.py', + 'p2p_segwit.py', 'feature_maxuploadtarget.py', - 'feature_block.py', - 'rpc_fundrawtransaction.py --legacy-wallet', - 'rpc_fundrawtransaction.py --descriptors', - 'p2p_compactblocks.py', - 'p2p_compactblocks_blocksonly.py', + 'mempool_updatefromblock.py', + 'mempool_persist.py --descriptors', + # vv Tests less than 60s vv + 'rpc_psbt.py --legacy-wallet', + 'rpc_psbt.py --descriptors', + 'wallet_fundrawtransaction.py --legacy-wallet', + 'wallet_fundrawtransaction.py --descriptors', + 'wallet_bumpfee.py --legacy-wallet', + 'wallet_bumpfee.py --descriptors', + 'wallet_import_rescan.py --legacy-wallet', + 'wallet_backup.py --legacy-wallet', + 'wallet_backup.py --descriptors', 'feature_segwit.py --legacy-wallet', 'feature_segwit.py --descriptors', - # vv Tests less than 2m vv + 'p2p_tx_download.py', + 'wallet_avoidreuse.py --legacy-wallet', + 'wallet_avoidreuse.py --descriptors', + 'feature_abortnode.py', + 'wallet_address_types.py --legacy-wallet', + 'wallet_address_types.py --descriptors', 'wallet_basic.py --legacy-wallet', 'wallet_basic.py --descriptors', - 'wallet_labels.py --legacy-wallet', - 'wallet_labels.py --descriptors', - 'p2p_segwit.py', + 'feature_maxtipage.py', + 'wallet_multiwallet.py --legacy-wallet', + 'wallet_multiwallet.py --descriptors', + 'wallet_multiwallet.py --usecli', + 'p2p_dns_seeds.py', + 'wallet_groups.py --legacy-wallet', + 'wallet_groups.py --descriptors', + 'p2p_blockfilters.py', + 'feature_assumevalid.py', + 'wallet_taproot.py --descriptors', + 'feature_bip68_sequence.py', + 'rpc_packages.py', + 'rpc_bind.py --ipv4', + 'rpc_bind.py --ipv6', + 'rpc_bind.py --nonloopback', + 'p2p_headers_sync_with_minchainwork.py', + 'p2p_feefilter.py', + 'feature_csv_activation.py', + 'p2p_sendheaders.py', + 'wallet_listtransactions.py --legacy-wallet', + 'wallet_listtransactions.py --descriptors', + # vv Tests less than 30s vv + 'p2p_invalid_messages.py', + 'rpc_createmultisig.py', 'p2p_timeouts.py', - 'p2p_tx_download.py', - 'mempool_updatefromblock.py', 'wallet_dump.py --legacy-wallet', - 'feature_taproot.py', 'rpc_signer.py', 'wallet_signer.py --descriptors', - # vv Tests less than 60s vv - 'p2p_sendheaders.py', 'wallet_importmulti.py --legacy-wallet', 'mempool_limit.py', 'rpc_txoutproof.py', 'wallet_listreceivedby.py --legacy-wallet', 'wallet_listreceivedby.py --descriptors', 'wallet_abandonconflict.py --legacy-wallet', - 'p2p_dns_seeds.py', 'wallet_abandonconflict.py --descriptors', - 'feature_csv_activation.py', - 'wallet_address_types.py --legacy-wallet', - 'wallet_address_types.py --descriptors', - 'feature_bip68_sequence.py', - 'p2p_feefilter.py', - 'rpc_packages.py', 'feature_reindex.py', - 'feature_abortnode.py', - # vv Tests less than 30s vv + 'wallet_labels.py --legacy-wallet', + 'wallet_labels.py --descriptors', + 'p2p_compactblocks.py', + 'p2p_compactblocks_blocksonly.py', + 'wallet_hd.py --legacy-wallet', + 'wallet_hd.py --descriptors', 'wallet_keypool_topup.py --legacy-wallet', 'wallet_keypool_topup.py --descriptors', 'wallet_fast_rescan.py --descriptors', - 'feature_fee_estimation.py', 'interface_zmq.py', 'rpc_invalid_address_message.py', 'interface_bitcoin_cli.py --legacy-wallet', @@ -155,20 +183,12 @@ BASE_SCRIPTS = [ 'rpc_misc.py', 'interface_rest.py', 'mempool_spend_coinbase.py', - 'wallet_avoidreuse.py --legacy-wallet', - 'wallet_avoidreuse.py --descriptors', 'wallet_avoid_mixing_output_types.py --descriptors', 'mempool_reorg.py', - 'mempool_persist.py', 'p2p_block_sync.py', - 'wallet_multiwallet.py --legacy-wallet', - 'wallet_multiwallet.py --descriptors', - 'wallet_multiwallet.py --usecli', 'wallet_createwallet.py --legacy-wallet', 'wallet_createwallet.py --usecli', 'wallet_createwallet.py --descriptors', - 'wallet_listtransactions.py --legacy-wallet', - 'wallet_listtransactions.py --descriptors', 'wallet_watchonly.py --legacy-wallet', 'wallet_watchonly.py --usecli --legacy-wallet', 'wallet_reorgsrestore.py', @@ -178,8 +198,6 @@ BASE_SCRIPTS = [ 'interface_usdt_net.py', 'interface_usdt_utxocache.py', 'interface_usdt_validation.py', - 'rpc_psbt.py --legacy-wallet', - 'rpc_psbt.py --descriptors', 'rpc_users.py', 'rpc_whitelist.py', 'feature_proxy.py', @@ -187,13 +205,10 @@ BASE_SCRIPTS = [ 'wallet_signrawtransactionwithwallet.py --legacy-wallet', 'wallet_signrawtransactionwithwallet.py --descriptors', 'rpc_signrawtransactionwithkey.py', - 'p2p_headers_sync_with_minchainwork.py', 'rpc_rawtransaction.py --legacy-wallet', - 'wallet_groups.py --legacy-wallet', 'wallet_transactiontime_rescan.py --descriptors', 'wallet_transactiontime_rescan.py --legacy-wallet', 'p2p_addrv2_relay.py', - 'wallet_groups.py --descriptors', 'p2p_compactblocks_hb.py', 'p2p_disconnect_ban.py', 'rpc_decodescript.py', @@ -208,8 +223,7 @@ BASE_SCRIPTS = [ 'wallet_keypool.py --legacy-wallet', 'wallet_keypool.py --descriptors', 'wallet_descriptor.py --descriptors', - 'wallet_miniscript.py', - 'feature_maxtipage.py', + 'wallet_miniscript.py --descriptors', 'p2p_nobloomfilter_messages.py', 'p2p_filter.py', 'rpc_setban.py', @@ -217,15 +231,13 @@ BASE_SCRIPTS = [ 'mining_prioritisetransaction.py', 'p2p_invalid_locator.py', 'p2p_invalid_block.py', - 'p2p_invalid_messages.py', 'p2p_invalid_tx.py', - 'feature_assumevalid.py', 'example_test.py', 'wallet_txn_doublespend.py --legacy-wallet', - 'wallet_multisig_descriptor_psbt.py', + 'wallet_multisig_descriptor_psbt.py --descriptors', 'wallet_txn_doublespend.py --descriptors', - 'feature_backwards_compatibility.py --legacy-wallet', - 'feature_backwards_compatibility.py --descriptors', + 'wallet_backwards_compatibility.py --legacy-wallet', + 'wallet_backwards_compatibility.py --descriptors', 'wallet_txn_clone.py --mineblock', 'feature_notifications.py', 'rpc_getblockfilter.py', @@ -235,7 +247,6 @@ BASE_SCRIPTS = [ 'feature_rbf.py', 'mempool_packages.py', 'mempool_package_onemore.py', - 'rpc_createmultisig.py', 'mempool_package_limits.py', 'feature_versionbits_warning.py', 'rpc_preciousblock.py', @@ -252,18 +263,12 @@ BASE_SCRIPTS = [ 'feature_nulldummy.py', 'mempool_accept.py', 'mempool_expiry.py', - 'wallet_import_rescan.py --legacy-wallet', 'wallet_import_with_label.py --legacy-wallet', 'wallet_importdescriptors.py --descriptors', 'wallet_upgradewallet.py --legacy-wallet', - 'rpc_bind.py --ipv4', - 'rpc_bind.py --ipv6', - 'rpc_bind.py --nonloopback', 'wallet_crosschain.py', 'mining_basic.py', 'feature_signet.py', - 'wallet_bumpfee.py --legacy-wallet', - 'wallet_bumpfee.py --descriptors', 'wallet_implicitsegwit.py --legacy-wallet', 'rpc_named_arguments.py', 'feature_startupnotify.py', @@ -294,8 +299,7 @@ BASE_SCRIPTS = [ 'wallet_sendall.py --legacy-wallet', 'wallet_sendall.py --descriptors', 'wallet_create_tx.py --descriptors', - 'wallet_taproot.py', - 'wallet_inactive_hdchains.py', + 'wallet_inactive_hdchains.py --legacy-wallet', 'p2p_fingerprint.py', 'feature_uacomment.py', 'feature_init.py', @@ -307,7 +311,6 @@ BASE_SCRIPTS = [ 'p2p_add_connections.py', 'feature_bind_port_discover.py', 'p2p_unrequested_blocks.py', - 'p2p_blockfilters.py', 'p2p_message_capture.py', 'feature_includeconf.py', 'feature_addrman.py', @@ -315,9 +318,11 @@ BASE_SCRIPTS = [ 'mempool_unbroadcast.py', 'mempool_compatibility.py', 'mempool_accept_wtxid.py', + 'mempool_dust.py', 'rpc_deriveaddresses.py', 'rpc_deriveaddresses.py --usecli', 'p2p_ping.py', + 'p2p_tx_privacy.py', 'rpc_scanblocks.py', 'p2p_sendtxrcncl.py', 'rpc_scantxoutset.py', @@ -580,7 +585,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir] if BOLD[0]: combined_logs_args += ['--color'] - combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate() + combined_logs, _ = subprocess.Popen(combined_logs_args, text=True, stdout=subprocess.PIPE).communicate() print("\n".join(deque(combined_logs.splitlines(), combined_logs_len))) if failfast: @@ -665,7 +670,7 @@ class TestHandler: self.jobs.append((test, time.time(), subprocess.Popen([sys.executable, self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + portseed_arg + tmpdir_arg, - universal_newlines=True, + text=True, stdout=log_stdout, stderr=log_stderr), testdir, diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py index e6fc9072ab..1ad2a579bf 100755 --- a/test/functional/tool_signet_miner.py +++ b/test/functional/tool_signet_miner.py @@ -20,6 +20,9 @@ CHALLENGE_PRIVATE_KEY = (42).to_bytes(32, 'big') class SignetMinerTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.chain = "signet" self.setup_clean_chain = True diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index 1e5ce513cb..a888f93b03 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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-wallet.""" @@ -19,6 +19,9 @@ BUFFER_SIZE = 16 * 1024 class ToolWalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True @@ -34,7 +37,7 @@ class ToolWalletTest(BitcoinTestFramework): if not self.options.descriptors and 'create' in args: default_args.append('-legacy') - return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) def assert_raises_tool_error(self, error, *args): p = self.bitcoin_wallet_process(*args) diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index d7850b41ac..934f44588d 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -21,6 +21,9 @@ from test_framework.util import ( class AbandonConflictTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.extra_args = [["-minrelaytxfee=0.00001"], []] diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index 5b836f693f..ebeb5620e5 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-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. @@ -66,6 +66,9 @@ from test_framework.util import ( ) class AddressTypeTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 6 self.extra_args = [ diff --git a/test/functional/wallet_avoid_mixing_output_types.py b/test/functional/wallet_avoid_mixing_output_types.py index cad9d02808..861765f452 100755 --- a/test/functional/wallet_avoid_mixing_output_types.py +++ b/test/functional/wallet_avoid_mixing_output_types.py @@ -106,6 +106,9 @@ def generate_payment_values(n, m): class AddressInputTypeGrouping(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py index f663666f57..5601d81227 100755 --- a/test/functional/wallet_avoidreuse.py +++ b/test/functional/wallet_avoidreuse.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 avoid_reuse and setwalletflag features.""" @@ -63,6 +63,8 @@ def assert_balances(node, mine, margin=0.001): assert_approx(got[k], v, margin) class AvoidReuseTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) def set_test_params(self): self.num_nodes = 2 @@ -118,6 +120,8 @@ class AvoidReuseTest(BitcoinTestFramework): assert_raises_rpc_error(-8, "Wallet flag is already set to false", self.nodes[0].setwalletflag, 'avoid_reuse', False) assert_raises_rpc_error(-8, "Wallet flag is already set to true", self.nodes[1].setwalletflag, 'avoid_reuse', True) + assert_raises_rpc_error(-8, "Unknown wallet flag: abc", self.nodes[0].setwalletflag, 'abc', True) + # Create a wallet with avoid reuse, and test that disabling it afterwards persists self.nodes[1].createwallet(wallet_name="avoid_reuse_persist", avoid_reuse=True) w = self.nodes[1].get_wallet_rpc("avoid_reuse_persist") @@ -191,7 +195,7 @@ class AvoidReuseTest(BitcoinTestFramework): # getbalances should show no used, 10 btc trusted assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10}) # node 0 should not show a used entry, as it does not enable avoid_reuse - assert("used" not in self.nodes[0].getbalances()["mine"]) + assert "used" not in self.nodes[0].getbalances()["mine"] self.nodes[1].sendtoaddress(retaddr, 5) self.generate(self.nodes[0], 1) diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index 292fe3a310..4ad25d964e 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -44,6 +44,9 @@ from test_framework.util import ( class WalletBackupTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py index 59a12193fd..f55a3758ce 100755 --- a/test/functional/feature_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Backwards compatibility functional test @@ -7,10 +7,6 @@ Test various backwards compatibility scenarios. Requires previous releases binaries, see test/README.md. -v0.15.2 is not required by this test, but it is used in wallet_upgradewallet.py. -Due to a hardfork in regtest, it can't be used to sync nodes. - - Due to RPC changes introduced in various versions the below tests won't work for older versions without some patches or workarounds. @@ -32,6 +28,9 @@ from test_framework.util import ( class BackwardsCompatibilityTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 10 @@ -194,18 +193,18 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): assert_equal(txs[1]["txid"], tx1_id) assert_equal(txs[2]["walletconflicts"], [tx1_id]) assert_equal(txs[1]["replaced_by_txid"], tx2_id) - assert not(txs[1]["abandoned"]) + assert not txs[1]["abandoned"] assert_equal(txs[1]["confirmations"], -1) assert_equal(txs[2]["blockindex"], 1) assert txs[3]["abandoned"] assert_equal(txs[4]["walletconflicts"], [tx3_id]) assert_equal(txs[3]["replaced_by_txid"], tx4_id) - assert not(hasattr(txs[3], "blockindex")) + assert not hasattr(txs[3], "blockindex") elif wallet_name == "w2": - assert(info['private_keys_enabled'] == False) + assert info['private_keys_enabled'] == False assert info['keypoolsize'] == 0 else: - assert(info['private_keys_enabled'] == True) + assert info['private_keys_enabled'] == True assert info['keypoolsize'] == 0 else: for node in legacy_nodes: @@ -271,6 +270,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): assert_equal(info["desc"], descsum_create(descriptor)) # Now copy that same wallet back to 0.16 to make sure no automatic upgrade breaks it + node_master.unloadwallet("u1_v16") os.remove(os.path.join(node_v16_wallets_dir, "wallets/u1_v16")) shutil.copyfile( os.path.join(node_master_wallets_dir, "u1_v16"), diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index 60da22ca26..9ed2caefb7 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 balance RPC methods.""" @@ -46,6 +46,9 @@ def create_transactions(node, address, amt, fees): return txs class WalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 20c577ceb3..52022a2eee 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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 @@ OUT_OF_RANGE = "Amount out of range" class WalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 4 self.extra_args = [[ @@ -728,6 +731,45 @@ class WalletTest(BitcoinTestFramework): assert_equal(coin_b["parent_descs"][0], multi_b) self.nodes[0].unloadwallet("wo") + self.log.info("Test -spendzeroconfchange") + self.restart_node(0, ["-spendzeroconfchange=0"]) + + # create new wallet and fund it with a confirmed UTXO + self.nodes[0].createwallet(wallet_name="zeroconf", load_on_startup=True) + zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf") + default_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name) + default_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('1.0')) + self.generate(self.nodes[0], 1, sync_fun=self.no_op) + utxos = zeroconf_wallet.listunspent(minconf=0) + assert_equal(len(utxos), 1) + assert_equal(utxos[0]['confirmations'], 1) + + # spend confirmed UTXO to ourselves + zeroconf_wallet.sendall(recipients=[zeroconf_wallet.getnewaddress()]) + utxos = zeroconf_wallet.listunspent(minconf=0) + assert_equal(len(utxos), 1) + assert_equal(utxos[0]['confirmations'], 0) + # accounts for untrusted pending balance + bal = zeroconf_wallet.getbalances() + assert_equal(bal['mine']['trusted'], 0) + assert_equal(bal['mine']['untrusted_pending'], utxos[0]['amount']) + + # spending an unconfirmed UTXO sent to ourselves should fail + assert_raises_rpc_error(-6, "Insufficient funds", zeroconf_wallet.sendtoaddress, zeroconf_wallet.getnewaddress(), Decimal('0.5')) + + # check that it works again with -spendzeroconfchange set (=default) + self.restart_node(0, ["-spendzeroconfchange=1"]) + zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf") + utxos = zeroconf_wallet.listunspent(minconf=0) + assert_equal(len(utxos), 1) + assert_equal(utxos[0]['confirmations'], 0) + # accounts for trusted balance + bal = zeroconf_wallet.getbalances() + assert_equal(bal['mine']['trusted'], utxos[0]['amount']) + assert_equal(bal['mine']['untrusted_pending'], 0) + + zeroconf_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('0.5')) + if __name__ == '__main__': WalletTest().main() diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 2ee3e00a7b..a2ae997ecb 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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. @@ -17,10 +17,6 @@ from decimal import Decimal from test_framework.blocktools import ( COINBASE_MATURITY, - add_witness_commitment, - create_block, - create_coinbase, - send_to_witness, ) from test_framework.messages import ( MAX_BIP125_RBF_SEQUENCE, @@ -46,6 +42,9 @@ TOO_HIGH = 100000 class BumpFeeTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True @@ -89,6 +88,7 @@ class BumpFeeTest(BitcoinTestFramework): test_nonrbf_bumpfee_fails(self, peer_node, dest_address) test_notmine_bumpfee(self, rbf_node, peer_node, dest_address) test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address) + test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address) test_dust_to_fee(self, rbf_node, dest_address) test_watchonly_psbt(self, peer_node, rbf_node, dest_address) test_rebumping(self, rbf_node, dest_address) @@ -200,16 +200,8 @@ def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address): # Create a transaction with segwit output, then create an RBF transaction # which spends it, and make sure bumpfee can be called on it. - segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001")) - segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress(address_type='bech32')) - segwitid = send_to_witness( - use_p2wsh=False, - node=rbf_node, - utxo=segwit_in, - pubkey=segwit_out["pubkey"], - encode_p2sh=False, - amount=Decimal("0.0009"), - sign=True) + segwit_out = rbf_node.getnewaddress(address_type='bech32') + segwitid = rbf_node.send({segwit_out: "0.0009"}, options={"change_position": 1})["txid"] rbfraw = rbf_node.createrawtransaction([{ 'txid': segwitid, @@ -295,6 +287,35 @@ def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_ad self.clear_mempool() +def test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address): + self.log.info('Test that fee can be bumped when it has abandoned descendant') + # parent is send-to-self, so we don't have to check which output is change when creating the child tx + parent_id = spend_one_input(rbf_node, rbf_node_address) + # Submit child transaction with low fee + child_id = rbf_node.send(outputs={dest_address: 0.00020000}, + options={"inputs": [{"txid": parent_id, "vout": 0}], "fee_rate": 2})["txid"] + assert child_id in rbf_node.getrawmempool() + + # Restart the node with higher min relay fee so the descendant tx is no longer in mempool so that we can abandon it + self.restart_node(1, ['-minrelaytxfee=0.00005'] + self.extra_args[1]) + rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) + self.connect_nodes(1, 0) + assert parent_id in rbf_node.getrawmempool() + assert child_id not in rbf_node.getrawmempool() + # Should still raise an error even if not in mempool + assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) + # Now abandon the child transaction and bump the original + rbf_node.abandontransaction(child_id) + bumped_result = rbf_node.bumpfee(parent_id, {"fee_rate": HIGH}) + assert bumped_result['txid'] in rbf_node.getrawmempool() + assert parent_id not in rbf_node.getrawmempool() + # Cleanup + self.restart_node(1, self.extra_args[1]) + rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) + self.connect_nodes(1, 0) + self.clear_mempool() + + def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): self.log.info('Testing small output with feerate bump succeeds') @@ -541,10 +562,10 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): # then invalidate the block so the rbf tx will be put back in the mempool. # This makes it possible to check whether the rbf tx outputs are # spendable before the rbf tx is confirmed. - block = submit_block_with_tx(rbf_node, rbftx) + block = self.generateblock(rbf_node, output="raw(51)", transactions=[rbftx]) # Can not abandon conflicted tx assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid)) - rbf_node.invalidateblock(block.hash) + rbf_node.invalidateblock(block["hash"]) # Call abandon to make sure the wallet doesn't attempt to resubmit # the bump tx and hope the wallet does not rebroadcast before we call. rbf_node.abandontransaction(bumpid) @@ -566,7 +587,7 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): def test_bumpfee_metadata(self, rbf_node, dest_address): self.log.info('Test that bumped txn metadata persists to new txn record') - assert(rbf_node.getbalance() < 49) + assert rbf_node.getbalance() < 49 self.generatetoaddress(rbf_node, 101, rbf_node.getnewaddress()) rbfid = rbf_node.sendtoaddress(dest_address, 49, "comment value", "to value") bumped_tx = rbf_node.bumpfee(rbfid) @@ -619,17 +640,6 @@ def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")): return txid -def submit_block_with_tx(node, tx): - tip = node.getbestblockhash() - height = node.getblockcount() + 1 - block_time = node.getblockheader(tip)["mediantime"] + 1 - block = create_block(int(tip, 16), create_coinbase(height), block_time, txlist=[tx]) - add_witness_commitment(block) - block.solve() - node.submitblock(block.serialize().hex()) - return block - - def test_no_more_inputs_fails(self, rbf_node, dest_address): self.log.info('Test that bumpfee fails when there are no available confirmed outputs') # feerate rbf requires confirmed outputs when change output doesn't exist or is insufficient diff --git a/test/functional/wallet_coinbase_category.py b/test/functional/wallet_coinbase_category.py index c2a8e612cf..c2cb0bf3b0 100755 --- a/test/functional/wallet_coinbase_category.py +++ b/test/functional/wallet_coinbase_category.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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 coinbase transactions return the correct categories. @@ -13,6 +13,9 @@ from test_framework.util import ( ) class CoinbaseCategoryTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py index a213a261ef..2d9bb38fcc 100755 --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,6 +14,9 @@ from test_framework.blocktools import ( class CreateTxWalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index 12480d4d1e..22c491441b 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 createwallet arguments. @@ -16,6 +16,9 @@ from test_framework.util import ( from test_framework.wallet_util import bytes_to_wif, generate_wif_key class CreateWalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 diff --git a/test/functional/wallet_crosschain.py b/test/functional/wallet_crosschain.py index c0047542ed..6f93ad4e3b 100755 --- a/test/functional/wallet_crosschain.py +++ b/test/functional/wallet_crosschain.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 The Bitcoin Core developers +# Copyright (c) 2020-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_raises_rpc_error class WalletCrossChain(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True @@ -33,20 +36,28 @@ class WalletCrossChain(BitcoinTestFramework): self.log.info("Creating wallets") node0_wallet = os.path.join(self.nodes[0].datadir, 'node0_wallet') + node0_wallet_backup = os.path.join(self.nodes[0].datadir, 'node0_wallet.bak') self.nodes[0].createwallet(node0_wallet) + self.nodes[0].backupwallet(node0_wallet_backup) self.nodes[0].unloadwallet(node0_wallet) node1_wallet = os.path.join(self.nodes[1].datadir, 'node1_wallet') + node1_wallet_backup = os.path.join(self.nodes[0].datadir, 'node1_wallet.bak') self.nodes[1].createwallet(node1_wallet) + self.nodes[1].backupwallet(node1_wallet_backup) self.nodes[1].unloadwallet(node1_wallet) - self.log.info("Loading wallets into nodes with a different genesis blocks") + self.log.info("Loading/restoring wallets into nodes with a different genesis block") if self.options.descriptors: assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].loadwallet, node1_wallet) assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].loadwallet, node0_wallet) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].restorewallet, 'w', node1_wallet_backup) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].restorewallet, 'w', node0_wallet_backup) else: assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].loadwallet, node1_wallet) assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].loadwallet, node0_wallet) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].restorewallet, 'w', node1_wallet_backup) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].restorewallet, 'w', node0_wallet_backup) if not self.options.descriptors: self.log.info("Override cross-chain wallet load protection") diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index e7cfa56c46..b0e93df36a 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -1,8 +1,14 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 descriptor wallet function.""" +import os + +try: + import sqlite3 +except ImportError: + pass from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework @@ -13,6 +19,9 @@ from test_framework.util import ( class WalletDescriptorTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -22,6 +31,7 @@ class WalletDescriptorTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() self.skip_if_no_sqlite() + self.skip_if_no_py_sqlite3() def run_test(self): if self.is_bdb_compiled(): @@ -104,7 +114,7 @@ class WalletDescriptorTest(BitcoinTestFramework): # Make sure things are disabled self.log.info("Test disabled RPCs") assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importprivkey, "cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW") - assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importpubkey, send_wrpc.getaddressinfo(send_wrpc.getnewaddress())) + assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importpubkey, send_wrpc.getaddressinfo(send_wrpc.getnewaddress())["pubkey"]) assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importaddress, recv_wrpc.getnewaddress()) assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importmulti, []) assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.addmultisigaddress, 1, [recv_wrpc.getnewaddress()]) @@ -221,5 +231,15 @@ class WalletDescriptorTest(BitcoinTestFramework): imp_addr = imp_rpc.getnewaddress(address_type=addr_type) assert_equal(exp_addr, imp_addr) + self.log.info("Test that loading descriptor wallet containing legacy key types throws error") + self.nodes[0].createwallet(wallet_name="crashme", descriptors=True) + self.nodes[0].unloadwallet("crashme") + wallet_db = os.path.join(self.nodes[0].datadir, self.chain, "wallets", "crashme", self.wallet_data_filename) + with sqlite3.connect(wallet_db) as conn: + # add "cscript" entry: key type is uint160 (20 bytes), value type is CScript (zero-length here) + conn.execute('INSERT INTO main VALUES(?, ?)', (b'\x07cscript' + b'\x00'*20, b'\x00')) + assert_raises_rpc_error(-4, "Unexpected legacy entry in descriptor wallet found.", self.nodes[0].loadwallet, "crashme") + + if __name__ == '__main__': WalletDescriptorTest().main () diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py index 74cddf2738..9c73f7dead 100755 --- a/test/functional/wallet_disable.py +++ b/test/functional/wallet_disable.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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. diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 9f0d666270..cf20ff1239 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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.""" @@ -93,6 +93,9 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): class WalletDumpTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.num_nodes = 1 self.extra_args = [["-keypool=90", "-addresstype=legacy"]] diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index 37c1c4bff3..885c52cf2e 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2020 The Bitcoin Core developers +# Copyright (c) 2016-2022 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""" @@ -14,6 +14,9 @@ from test_framework.util import ( class WalletEncryptionTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py index acd92097ff..f0740b72fd 100755 --- a/test/functional/wallet_fallbackfee.py +++ b/test/functional/wallet_fallbackfee.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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.""" @@ -9,6 +9,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_raises_rpc_error class WalletRBFTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py index 3b8ae8eb92..1ab24f1a96 100755 --- a/test/functional/wallet_fast_rescan.py +++ b/test/functional/wallet_fast_rescan.py @@ -21,6 +21,9 @@ NUM_BLOCKS = 6 # number of blocks to mine class WalletFastRescanTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 1 self.extra_args = [[f'-keypool={KEYPOOL_SIZE}', '-blockfilterindex=1']] @@ -37,7 +40,6 @@ class WalletFastRescanTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] wallet = MiniWallet(node) - wallet.rescan_utxos() self.log.info("Create descriptor wallet with backup") WALLET_BACKUP_FILENAME = os.path.join(node.datadir, 'wallet.bak') diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index 1152995ac9..29ddb77b41 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -27,6 +27,8 @@ from test_framework.util import ( ) from test_framework.wallet_util import bytes_to_wif +ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \ + "Please allow other inputs to be automatically selected or include more coins manually" def get_unspent(listunspent, amount): for utx in listunspent: @@ -35,6 +37,9 @@ def get_unspent(listunspent, amount): raise AssertionError('Could not find unspent with amount={}'.format(amount)) class RawTransactionsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True @@ -107,6 +112,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.generate(self.nodes[0], 121) self.test_add_inputs_default_value() + self.test_preset_inputs_selection() self.test_weight_calculation() self.test_change_position() self.test_simple() @@ -142,6 +148,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.test_external_inputs() self.test_22670() self.test_feerate_rounding() + self.test_input_confs_control() def test_change_position(self): """Ensure setting changePosition in fundraw with an exact match is handled properly.""" @@ -324,7 +331,7 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) # Should fail without add_inputs: - assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) # add_inputs is enabled by default rawtxfund = self.nodes[2].fundrawtransaction(rawtx) @@ -356,7 +363,7 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) # Should fail without add_inputs: - assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True}) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) @@ -390,7 +397,7 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) # Should fail without add_inputs: - assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True}) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) @@ -979,11 +986,15 @@ class RawTransactionsTest(BitcoinTestFramework): # are selected, the transaction will end up being too large, so it # shouldn't use BnB and instead fall back to Knapsack but that behavior # is not implemented yet. For now we just check that we get an error. + # First, force the wallet to bulk-generate the addresses we'll need. + recipient.keypoolrefill(1500) for _ in range(1500): outputs[recipient.getnewaddress()] = 0.1 wallet.sendmany("", outputs) self.generate(self.nodes[0], 10) - assert_raises_rpc_error(-4, "Transaction too large", recipient.fundrawtransaction, rawtx) + assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight. " + "Please try sending a smaller amount or manually consolidating your wallet's UTXOs", + recipient.fundrawtransaction, rawtx) self.nodes[0].unloadwallet("large") def test_external_inputs(self): @@ -1124,7 +1135,7 @@ class RawTransactionsTest(BitcoinTestFramework): } ] } - assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{addr1: 8}], options=options) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 8}], options=options) # Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount) options["add_inputs"] = True @@ -1152,7 +1163,7 @@ class RawTransactionsTest(BitcoinTestFramework): # 6. Explicit add_inputs=false, no preset inputs: options = {"add_inputs": False} - assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{addr1: 3}], options=options) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 3}], options=options) ################################################ @@ -1169,7 +1180,7 @@ class RawTransactionsTest(BitcoinTestFramework): "vout": 1 # change position was hardcoded to index 0 }] outputs = {self.nodes[1].getnewaddress(): 8} - assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, inputs=inputs, outputs=outputs) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=inputs, outputs=outputs) # Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount) options["add_inputs"] = True @@ -1196,10 +1207,54 @@ class RawTransactionsTest(BitcoinTestFramework): # Case (6). Explicit add_inputs=false, no preset inputs: options = {"add_inputs": False} - assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, options=options) + assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, options=options) self.nodes[2].unloadwallet("test_preset_inputs") + def test_preset_inputs_selection(self): + self.log.info('Test wallet preset inputs are not double-counted or reused in coin selection') + + # Create and fund the wallet with 4 UTXO of 5 BTC each (20 BTC total) + self.nodes[2].createwallet("test_preset_inputs_selection") + wallet = self.nodes[2].get_wallet_rpc("test_preset_inputs_selection") + outputs = {} + for _ in range(4): + outputs[wallet.getnewaddress(address_type="bech32")] = 5 + self.nodes[0].sendmany("", outputs) + self.generate(self.nodes[0], 1) + + # Select the preset inputs + coins = wallet.listunspent() + preset_inputs = [coins[0], coins[1], coins[2]] + + # Now let's create the tx creation options + options = { + "inputs": preset_inputs, + "add_inputs": True, # automatically add coins from the wallet to fulfill the target + "subtract_fee_from_outputs": [0], # deduct fee from first output + "add_to_wallet": False + } + + # Attempt to send 29 BTC from a wallet that only has 20 BTC. The wallet should exclude + # the preset inputs from the pool of available coins, realize that there is not enough + # money to fund the 29 BTC payment, and fail with "Insufficient funds". + # + # Even with SFFO, the wallet can only afford to send 20 BTC. + # If the wallet does not properly exclude preset inputs from the pool of available coins + # prior to coin selection, it may create a transaction that does not fund the full payment + # amount or, through SFFO, incorrectly reduce the recipient's amount by the difference + # between the original target and the wrongly counted inputs (in this case 9 BTC) + # so that the recipient's amount is no longer equal to the user's selected target of 29 BTC. + + # First case, use 'subtract_fee_from_outputs = true' + assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options) + + # Second case, don't use 'subtract_fee_from_outputs' + del options["subtract_fee_from_outputs"] + assert_raises_rpc_error(-4, "Insufficient funds", wallet.send, outputs=[{wallet.getnewaddress(address_type="bech32"): 29}], options=options) + + self.nodes[2].unloadwallet("test_preset_inputs_selection") + def test_weight_calculation(self): self.log.info("Test weight calculation with external inputs") @@ -1349,6 +1404,66 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}]) assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, {"fee_rate": 1.85}) + def test_input_confs_control(self): + self.nodes[0].createwallet("minconf") + wallet = self.nodes[0].get_wallet_rpc("minconf") + + # Fund the wallet with different chain heights + for _ in range(2): + self.nodes[2].sendmany("", {wallet.getnewaddress():1, wallet.getnewaddress():1}) + self.generate(self.nodes[2], 1) + + unconfirmed_txid = wallet.sendtoaddress(wallet.getnewaddress(), 0.5) + + self.log.info("Crafting TX using an unconfirmed input") + target_address = self.nodes[2].getnewaddress() + raw_tx1 = wallet.createrawtransaction([], {target_address: 0.1}, 0, True) + funded_tx1 = wallet.fundrawtransaction(raw_tx1, {'fee_rate': 1, 'maxconf': 0})['hex'] + + # Make sure we only had the one input + tx1_inputs = self.nodes[0].decoderawtransaction(funded_tx1)['vin'] + assert_equal(len(tx1_inputs), 1) + + utxo1 = tx1_inputs[0] + assert unconfirmed_txid == utxo1['txid'] + + final_tx1 = wallet.signrawtransactionwithwallet(funded_tx1)['hex'] + txid1 = self.nodes[0].sendrawtransaction(final_tx1) + + mempool = self.nodes[0].getrawmempool() + assert txid1 in mempool + + self.log.info("Fail to craft a new TX with minconf above highest one") + # Create a replacement tx to 'final_tx1' that has 1 BTC target instead of 0.1. + raw_tx2 = wallet.createrawtransaction([{'txid': utxo1['txid'], 'vout': utxo1['vout']}], {target_address: 1}) + assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, raw_tx2, {'add_inputs': True, 'minconf': 3, 'fee_rate': 10}) + + self.log.info("Fail to broadcast a new TX with maxconf 0 due to BIP125 rules to verify it actually chose unconfirmed outputs") + # Now fund 'raw_tx2' to fulfill the total target (1 BTC) by using all the wallet unconfirmed outputs. + # As it was created with the first unconfirmed output, 'raw_tx2' only has 0.1 BTC covered (need to fund 0.9 BTC more). + # So, the selection process, to cover the amount, will pick up the 'final_tx1' output as well, which is an output of the tx that this + # new tx is replacing!. So, once we send it to the mempool, it will return a "bad-txns-spends-conflicting-tx" + # because the input will no longer exist once the first tx gets replaced by this new one). + funded_invalid = wallet.fundrawtransaction(raw_tx2, {'add_inputs': True, 'maxconf': 0, 'fee_rate': 10})['hex'] + final_invalid = wallet.signrawtransactionwithwallet(funded_invalid)['hex'] + assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, final_invalid) + + self.log.info("Craft a replacement adding inputs with highest depth possible") + funded_tx2 = wallet.fundrawtransaction(raw_tx2, {'add_inputs': True, 'minconf': 2, 'fee_rate': 10})['hex'] + tx2_inputs = self.nodes[0].decoderawtransaction(funded_tx2)['vin'] + assert_greater_than_or_equal(len(tx2_inputs), 2) + for vin in tx2_inputs: + if vin['txid'] != unconfirmed_txid: + assert_greater_than_or_equal(self.nodes[0].gettxout(vin['txid'], vin['vout'])['confirmations'], 2) + + final_tx2 = wallet.signrawtransactionwithwallet(funded_tx2)['hex'] + txid2 = self.nodes[0].sendrawtransaction(final_tx2) + + mempool = self.nodes[0].getrawmempool() + assert txid1 not in mempool + assert txid2 in mempool + + wallet.unloadwallet() if __name__ == '__main__': RawTransactionsTest().main() diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index e5e4cf03bf..83c1826a41 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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.""" @@ -16,6 +16,9 @@ from test_framework.util import ( class WalletGroupTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 5 diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 220c856498..0f79df6e5d 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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.""" @@ -16,6 +16,9 @@ from test_framework.util import ( class WalletHDTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/wallet_implicitsegwit.py b/test/functional/wallet_implicitsegwit.py index a8583e2879..baa9bafb00 100755 --- a/test/functional/wallet_implicitsegwit.py +++ b/test/functional/wallet_implicitsegwit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 implicit segwit feature.""" @@ -36,9 +36,12 @@ def check_implicit_transactions(implicit_keys, implicit_node): pubkey = implicit_keys[a] for b in address_types: b_address = key_to_address(pubkey, b) - assert(('receive', b_address) in tuple((tx['category'], tx['address']) for tx in txs)) + assert ('receive', b_address) in tuple((tx['category'], tx['address']) for tx in txs) class ImplicitSegwitTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.num_nodes = 2 self.supports_cli = False diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 085ad51c79..211e939a39 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -147,6 +147,9 @@ def get_rand_amount(): class ImportRescanTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.num_nodes = 2 + len(IMPORT_NODES) self.supports_cli = False @@ -176,7 +179,16 @@ class ImportRescanTest(BitcoinTestFramework): # Create one transaction on node 0 with a unique amount for # each possible type of wallet import RPC. + last_variants = [] for i, variant in enumerate(IMPORT_VARIANTS): + if i % 10 == 0: + blockhash = self.generate(self.nodes[0], 1)[0] + conf_height = self.nodes[0].getblockcount() + timestamp = self.nodes[0].getblockheader(blockhash)["time"] + for var in last_variants: + var.confirmation_height = conf_height + var.timestamp = timestamp + last_variants.clear() variant.label = "label {} {}".format(i, variant) variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress( label=variant.label, @@ -185,9 +197,15 @@ class ImportRescanTest(BitcoinTestFramework): variant.key = self.nodes[1].dumpprivkey(variant.address["address"]) variant.initial_amount = get_rand_amount() variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount) - self.generate(self.nodes[0], 1) # Generate one block for each send - variant.confirmation_height = self.nodes[0].getblockcount() - variant.timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] + last_variants.append(variant) + + blockhash = self.generate(self.nodes[0], 1)[0] + conf_height = self.nodes[0].getblockcount() + timestamp = self.nodes[0].getblockheader(blockhash)["time"] + for var in last_variants: + var.confirmation_height = conf_height + var.timestamp = timestamp + last_variants.clear() # Generate a block further in the future (past the rescan window). assert_equal(self.nodes[0].getrawmempool(), []) @@ -214,11 +232,14 @@ class ImportRescanTest(BitcoinTestFramework): variant.check() # Create new transactions sending to each address. - for variant in IMPORT_VARIANTS: + for i, variant in enumerate(IMPORT_VARIANTS): + if i % 10 == 0: + blockhash = self.generate(self.nodes[0], 1)[0] + conf_height = self.nodes[0].getblockcount() + 1 variant.sent_amount = get_rand_amount() variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount) - self.generate(self.nodes[0], 1) # Generate one block for each send - variant.confirmation_height = self.nodes[0].getblockcount() + variant.confirmation_height = conf_height + self.generate(self.nodes[0], 1) assert_equal(self.nodes[0].getrawmempool(), []) self.sync_all() diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py index 6a9d2e8290..0a1fc31ebc 100755 --- a/test/functional/wallet_import_with_label.py +++ b/test/functional/wallet_import_with_label.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2020 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 behavior of RPC importprivkey on set and unset labels of @@ -15,6 +15,9 @@ from test_framework.wallet_util import test_address class ImportWithLabel(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py index 9744009af8..ca0209b61d 100755 --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 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 importdescriptors RPC. @@ -15,7 +15,6 @@ variants. - `test_address()` is called to call getaddressinfo for an address on node1 and test the values returned.""" -from test_framework.address import key_to_p2pkh from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.descriptors import descsum_create @@ -30,6 +29,9 @@ from test_framework.wallet_util import ( ) class ImportDescriptorsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 2 self.extra_args = [["-addresstype=legacy"], @@ -117,12 +119,11 @@ class ImportDescriptorsTest(BitcoinTestFramework): self.log.info("Internal addresses should be detected as such") key = get_generate_key() - addr = key_to_p2pkh(key.pubkey) self.test_importdesc({"desc": descsum_create("pkh(" + key.pubkey + ")"), "timestamp": "now", "internal": True}, success=True) - info = w1.getaddressinfo(addr) + info = w1.getaddressinfo(key.p2pkh_addr) assert_equal(info["ismine"], True) assert_equal(info["ischange"], True) @@ -484,8 +485,8 @@ class ImportDescriptorsTest(BitcoinTestFramework): assert_equal(addr, 'bcrt1qp8s25ckjl7gr6x2q3dx3tn2pytwp05upkjztk6ey857tt50r5aeqn6mvr9') # Derived at m/84'/0'/0'/1 change_addr = wmulti_pub.getrawchangeaddress('bech32') assert_equal(change_addr, 'bcrt1qzxl0qz2t88kljdnkzg4n4gapr6kte26390gttrg79x66nt4p04fssj53nl') - assert(send_txid in self.nodes[0].getrawmempool(True)) - assert(send_txid in (x['txid'] for x in wmulti_pub.listunspent(0))) + assert send_txid in self.nodes[0].getrawmempool(True) + assert send_txid in (x['txid'] for x in wmulti_pub.listunspent(0)) assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999) # generate some utxos for next tests diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 62a1a3341d..31013f6323 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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. @@ -35,6 +35,9 @@ from test_framework.wallet_util import ( class ImportMultiTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.num_nodes = 2 self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"]] diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py index 2a4d0981c7..77b407579f 100755 --- a/test/functional/wallet_importprunedfunds.py +++ b/test/functional/wallet_importprunedfunds.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -21,6 +21,9 @@ from test_framework.wallet_util import bytes_to_wif class ImportPrunedFundsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/wallet_inactive_hdchains.py b/test/functional/wallet_inactive_hdchains.py index e1dad00876..c0b3fea1c0 100755 --- a/test/functional/wallet_inactive_hdchains.py +++ b/test/functional/wallet_inactive_hdchains.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ @@ -17,6 +17,9 @@ from test_framework.wallet_util import ( class InactiveHDChainsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index 54c47511a9..bd97851153 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -11,6 +11,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error class KeyPoolTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 @@ -201,6 +204,9 @@ class KeyPoolTest(BitcoinTestFramework): res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010, "changeAddress": addr.pop()}) assert_equal("psbt" in res, True) + if not self.options.descriptors: + msg = "Error: Private keys are disabled for this wallet" + assert_raises_rpc_error(-4, msg, w2.keypoolrefill, 100) if __name__ == '__main__': KeyPoolTest().main() diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index 4c965b7160..18c3ae1f7c 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-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. @@ -21,6 +21,9 @@ from test_framework.util import ( class KeypoolRestoreTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 4 diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py index c29b02e661..a39700f73a 100755 --- a/test/functional/wallet_labels.py +++ b/test/functional/wallet_labels.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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. @@ -18,13 +18,54 @@ from test_framework.wallet_util import test_address class WalletLabelsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 1 + self.num_nodes = 2 def skip_test_if_missing_module(self): self.skip_if_no_wallet() + def invalid_label_name_test(self): + node = self.nodes[0] + address = node.getnewaddress() + pubkey = node.getaddressinfo(address)['pubkey'] + rpc_calls = [ + [node.getnewaddress], + [node.setlabel, address], + [node.getaddressesbylabel], + [node.importpubkey, pubkey], + [node.addmultisigaddress, 1, [pubkey]], + [node.getreceivedbylabel], + [node.listsinceblock, node.getblockhash(0), 1, False, True, False], + ] + if self.options.descriptors: + response = node.importdescriptors([{ + 'desc': f'pkh({pubkey})', + 'label': '*', + 'timestamp': 'now', + }]) + else: + rpc_calls.extend([ + [node.importprivkey, node.dumpprivkey(address)], + [node.importaddress, address], + ]) + + response = node.importmulti([{ + 'scriptPubKey': {'address': address}, + 'label': '*', + 'timestamp': 'now', + }]) + + assert_equal(response[0]['success'], False) + assert_equal(response[0]['error']['code'], -11) + assert_equal(response[0]['error']['message'], "Invalid label name") + + for rpc_call in rpc_calls: + assert_raises_rpc_error(-11, "Invalid label name", *rpc_call, "*") + def run_test(self): # Check that there's no UTXO on the node node = self.nodes[0] @@ -80,8 +121,14 @@ class WalletLabelsTest(BitcoinTestFramework): label.add_receive_address(address) label.verify(node) + # Check listlabels when passing 'purpose' + node2_addr = self.nodes[1].getnewaddress() + node.setlabel(node2_addr, "node2_addr") + assert_equal(node.listlabels(purpose="send"), ["node2_addr"]) + assert_equal(node.listlabels(purpose="receive"), sorted(['coinbase'] + [label.name for label in labels])) + # Check all labels are returned by listlabels. - assert_equal(node.listlabels(), sorted(['coinbase'] + [label.name for label in labels])) + assert_equal(node.listlabels(), sorted(['coinbase'] + [label.name for label in labels] + ["node2_addr"])) # Send a transaction to each label. for label in labels: @@ -135,6 +182,8 @@ class WalletLabelsTest(BitcoinTestFramework): # in the label. This is a no-op. change_label(node, labels[2].addresses[0], labels[2], labels[2]) + self.invalid_label_name_test() + if self.options.descriptors: # This is a descriptor wallet test because of segwit v1+ addresses self.log.info('Check watchonly labels') diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py index d5372f5aee..fb2156bda1 100755 --- a/test/functional/wallet_listdescriptors.py +++ b/test/functional/wallet_listdescriptors.py @@ -1,11 +1,14 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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 listdescriptors RPC.""" +from test_framework.blocktools import ( + TIME_GENESIS_BLOCK, +) from test_framework.descriptors import ( - descsum_create + descsum_create, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -15,6 +18,9 @@ from test_framework.util import ( class ListDescriptorsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 1 @@ -63,13 +69,13 @@ class ListDescriptorsTest(BitcoinTestFramework): wallet = node.get_wallet_rpc('w2') wallet.importdescriptors([{ 'desc': descsum_create('wpkh(' + xprv + hardened_path + '/0/*)'), - 'timestamp': 1296688602, + 'timestamp': TIME_GENESIS_BLOCK, }]) expected = { 'wallet_name': 'w2', 'descriptors': [ {'desc': descsum_create('wpkh([80002067' + hardened_path + ']' + xpub_acc + '/0/*)'), - 'timestamp': 1296688602, + 'timestamp': TIME_GENESIS_BLOCK, 'active': False, 'range': [0, 0], 'next': 0}, @@ -83,7 +89,7 @@ class ListDescriptorsTest(BitcoinTestFramework): 'wallet_name': 'w2', 'descriptors': [ {'desc': descsum_create('wpkh(' + xprv + hardened_path + '/0/*)'), - 'timestamp': 1296688602, + 'timestamp': TIME_GENESIS_BLOCK, 'active': False, 'range': [0, 0], 'next': 0}, @@ -105,7 +111,7 @@ class ListDescriptorsTest(BitcoinTestFramework): watch_only_wallet = node.get_wallet_rpc('watch-only') watch_only_wallet.importdescriptors([{ 'desc': descsum_create('wpkh(' + xpub_acc + ')'), - 'timestamp': 1296688602, + 'timestamp': TIME_GENESIS_BLOCK, }]) assert_raises_rpc_error(-4, 'Can\'t get descriptor string', watch_only_wallet.listdescriptors, True) @@ -114,14 +120,14 @@ class ListDescriptorsTest(BitcoinTestFramework): wallet = node.get_wallet_rpc('w4') wallet.importdescriptors([{ 'desc': descsum_create('combo(' + node.get_deterministic_priv_key().key + ')'), - 'timestamp': 1296688602, + 'timestamp': TIME_GENESIS_BLOCK, }]) expected = { 'wallet_name': 'w4', 'descriptors': [ {'active': False, 'desc': 'combo(0227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3f)#np574htj', - 'timestamp': 1296688602}, + 'timestamp': TIME_GENESIS_BLOCK}, ] } assert_equal(expected, wallet.listdescriptors()) diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py index f1d7de2f27..8ec21484d1 100755 --- a/test/functional/wallet_listreceivedby.py +++ b/test/functional/wallet_listreceivedby.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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, listreceivedbylabel, getreceivedybaddress, and getreceivedbylabel RPCs.""" @@ -16,6 +16,9 @@ from test_framework.wallet_util import test_address class ReceivedByTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 # whitelist peers to speed up tx relay / mempool sync diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index aff408ceb1..bfca344fd1 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 listsinceblock RPC.""" @@ -20,6 +20,9 @@ from test_framework.wallet_util import bytes_to_wif from decimal import Decimal class ListSinceBlockTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True @@ -46,6 +49,7 @@ class ListSinceBlockTest(BitcoinTestFramework): self.test_desc() self.test_send_to_self() self.test_op_return() + self.test_label() def test_no_blockhash(self): self.log.info("Test no blockhash") @@ -462,6 +466,20 @@ class ListSinceBlockTest(BitcoinTestFramework): assert 'address' not in op_ret_tx + def test_label(self): + self.log.info('Test passing "label" argument fetches incoming transactions having the specified label') + new_addr = self.nodes[1].getnewaddress(label="new_addr", address_type="bech32") + + self.nodes[2].sendtoaddress(address=new_addr, amount="0.001") + self.generate(self.nodes[2], 1) + + for label in ["new_addr", ""]: + new_addr_transactions = self.nodes[1].listsinceblock(label=label)["transactions"] + assert_equal(len(new_addr_transactions), 1) + assert_equal(new_addr_transactions[0]["label"], label) + if label == "new_addr": + assert_equal(new_addr_transactions[0]["address"], new_addr) + if __name__ == '__main__': ListSinceBlockTest().main() diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py index 9bb06774a5..a44c129c87 100755 --- a/test/functional/wallet_listtransactions.py +++ b/test/functional/wallet_listtransactions.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2014-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -21,6 +21,9 @@ from test_framework.util import ( class ListTransactionsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 3 # This test isn't testing txn relay/timing, so set whitelist on the diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index 3c1cb6ac32..688ac98617 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 Migrating a wallet from legacy to descriptor.""" @@ -19,6 +19,9 @@ from test_framework.wallet_util import ( class WalletMigrationTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -37,11 +40,13 @@ class WalletMigrationTest(BitcoinTestFramework): assert_equal(file_magic, b'SQLite format 3\x00') assert_equal(self.nodes[0].get_wallet_rpc(wallet_name).getwalletinfo()["format"], "sqlite") - def create_legacy_wallet(self, wallet_name): - self.nodes[0].createwallet(wallet_name=wallet_name) + def create_legacy_wallet(self, wallet_name, disable_private_keys=False): + self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, disable_private_keys=disable_private_keys) wallet = self.nodes[0].get_wallet_rpc(wallet_name) - assert_equal(wallet.getwalletinfo()["descriptors"], False) - assert_equal(wallet.getwalletinfo()["format"], "bdb") + info = wallet.getwalletinfo() + assert_equal(info["descriptors"], False) + assert_equal(info["format"], "bdb") + assert_equal(info["private_keys_enabled"], not disable_private_keys) return wallet def assert_addr_info_equal(self, addr_info, addr_info_old): @@ -184,11 +189,9 @@ class WalletMigrationTest(BitcoinTestFramework): # Some keys in multisig do not belong to this wallet self.log.info("Test migration of a wallet that has some keys in a multisig") - self.nodes[0].createwallet(wallet_name="multisig1") - multisig1 = self.nodes[0].get_wallet_rpc("multisig1") + multisig1 = self.create_legacy_wallet("multisig1") ms_info = multisig1.addmultisigaddress(2, [multisig1.getnewaddress(), pub1, pub2]) ms_info2 = multisig1.addmultisigaddress(2, [multisig1.getnewaddress(), pub1, pub2]) - assert_equal(multisig1.getwalletinfo()["descriptors"], False) addr1 = ms_info["address"] addr2 = ms_info2["address"] @@ -253,11 +256,9 @@ class WalletMigrationTest(BitcoinTestFramework): # Wallet with an imported address. Should be the same thing as the multisig test self.log.info("Test migration of a wallet with watchonly imports") - self.nodes[0].createwallet(wallet_name="imports0") - imports0 = self.nodes[0].get_wallet_rpc("imports0") - assert_equal(imports0.getwalletinfo()["descriptors"], False) + imports0 = self.create_legacy_wallet("imports0") - # Exteranl address label + # External address label imports0.setlabel(default.getnewaddress(), "external") # Normal non-watchonly tx @@ -310,16 +311,19 @@ class WalletMigrationTest(BitcoinTestFramework): assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", watchonly.gettransaction, received_txid) assert_equal(len(watchonly.listtransactions(include_watchonly=True)), 3) + # Check that labels were migrated and persisted to watchonly wallet + self.nodes[0].unloadwallet("imports0_watchonly") + self.nodes[0].loadwallet("imports0_watchonly") + labels = watchonly.listlabels() + assert "external" in labels + assert "imported" in labels + def test_no_privkeys(self): default = self.nodes[0].get_wallet_rpc(self.default_wallet_name) # Migrating an actual watchonly wallet should not create a new watchonly wallet self.log.info("Test migration of a pure watchonly wallet") - self.nodes[0].createwallet(wallet_name="watchonly0", disable_private_keys=True) - watchonly0 = self.nodes[0].get_wallet_rpc("watchonly0") - info = watchonly0.getwalletinfo() - assert_equal(info["descriptors"], False) - assert_equal(info["private_keys_enabled"], False) + watchonly0 = self.create_legacy_wallet("watchonly0", disable_private_keys=True) addr = default.getnewaddress() desc = default.getaddressinfo(addr)["desc"] @@ -342,11 +346,7 @@ class WalletMigrationTest(BitcoinTestFramework): # Migrating a wallet with pubkeys added to the keypool self.log.info("Test migration of a pure watchonly wallet with pubkeys in keypool") - self.nodes[0].createwallet(wallet_name="watchonly1", disable_private_keys=True) - watchonly1 = self.nodes[0].get_wallet_rpc("watchonly1") - info = watchonly1.getwalletinfo() - assert_equal(info["descriptors"], False) - assert_equal(info["private_keys_enabled"], False) + watchonly1 = self.create_legacy_wallet("watchonly1", disable_private_keys=True) addr1 = default.getnewaddress(address_type="bech32") addr2 = default.getnewaddress(address_type="bech32") @@ -393,6 +393,15 @@ class WalletMigrationTest(BitcoinTestFramework): assert_equal(bals, wallet.getbalances()) + def test_encrypted(self): + self.log.info("Test migration of an encrypted wallet") + wallet = self.create_legacy_wallet("encrypted") + + wallet.encryptwallet("pass") + + assert_raises_rpc_error(-15, "Error: migratewallet on encrypted wallets is currently unsupported.", wallet.migratewallet) + # TODO: Fix migratewallet so that we can actually migrate encrypted wallets + def run_test(self): self.generate(self.nodes[0], 101) @@ -402,6 +411,7 @@ class WalletMigrationTest(BitcoinTestFramework): self.test_other_watchonly() self.test_no_privkeys() self.test_pk_coinbases() + self.test_encrypted() if __name__ == '__main__': WalletMigrationTest().main() diff --git a/test/functional/wallet_miniscript.py b/test/functional/wallet_miniscript.py index 2252f1e424..cefcaf4dc7 100755 --- a/test/functional/wallet_miniscript.py +++ b/test/functional/wallet_miniscript.py @@ -22,6 +22,9 @@ MINISCRIPTS = [ class WalletMiniscriptTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 1 diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py index 2b565db137..12069fb00d 100755 --- a/test/functional/wallet_multisig_descriptor_psbt.py +++ b/test/functional/wallet_multisig_descriptor_psbt.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 basic M-of-N multisig setup between multiple people using descriptor wallets and PSBTs, as well as a signing flow. @@ -16,6 +16,9 @@ from test_framework.util import ( class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 3 self.setup_clean_chain = True diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 1c890d7207..2faf6cad8b 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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. @@ -52,6 +52,7 @@ class MultiWalletTest(BitcoinTestFramework): self.skip_if_no_wallet() def add_options(self, parser): + self.add_wallet_options(parser) parser.add_argument( '--data_wallets_dir', default=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/wallets/'), @@ -302,12 +303,8 @@ class MultiWalletTest(BitcoinTestFramework): assert_raises_rpc_error(-18, "Wallet file verification failed. Failed to load database path '{}'. Path does not exist.".format(path), self.nodes[0].loadwallet, 'wallets') # Fail to load duplicate wallets - path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "w1", "wallet.dat") - if self.options.descriptors: - assert_raises_rpc_error(-4, f"Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['PACKAGE_NAME']}?", self.nodes[0].loadwallet, wallet_names[0]) - else: - assert_raises_rpc_error(-35, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, wallet_names[0]) - + assert_raises_rpc_error(-35, "Wallet \"w1\" is already loaded.", self.nodes[0].loadwallet, wallet_names[0]) + if not self.options.descriptors: # This tests the default wallet that BDB makes, so SQLite wallet doesn't need to test this # Fail to load duplicate wallets by different ways (directory and filepath) path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "wallet.dat") diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py index 7295db4653..d9f7c14ded 100755 --- a/test/functional/wallet_orphanedreward.py +++ b/test/functional/wallet_orphanedreward.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 orphaned block rewards in the wallet.""" @@ -8,6 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal class OrphanedBlockRewardTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/wallet_pruning.py b/test/functional/wallet_pruning.py new file mode 100755 index 0000000000..6d8475ce8d --- /dev/null +++ b/test/functional/wallet_pruning.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 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 on pruned node.""" +import os + +from test_framework.util import assert_equal, assert_raises_rpc_error +from test_framework.blocktools import ( + COINBASE_MATURITY, + create_block +) +from test_framework.blocktools import create_coinbase +from test_framework.test_framework import BitcoinTestFramework + +from test_framework.script import ( + CScript, + OP_RETURN, + OP_TRUE, +) + +class WalletPruningTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 2 + self.wallet_names = [] + self.extra_args = [ + [], # node dedicated to mining + ['-prune=550'], # node dedicated to testing pruning + ] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + self.skip_if_no_bdb() + + def mine_large_blocks(self, node, n): + # Get the block parameters for the first block + best_block = node.getblock(node.getbestblockhash()) + height = int(best_block["height"]) + 1 + self.nTime = max(self.nTime, int(best_block["time"])) + 1 + previousblockhash = int(best_block["hash"], 16) + big_script = CScript([OP_RETURN] + [OP_TRUE] * 950000) + for _ in range(n): + block = create_block(hashprev=previousblockhash, ntime=self.nTime, coinbase=create_coinbase(height, script_pubkey=big_script)) + block.solve() + + # Submit to the node + node.submitblock(block.serialize().hex()) + + previousblockhash = block.sha256 + height += 1 + + # Simulate 10 minutes of work time per block + # Important for matching a timestamp with a block +- some window + self.nTime += 600 + for n in self.nodes: + if n.running: + n.setmocktime(self.nTime) # Update node's time to accept future blocks + self.sync_all() + + def test_wallet_import_pruned(self, wallet_name): + self.log.info("Make sure we can import wallet when pruned and required blocks are still available") + + wallet_file = wallet_name + ".dat" + wallet_birthheight = self.get_birthheight(wallet_file) + + # Verify that the block at wallet's birthheight is available at the pruned node + self.nodes[1].getblock(self.nodes[1].getblockhash(wallet_birthheight)) + + # Import wallet into pruned node + self.nodes[1].createwallet(wallet_name="wallet_pruned", descriptors=False, load_on_startup=True) + self.nodes[1].importwallet(os.path.join(self.nodes[0].datadir, wallet_file)) + + # Make sure that prune node's wallet correctly accounts for balances + assert_equal(self.nodes[1].getbalance(), self.nodes[0].getbalance()) + + self.log.info("- Done") + + def test_wallet_import_pruned_with_missing_blocks(self, wallet_name): + self.log.info("Make sure we cannot import wallet when pruned and required blocks are not available") + + wallet_file = wallet_name + ".dat" + wallet_birthheight = self.get_birthheight(wallet_file) + + # Verify that the block at wallet's birthheight is not available at the pruned node + assert_raises_rpc_error(-1, "Block not available (pruned data)", self.nodes[1].getblock, self.nodes[1].getblockhash(wallet_birthheight)) + + # Make sure wallet cannot be imported because of missing blocks + # This will try to rescan blocks `TIMESTAMP_WINDOW` (2h) before the wallet birthheight. + # There are 6 blocks an hour, so 11 blocks (excluding birthheight). + assert_raises_rpc_error(-4, f"Pruned blocks from height {wallet_birthheight - 11} required to import keys. Use RPC call getblockchaininfo to determine your pruned height.", self.nodes[1].importwallet, os.path.join(self.nodes[0].datadir, wallet_file)) + self.log.info("- Done") + + def get_birthheight(self, wallet_file): + """Gets birthheight of a wallet on node0""" + with open(os.path.join(self.nodes[0].datadir, wallet_file), 'r', encoding="utf8") as f: + for line in f: + if line.startswith('# * Best block at time of backup'): + wallet_birthheight = int(line.split(' ')[9]) + return wallet_birthheight + + def has_block(self, block_index): + """Checks if the pruned node has the specific blk0000*.dat file""" + return os.path.isfile(os.path.join(self.nodes[1].datadir, self.chain, "blocks", f"blk{block_index:05}.dat")) + + def create_wallet(self, wallet_name, *, unload=False): + """Creates and dumps a wallet on the non-pruned node0 to be later import by the pruned node""" + self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, load_on_startup=True) + self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, wallet_name + ".dat")) + if (unload): + self.nodes[0].unloadwallet(wallet_name) + + def run_test(self): + self.nTime = 0 + self.log.info("Warning! This test requires ~1.3GB of disk space") + + self.log.info("Generating a long chain of blocks...") + + # A blk*.dat file is 128MB + # Generate 250 light blocks + self.generate(self.nodes[0], 250, sync_fun=self.no_op) + # Generate 50MB worth of large blocks in the blk00000.dat file + self.mine_large_blocks(self.nodes[0], 50) + + # Create a wallet which birth's block is in the blk00000.dat file + wallet_birthheight_1 = "wallet_birthheight_1" + assert_equal(self.has_block(1), False) + self.create_wallet(wallet_birthheight_1, unload=True) + + # Generate enough large blocks to reach pruning disk limit + # Not pruning yet because we are still below PruneAfterHeight + self.mine_large_blocks(self.nodes[0], 600) + self.log.info("- Long chain created") + + # Create a wallet with birth height > wallet_birthheight_1 + wallet_birthheight_2 = "wallet_birthheight_2" + self.create_wallet(wallet_birthheight_2) + + # Fund wallet to later verify that importwallet correctly accounts for balances + self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, self.nodes[0].getnewaddress(), sync_fun=self.no_op) + + # We've reached pruning storage & height limit but + # pruning doesn't run until another chunk (blk*.dat file) is allocated. + # That's why we are generating another 5 large blocks + self.mine_large_blocks(self.nodes[0], 5) + + # blk00000.dat file is now pruned from node1 + assert_equal(self.has_block(0), False) + + self.test_wallet_import_pruned(wallet_birthheight_2) + self.test_wallet_import_pruned_with_missing_blocks(wallet_birthheight_1) + +if __name__ == '__main__': + WalletPruningTest().main() diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py index f2bdb114b7..1c79c6816c 100755 --- a/test/functional/wallet_reorgsrestore.py +++ b/test/functional/wallet_reorgsrestore.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,6 +23,9 @@ from test_framework.util import ( ) class ReorgsRestoreTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 3 @@ -91,11 +94,11 @@ class ReorgsRestoreTest(BitcoinTestFramework): tx_after_reorg = self.nodes[1].gettransaction(txid) # Check that normal confirmed tx is confirmed again but with different blockhash assert_equal(tx_after_reorg["confirmations"], 2) - assert(tx_before_reorg["blockhash"] != tx_after_reorg["blockhash"]) + assert tx_before_reorg["blockhash"] != tx_after_reorg["blockhash"] conflicted_after_reorg = self.nodes[1].gettransaction(conflicted_txid) # Check that conflicted tx is confirmed again with blockhash different than previously conflicting tx assert_equal(conflicted_after_reorg["confirmations"], 1) - assert(conflicting["blockhash"] != conflicted_after_reorg["blockhash"]) + assert conflicting["blockhash"] != conflicted_after_reorg["blockhash"] if __name__ == '__main__': ReorgsRestoreTest().main() diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index b3d02fbfc9..7e4a4002b2 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 resends transactions periodically.""" @@ -18,6 +18,9 @@ from test_framework.util import ( ) class ResendWalletTransactionsTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index 83b8332c4d..ac3ec06eec 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-2022 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 send RPC command.""" @@ -25,6 +25,9 @@ from test_framework.util import ( from test_framework.wallet_util import bytes_to_wif class WalletSendTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 2 # whitelist all peers to speed up tx relay / mempool sync @@ -42,7 +45,7 @@ class WalletSendTest(BitcoinTestFramework): conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None, inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None, include_watching=None, locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None, - expect_error=None, solving_data=None): + expect_error=None, solving_data=None, minconf=None): assert (amount is None) != (data is None) from_balance_before = from_wallet.getbalances()["mine"]["trusted"] @@ -103,6 +106,8 @@ class WalletSendTest(BitcoinTestFramework): options["subtract_fee_from_outputs"] = subtract_fee_from_outputs if solving_data is not None: options["solving_data"] = solving_data + if minconf is not None: + options["minconf"] = minconf if len(options.keys()) == 0: options = None @@ -276,11 +281,11 @@ class WalletSendTest(BitcoinTestFramework): self.log.info("Don't broadcast...") res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=False) - assert(res["hex"]) + assert res["hex"] self.log.info("Return PSBT...") res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, psbt=True) - assert(res["psbt"]) + assert res["psbt"] self.log.info("Create transaction that spends to address, but don't broadcast...") self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=False) @@ -409,10 +414,12 @@ class WalletSendTest(BitcoinTestFramework): assert res["complete"] utxo1 = w0.listunspent()[0] assert_equal(utxo1["amount"], 50) + ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \ + "Please allow other inputs to be automatically selected or include more coins manually" self.test_send(from_wallet=w0, to_wallet=w1, amount=51, inputs=[utxo1], - expect_error=(-4, "Insufficient funds")) + expect_error=(-4, ERR_NOT_ENOUGH_PRESET_INPUTS)) self.test_send(from_wallet=w0, to_wallet=w1, amount=51, inputs=[utxo1], add_inputs=False, - expect_error=(-4, "Insufficient funds")) + expect_error=(-4, ERR_NOT_ENOUGH_PRESET_INPUTS)) res = self.test_send(from_wallet=w0, to_wallet=w1, amount=51, inputs=[utxo1], add_inputs=True, add_to_wallet=False) assert res["complete"] @@ -482,6 +489,16 @@ class WalletSendTest(BitcoinTestFramework): res = self.test_send(from_wallet=w5, to_wallet=w0, amount=1, include_unsafe=True) assert res["complete"] + self.log.info("Minconf") + self.nodes[1].createwallet(wallet_name="minconfw") + minconfw= self.nodes[1].get_wallet_rpc("minconfw") + self.test_send(from_wallet=w0, to_wallet=minconfw, amount=2) + self.generate(self.nodes[0], 3) + self.test_send(from_wallet=minconfw, to_wallet=w0, amount=1, minconf=4, expect_error=(-4, "Insufficient funds")) + self.test_send(from_wallet=minconfw, to_wallet=w0, amount=1, minconf=-4, expect_error=(-8, "Negative minconf")) + res = self.test_send(from_wallet=minconfw, to_wallet=w0, amount=1, minconf=3) + assert res["complete"] + self.log.info("External outputs") eckey = ECKey() eckey.generate() diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py index 4fe11455b1..f6440f07d7 100755 --- a/test/functional/wallet_sendall.py +++ b/test/functional/wallet_sendall.py @@ -26,6 +26,9 @@ def cleanup(func): class SendallTest(BitcoinTestFramework): # Setup and helpers + def add_options(self, parser): + self.add_wallet_options(parser) + def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -282,6 +285,12 @@ class SendallTest(BitcoinTestFramework): fee_rate=100000) @cleanup + def sendall_fails_on_low_fee(self): + self.log.info("Test sendall fails if the transaction fee is lower than the minimum fee rate setting") + assert_raises_rpc_error(-8, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)", + self.wallet.sendall, recipients=[self.recipient], fee_rate=0.999) + + @cleanup def sendall_watchonly_specific_inputs(self): self.log.info("Test sendall with a subset of UTXO pool in a watchonly wallet") self.add_utxos([17, 4]) @@ -308,9 +317,75 @@ class SendallTest(BitcoinTestFramework): assert_equal(decoded["tx"]["vin"][0]["vout"], utxo["vout"]) assert_equal(decoded["tx"]["vout"][0]["scriptPubKey"]["address"], self.remainder_target) + @cleanup + def sendall_with_minconf(self): + # utxo of 17 bicoin has 6 confirmations, utxo of 4 has 3 + self.add_utxos([17]) + self.generate(self.nodes[0], 2) + self.add_utxos([4]) + self.generate(self.nodes[0], 2) + + self.log.info("Test sendall fails because minconf is negative") + + assert_raises_rpc_error(-8, + "Invalid minconf (minconf cannot be negative): -2", + self.wallet.sendall, + recipients=[self.remainder_target], + options={"minconf": -2}) + self.log.info("Test sendall fails because minconf is used while specific inputs are provided") + + utxo = self.wallet.listunspent()[0] + assert_raises_rpc_error(-8, + "Cannot combine minconf or maxconf with specific inputs.", + self.wallet.sendall, + recipients=[self.remainder_target], + options={"inputs": [utxo], "minconf": 2}) + + self.log.info("Test sendall fails because there are no utxos with enough confirmations specified by minconf") + + assert_raises_rpc_error(-6, + "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.", + self.wallet.sendall, + recipients=[self.remainder_target], + options={"minconf": 7}) + + self.log.info("Test sendall only spends utxos with a specified number of confirmations when minconf is used") + self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"minconf": 6}) + + assert_equal(len(self.wallet.listunspent()), 1) + assert_equal(self.wallet.listunspent()[0]['confirmations'], 3) + + # decrease minconf and show the remaining utxo is picked up + self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"minconf": 3}) + assert_equal(self.wallet.getbalance(), 0) + + @cleanup + def sendall_with_maxconf(self): + # utxo of 17 bicoin has 6 confirmations, utxo of 4 has 3 + self.add_utxos([17]) + self.generate(self.nodes[0], 2) + self.add_utxos([4]) + self.generate(self.nodes[0], 2) + + self.log.info("Test sendall fails because there are no utxos with enough confirmations specified by maxconf") + assert_raises_rpc_error(-6, + "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.", + self.wallet.sendall, + recipients=[self.remainder_target], + options={"maxconf": 1}) + + self.log.info("Test sendall only spends utxos with a specified number of confirmations when maxconf is used") + self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"maxconf":4}) + assert_equal(len(self.wallet.listunspent()), 1) + assert_equal(self.wallet.listunspent()[0]['confirmations'], 6) + # This tests needs to be the last one otherwise @cleanup will fail with "Transaction too large" error def sendall_fails_with_transaction_too_large(self): self.log.info("Test that sendall fails if resulting transaction is too large") + + # Force the wallet to bulk-generate the addresses we'll need + self.wallet.keypoolrefill(1600) + # create many inputs outputs = {self.wallet.getnewaddress(): 0.000025 for _ in range(1600)} self.def_wallet.sendmany(amounts=outputs) @@ -373,9 +448,18 @@ class SendallTest(BitcoinTestFramework): # Sendall fails when providing a fee that is too high self.sendall_fails_on_high_fee() + # Sendall fails when fee rate is lower than minimum + self.sendall_fails_on_low_fee() + # Sendall succeeds with watchonly wallets spending specific UTXOs self.sendall_watchonly_specific_inputs() + # Sendall only uses outputs with at least a give number of confirmations when using minconf + self.sendall_with_minconf() + + # Sendall only uses outputs with less than a given number of confirmation when using minconf + self.sendall_with_maxconf() + # Sendall fails when many inputs result to too large transaction self.sendall_fails_with_transaction_too_large() diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py index db3a8a2efa..8d25044e43 100755 --- a/test/functional/wallet_signer.py +++ b/test/functional/wallet_signer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 external signer. @@ -13,11 +13,15 @@ import platform from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + assert_greater_than, assert_raises_rpc_error, ) class WalletSignerTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def mock_signer_path(self): path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mocks', 'signer.py') if platform.system() == "Windows": @@ -166,11 +170,11 @@ class WalletSignerTest(BitcoinTestFramework): assert_equal(result[1], {'success': True}) assert_equal(mock_wallet.getwalletinfo()["txcount"], 1) dest = self.nodes[0].getnewaddress(address_type='bech32') - mock_psbt = mock_wallet.walletcreatefundedpsbt([], {dest:0.5}, 0, {}, True)['psbt'] + mock_psbt = mock_wallet.walletcreatefundedpsbt([], {dest:0.5}, 0, {'replaceable': True}, True)['psbt'] mock_psbt_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt, sign=True, sighashtype="ALL", bip32derivs=True) mock_psbt_final = mock_wallet.finalizepsbt(mock_psbt_signed["psbt"]) mock_tx = mock_psbt_final["hex"] - assert(mock_wallet.testmempoolaccept([mock_tx])[0]["allowed"]) + assert mock_wallet.testmempoolaccept([mock_tx])[0]["allowed"] # # Create a new wallet and populate with specific public keys, in order # # to work with the mock signed PSBT. @@ -199,22 +203,42 @@ class WalletSignerTest(BitcoinTestFramework): # assert_equal(result[1], {'success': True}) assert_equal(hww.getwalletinfo()["txcount"], 1) - assert(hww.testmempoolaccept([mock_tx])[0]["allowed"]) + assert hww.testmempoolaccept([mock_tx])[0]["allowed"] with open(os.path.join(self.nodes[1].cwd, "mock_psbt"), "w", encoding="utf8") as f: f.write(mock_psbt_signed["psbt"]) self.log.info('Test send using hww1') + # Don't broadcast transaction yet so the RPC returns the raw hex res = hww.send(outputs={dest:0.5},options={"add_to_wallet": False}) - assert(res["complete"]) + assert res["complete"] assert_equal(res["hex"], mock_tx) self.log.info('Test sendall using hww1') res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()],options={"add_to_wallet": False}) - assert(res["complete"]) + assert res["complete"] assert_equal(res["hex"], mock_tx) + # Broadcast transaction so we can bump the fee + hww.sendrawtransaction(res["hex"]) + + self.log.info('Prepare fee bumped mock PSBT') + + # Now that the transaction is broadcast, bump fee in mock wallet: + orig_tx_id = res["txid"] + mock_psbt_bumped = mock_wallet.psbtbumpfee(orig_tx_id)["psbt"] + mock_psbt_bumped_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt_bumped, sign=True, sighashtype="ALL", bip32derivs=True) + + with open(os.path.join(self.nodes[1].cwd, "mock_psbt"), "w", encoding="utf8") as f: + f.write(mock_psbt_bumped_signed["psbt"]) + + self.log.info('Test bumpfee using hww1') + + # Bump fee + res = hww.bumpfee(orig_tx_id) + assert_greater_than(res["fee"], res["origfee"]) + assert_equal(res["errors"], []) # # Handle error thrown by script # self.set_mock_result(self.nodes[4], "2") diff --git a/test/functional/wallet_signmessagewithaddress.py b/test/functional/wallet_signmessagewithaddress.py index 74a8f2eef2..4a4b818bd1 100755 --- a/test/functional/wallet_signmessagewithaddress.py +++ b/test/functional/wallet_signmessagewithaddress.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2016-2021 The Bitcoin Core developers +# Copyright (c) 2016-2022 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 commands for signing and verifying messages.""" @@ -10,6 +10,9 @@ from test_framework.util import ( ) class SignMessagesWithAddressTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet_signrawtransactionwithwallet.py b/test/functional/wallet_signrawtransactionwithwallet.py index 6b30386b7e..3d2f41cb83 100755 --- a/test/functional/wallet_signrawtransactionwithwallet.py +++ b/test/functional/wallet_signrawtransactionwithwallet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2021 The Bitcoin Core developers +# Copyright (c) 2015-2022 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 signrawtransactionwithwallet RPC.""" @@ -34,6 +34,9 @@ from decimal import ( ) class SignRawTransactionWithWalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/wallet_simulaterawtx.py b/test/functional/wallet_simulaterawtx.py index a408b99515..545aad892c 100755 --- a/test/functional/wallet_simulaterawtx.py +++ b/test/functional/wallet_simulaterawtx.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 simulaterawtransaction. @@ -15,6 +15,9 @@ from test_framework.util import ( ) class SimulateTxTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py index d96c2da686..2cc4e312af 100755 --- a/test/functional/wallet_startup.py +++ b/test/functional/wallet_startup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2020 The Bitcoin Core developers +# Copyright (c) 2017-2022 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 load on startup. @@ -13,6 +13,9 @@ from test_framework.util import ( class WalletStartupTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py index 4c28958982..b52892704f 100755 --- a/test/functional/wallet_taproot.py +++ b/test/functional/wallet_taproot.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 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 generation and spending of P2TR addresses.""" @@ -187,6 +187,9 @@ def compute_raw_taproot_address(pubkey): class WalletTaprootTest(BitcoinTestFramework): """Test generation and spending of P2TR address outputs.""" + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True @@ -241,7 +244,7 @@ class WalletTaprootTest(BitcoinTestFramework): desc_pub = self.make_desc(pattern, privmap, keys, True) assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub) result = addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}]) - assert(result[0]['success']) + assert result[0]['success'] address_type = "bech32m" if "tr" in pattern else "bech32" for i in range(4): addr_g = addr_gen.getnewaddress(address_type=address_type) @@ -257,9 +260,9 @@ class WalletTaprootTest(BitcoinTestFramework): # tr descriptors can be imported result = privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}]) - assert(result[0]["success"]) + assert result[0]['success'] result = pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}]) - assert(result[0]["success"]) + assert result[0]["success"] # Cleanup privs_tr_enabled.unloadwallet() @@ -281,9 +284,9 @@ class WalletTaprootTest(BitcoinTestFramework): assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub) assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub) result = rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}]) - assert(result[0]['success']) + assert result[0]['success'] result = rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}]) - assert(result[0]['success']) + assert result[0]['success'] address_type = "bech32m" if "tr" in pattern else "bech32" for i in range(4): addr_g = rpc_online.getnewaddress(address_type=address_type) @@ -299,12 +302,12 @@ class WalletTaprootTest(BitcoinTestFramework): # Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends. res = rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200) self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op) - assert(rpc_online.gettransaction(res)["confirmations"] > 0) + assert rpc_online.gettransaction(res)["confirmations"] > 0 # Cleanup txid = rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"] self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op) - assert(rpc_online.gettransaction(txid)["confirmations"] > 0) + assert rpc_online.gettransaction(txid)["confirmations"] > 0 rpc_online.unloadwallet() def do_test_psbt(self, comment, pattern, privmap, treefn, keys_pay, keys_change): @@ -326,16 +329,16 @@ class WalletTaprootTest(BitcoinTestFramework): assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub) assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub) result = psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}]) - assert(result[0]['success']) + assert result[0]['success'] result = psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}]) - assert(result[0]['success']) + assert result[0]['success'] result = psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}]) - assert(result[0]['success']) + assert result[0]['success'] result = psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}]) - assert(result[0]['success']) + assert result[0]['success'] for key in keys_pay + keys_change: result = key_only_wallet.importdescriptors([{"desc": descsum_create(f"wpkh({key['xprv']}/*)"), "timestamp":"now"}]) - assert(result[0]["success"]) + assert result[0]["success"] address_type = "bech32m" if "tr" in pattern else "bech32" for i in range(4): addr_g = psbt_online.getnewaddress(address_type=address_type) @@ -372,7 +375,7 @@ class WalletTaprootTest(BitcoinTestFramework): txid = self.nodes[0].sendrawtransaction(rawtx) self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op) - assert(psbt_online.gettransaction(txid)['confirmations'] > 0) + assert psbt_online.gettransaction(txid)['confirmations'] > 0 # Cleanup psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"] @@ -380,7 +383,7 @@ class WalletTaprootTest(BitcoinTestFramework): rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex'] txid = self.nodes[0].sendrawtransaction(rawtx) self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op) - assert(psbt_online.gettransaction(txid)['confirmations'] > 0) + assert psbt_online.gettransaction(txid)['confirmations'] > 0 psbt_online.unloadwallet() psbt_offline.unloadwallet() diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py index a71cec6607..57a7c3907a 100755 --- a/test/functional/wallet_timelock.py +++ b/test/functional/wallet_timelock.py @@ -8,6 +8,9 @@ from test_framework.util import assert_equal class WalletLocktimeTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py index 9caa1fa3d0..de9616b4a1 100755 --- a/test/functional/wallet_transactiontime_rescan.py +++ b/test/functional/wallet_transactiontime_rescan.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 time during old block rescanning @@ -17,6 +17,9 @@ from test_framework.util import ( class TransactionTimeRescanTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.setup_clean_chain = False self.num_nodes = 3 diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 5bdde13aa4..d8ef66d83a 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -24,6 +24,7 @@ class TxnMallTest(BitcoinTestFramework): self.skip_if_no_wallet() def add_options(self, parser): + self.add_wallet_options(parser) 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", diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index 206187fb61..38ebfe0d7a 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-2021 The Bitcoin Core developers +# Copyright (c) 2014-2022 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.""" @@ -22,6 +22,7 @@ class TxnMallTest(BitcoinTestFramework): self.skip_if_no_wallet() def add_options(self, parser): + self.add_wallet_options(parser) parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index c452e1eafd..4495a7d778 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """upgradewallet RPC functional test @@ -45,6 +45,9 @@ def deser_keymeta(f): return ver, create_time, kp_str, seed_id, fpr, path_len, path, has_key_orig class UpgradeWalletTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, descriptors=False) + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py index 69c32ba54c..dd4514318c 100755 --- a/test/functional/wallet_watchonly.py +++ b/test/functional/wallet_watchonly.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 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 createwallet watchonly arguments. @@ -14,6 +14,9 @@ from test_framework.util import ( class CreateWalletWatchonlyTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser) + def set_test_params(self): self.num_nodes = 1 diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index e2eab2a0fe..af21e7b956 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -143,7 +143,7 @@ def main(): timeout=20, check=True, stderr=subprocess.PIPE, - universal_newlines=True, + text=True, ).stderr if "libFuzzer" not in help_output: logging.error("Must be built with libFuzzer") @@ -200,7 +200,7 @@ def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets): env=get_fuzz_env(target=t, source_dir=src_dir), check=True, stderr=subprocess.PIPE, - universal_newlines=True, + text=True, ).stderr)) futures = [] @@ -241,7 +241,7 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir) env=get_fuzz_env(target=t, source_dir=src_dir), check=True, stderr=subprocess.PIPE, - universal_newlines=True, + text=True, ).stderr logging.debug(output) @@ -270,7 +270,7 @@ def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind): args, env=get_fuzz_env(target=t, source_dir=src_dir), stderr=subprocess.PIPE, - universal_newlines=True, + text=True, ) output += result.stderr return output, result @@ -299,7 +299,7 @@ def parse_test_list(*, fuzz_bin): }, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, - universal_newlines=True, + text=True, ).stdout.splitlines() return test_list_all diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py index c983dce619..7f5f15655c 100755 --- a/test/get_previous_releases.py +++ b/test/get_previous_releases.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (c) 2018-2021 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -136,7 +136,7 @@ def download_binary(tag, args) -> int: tarballHash = hasher.hexdigest() if tarballHash not in SHA256_SUMS or SHA256_SUMS[tarballHash]['tarball'] != tarball: - if tarball in SHA256_SUMS.values(): + if tarball in [v['tarball'] for v in SHA256_SUMS.values()]: print("Checksum did not match") return 1 @@ -148,10 +148,39 @@ def download_binary(tag, args) -> int: ret = subprocess.run(['tar', '-zxf', tarball, '-C', tag, '--strip-components=1', 'bitcoin-{tag}'.format(tag=tag[1:])]).returncode - if ret: + if ret != 0: + print(f"Failed to extract the {tag} tarball") return ret Path(tarball).unlink() + + if tag >= "v23" and platform == "arm64-apple-darwin": + # Starting with v23 there are arm64 binaries for ARM (e.g. M1, M2) macs, but they have to be signed to run + binary_path = f'{os.getcwd()}/{tag}/bin/' + + for arm_binary in os.listdir(binary_path): + # Is it already signed? + ret = subprocess.run( + ['codesign', '-v', binary_path + arm_binary], + stderr=subprocess.DEVNULL, # Suppress expected stderr output + ).returncode + if ret == 1: + # Have to self-sign the binary + ret = subprocess.run( + ['codesign', '-s', '-', binary_path + arm_binary] + ).returncode + if ret != 0: + print(f"Failed to self-sign {tag} {arm_binary} arm64 binary") + return 1 + + # Confirm success + ret = subprocess.run( + ['codesign', '-v', binary_path + arm_binary] + ).returncode + if ret != 0: + print(f"Failed to verify the self-signed {tag} {arm_binary} arm64 binary") + return 1 + return 0 @@ -260,11 +289,10 @@ if __name__ == '__main__': help='download release binary.') parser.add_argument('-t', '--target-dir', action='store', help='target directory.', default='releases') - parser.add_argument('tags', nargs='*', default=set( - [v['tag'] for v in SHA256_SUMS.values()] - ), + all_tags = sorted([*set([v['tag'] for v in SHA256_SUMS.values()])]) + parser.add_argument('tags', nargs='*', default=all_tags, help='release tags. e.g.: v0.18.1 v0.20.0rc2 ' - '(if not specified, the full list needed for' + '(if not specified, the full list needed for ' 'backwards compatibility tests will be used)' ) args = parser.parse_args() diff --git a/test/lint/README.md b/test/lint/README.md index 8d592c3282..704922d7ab 100644 --- a/test/lint/README.md +++ b/test/lint/README.md @@ -1,5 +1,23 @@ This folder contains lint scripts. +Running locally +=============== + +To run linters locally with the same versions as the CI environment, use the included +Dockerfile: + +```sh +cd ./ci/lint +docker build -t bitcoin-linter . + +cd /root/of/bitcoin/repo +docker run --rm -v $(pwd):/bitcoin -it bitcoin-linter +``` + +After building the container once, you can simply run the last command any time you +want to lint. + + check-doc.py ============ Check for missing documentation of command line options. diff --git a/test/lint/all-lint.py b/test/lint/all-lint.py index 34a7b9742a..c7889796c6 100755 --- a/test/lint/all-lint.py +++ b/test/lint/all-lint.py @@ -10,11 +10,12 @@ from glob import glob from pathlib import Path from subprocess import run +from sys import executable exit_code = 0 mod_path = Path(__file__).parent for lint in glob(f"{mod_path}/lint-*.py"): - result = run([lint]) + result = run([executable, lint]) if result.returncode != 0: print(f"^---- failure generated from {lint.split('/')[-1]}") exit_code |= result.returncode diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py index feaebc68e9..d22dd9d996 100755 --- a/test/lint/check-doc.py +++ b/test/lint/check-doc.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2020 The Bitcoin Core developers +# Copyright (c) 2015-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,7 +15,7 @@ import re FOLDER_GREP = 'src' FOLDER_TEST = 'src/test/' -REGEX_ARG = r'(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\("(-[^"]+)"' +REGEX_ARG = r'\b(?:GetArg|GetArgs|GetBoolArg|GetIntArg|GetPathArg|IsArgSet|get_net)\("(-[^"]+)"' REGEX_DOC = r'AddArg\("(-[^"=]+?)(?:=|")' 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) diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh index 9449b393f1..55c9528dea 100755 --- a/test/lint/commit-script-check.sh +++ b/test/lint/commit-script-check.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py index 195ff33d11..e7eecebce5 100755 --- a/test/lint/lint-assertions.py +++ b/test/lint/lint-assertions.py @@ -12,7 +12,7 @@ import subprocess def git_grep(params: [], error_msg: ""): try: - output = subprocess.check_output(["git", "grep", *params], universal_newlines=True, encoding="utf8") + output = subprocess.check_output(["git", "grep", *params], text=True, encoding="utf8") print(error_msg) print(output) return 1 diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index b69bbe7cd0..cf6a5f81f1 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -38,14 +38,14 @@ def main(): os.chdir(CODE_DIR) files = subprocess.check_output( ['git', 'ls-files', '--', '*.h', '*.cpp'], - universal_newlines=True, + text=True, ).splitlines() command = [sys.executable, "../contrib/devtools/circular-dependencies.py", *files] dependencies_output = subprocess.run( command, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ) for dependency_str in dependencies_output.stdout.rstrip().split("\n"): diff --git a/test/lint/lint-files.py b/test/lint/lint-files.py index 123bee2cbc..f2b5db681b 100755 --- a/test/lint/lint-files.py +++ b/test/lint/lint-files.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers +# Copyright (c) 2021-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/test/lint/lint-git-commit-check.py b/test/lint/lint-git-commit-check.py index a1d03370e8..5897a17e70 100755 --- a/test/lint/lint-git-commit-check.py +++ b/test/lint/lint-git-commit-check.py @@ -42,15 +42,17 @@ def main(): commit_range = "HEAD~" + args.prev_commits + "...HEAD" else: # This assumes that the target branch of the pull request will be master. - merge_base = check_output(["git", "merge-base", "HEAD", "master"], universal_newlines=True, encoding="utf8").rstrip("\n") + merge_base = check_output(["git", "merge-base", "HEAD", "master"], text=True, encoding="utf8").rstrip("\n") commit_range = merge_base + "..HEAD" else: commit_range = os.getenv("COMMIT_RANGE") + if commit_range == "SKIP_EMPTY_NOT_A_PR": + sys.exit(0) - commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], universal_newlines=True, encoding="utf8").splitlines() + commit_hashes = check_output(["git", "log", commit_range, "--format=%H"], text=True, encoding="utf8").splitlines() for hash in commit_hashes: - commit_info = check_output(["git", "log", "--format=%B", "-n", "1", hash], universal_newlines=True, encoding="utf8").splitlines() + commit_info = check_output(["git", "log", "--format=%B", "-n", "1", hash], text=True, encoding="utf8").splitlines() if len(commit_info) >= 2: if commit_info[1]: print(f"The subject line of commit hash {hash} is followed by a non-empty line. Subject lines should always be followed by a blank line.") diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py index b3fa4b9303..459030bb0b 100755 --- a/test/lint/lint-includes.py +++ b/test/lint/lint-includes.py @@ -35,13 +35,13 @@ EXPECTED_BOOST_INCLUDES = ["boost/date_time/posix_time/posix_time.hpp", def get_toplevel(): - return check_output(["git", "rev-parse", "--show-toplevel"], universal_newlines=True, encoding="utf8").rstrip("\n") + return check_output(["git", "rev-parse", "--show-toplevel"], text=True, encoding="utf8").rstrip("\n") def list_files_by_suffix(suffixes): exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS] - files_list = check_output(["git", "ls-files", "src"] + exclude_args, universal_newlines=True, encoding="utf8").splitlines() + files_list = check_output(["git", "ls-files", "src"] + exclude_args, text=True, encoding="utf8").splitlines() return [file for file in files_list if file.endswith(suffixes)] @@ -63,7 +63,7 @@ def find_included_cpps(): included_cpps = list() try: - included_cpps = check_output(["git", "grep", "-E", r"^#include [<\"][^>\"]+\.cpp[>\"]", "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8").splitlines() + included_cpps = check_output(["git", "grep", "-E", r"^#include [<\"][^>\"]+\.cpp[>\"]", "--", "*.cpp", "*.h"], text=True, encoding="utf8").splitlines() except CalledProcessError as e: if e.returncode > 1: raise e @@ -77,7 +77,7 @@ def find_extra_boosts(): exclusion_set = set() try: - included_boosts = check_output(["git", "grep", "-E", r"^#include <boost/", "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8").splitlines() + included_boosts = check_output(["git", "grep", "-E", r"^#include <boost/", "--", "*.cpp", "*.h"], text=True, encoding="utf8").splitlines() except CalledProcessError as e: if e.returncode > 1: raise e @@ -100,7 +100,7 @@ def find_quote_syntax_inclusions(): quote_syntax_inclusions = list() try: - quote_syntax_inclusions = check_output(["git", "grep", r"^#include \"", "--", "*.cpp", "*.h"] + exclude_args, universal_newlines=True, encoding="utf8").splitlines() + quote_syntax_inclusions = check_output(["git", "grep", r"^#include \"", "--", "*.cpp", "*.h"] + exclude_args, text=True, encoding="utf8").splitlines() except CalledProcessError as e: if e.returncode > 1: raise e @@ -143,13 +143,13 @@ def main(): if extra_boosts: for boost in extra_boosts: print(f"A new Boost dependency in the form of \"{boost}\" appears to have been introduced:") - print(check_output(["git", "grep", boost, "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8")) + print(check_output(["git", "grep", boost, "--", "*.cpp", "*.h"], text=True, encoding="utf8")) exit_code = 1 # Check if Boost dependencies are no longer used for expected_boost in EXPECTED_BOOST_INCLUDES: try: - check_output(["git", "grep", "-q", r"^#include <%s>" % expected_boost, "--", "*.cpp", "*.h"], universal_newlines=True, encoding="utf8") + check_output(["git", "grep", "-q", r"^#include <%s>" % expected_boost, "--", "*.cpp", "*.h"], text=True, encoding="utf8") except CalledProcessError as e: if e.returncode > 1: raise e diff --git a/test/lint/lint-locale-dependence.py b/test/lint/lint-locale-dependence.py index ce7444cd1a..c5cb34b20a 100755 --- a/test/lint/lint-locale-dependence.py +++ b/test/lint/lint-locale-dependence.py @@ -223,7 +223,7 @@ def find_locale_dependent_function_uses(): git_grep_output = list() try: - git_grep_output = check_output(git_grep_command, universal_newlines=True, encoding="utf8").splitlines() + git_grep_output = check_output(git_grep_command, text=True, encoding="utf8").splitlines() except CalledProcessError as e: if e.returncode > 1: raise e diff --git a/test/lint/lint-logs.py b/test/lint/lint-logs.py index aaf697467d..de04a1aeca 100755 --- a/test/lint/lint-logs.py +++ b/test/lint/lint-logs.py @@ -16,7 +16,7 @@ from subprocess import check_output def main(): - logs_list = check_output(["git", "grep", "--extended-regexp", r"(LogPrintLevel|LogPrintfCategory|LogPrintf?)\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines() + logs_list = check_output(["git", "grep", "--extended-regexp", r"(LogPrintLevel|LogPrintfCategory|LogPrintf?)\(", "--", "*.cpp"], text=True, encoding="utf8").splitlines() unterminated_logs = [line for line in logs_list if not re.search(r'(\\n"|/\* Continued \*/)', line)] diff --git a/test/lint/lint-python-mutable-default-parameters.py b/test/lint/lint-python-mutable-default-parameters.py index 7991e3630b..820595ea34 100755 --- a/test/lint/lint-python-mutable-default-parameters.py +++ b/test/lint/lint-python-mutable-default-parameters.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (c) 2019 The Bitcoin Core developers +# Copyright (c) 2019-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -21,7 +21,7 @@ def main(): "--", "*.py", ] - output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True) + output = subprocess.run(command, stdout=subprocess.PIPE, text=True) if len(output.stdout) > 0: error_msg = ( "A mutable list or dict seems to be used as default parameter value:\n\n" diff --git a/test/lint/lint-python-utf8-encoding.py b/test/lint/lint-python-utf8-encoding.py index 62fdc34d50..364da63468 100755 --- a/test/lint/lint-python-utf8-encoding.py +++ b/test/lint/lint-python-utf8-encoding.py @@ -23,7 +23,7 @@ def check_fileopens(): fileopens = list() try: - fileopens = check_output(["git", "grep", r" open(", "--", "*.py"] + get_exclude_args(), universal_newlines=True, encoding="utf8").splitlines() + fileopens = check_output(["git", "grep", r" open(", "--", "*.py"] + get_exclude_args(), text=True, encoding="utf8").splitlines() except CalledProcessError as e: if e.returncode > 1: raise e @@ -37,12 +37,12 @@ def check_checked_outputs(): checked_outputs = list() try: - checked_outputs = check_output(["git", "grep", "check_output(", "--", "*.py"] + get_exclude_args(), universal_newlines=True, encoding="utf8").splitlines() + checked_outputs = check_output(["git", "grep", "check_output(", "--", "*.py"] + get_exclude_args(), text=True, encoding="utf8").splitlines() except CalledProcessError as e: if e.returncode > 1: raise e - filtered_checked_outputs = [checked_output for checked_output in checked_outputs if re.search(r"universal_newlines=True", checked_output) and not re.search(r"encoding=.(ascii|utf8|utf-8).", checked_output)] + filtered_checked_outputs = [checked_output for checked_output in checked_outputs if re.search(r"text=True", checked_output) and not re.search(r"encoding=.(ascii|utf8|utf-8).", checked_output)] return filtered_checked_outputs diff --git a/test/lint/lint-shell.py b/test/lint/lint-shell.py index ed95024ef5..1646bf0d3e 100755 --- a/test/lint/lint-shell.py +++ b/test/lint/lint-shell.py @@ -25,7 +25,7 @@ def check_shellcheck_install(): sys.exit(0) def get_files(command): - output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True) + output = subprocess.run(command, stdout=subprocess.PIPE, text=True) files = output.stdout.split('\n') # remove whitespace element diff --git a/test/lint/lint-spelling.py b/test/lint/lint-spelling.py index 14d7d13a75..ac0bddeaa6 100755 --- a/test/lint/lint-spelling.py +++ b/test/lint/lint-spelling.py @@ -12,7 +12,7 @@ Note: Will exit successfully regardless of spelling errors. from subprocess import check_output, STDOUT, CalledProcessError IGNORE_WORDS_FILE = 'test/lint/spelling.ignore-words.txt' -FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/leveldb/", ":(exclude)src/crc32c/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)src/secp256k1/", ":(exclude)src/minisketch/", ":(exclude)contrib/builder-keys/keys.txt", ":(exclude)contrib/guix/patches"] +FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/leveldb/", ":(exclude)src/crc32c/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)src/secp256k1/", ":(exclude)src/minisketch/", ":(exclude)contrib/guix/patches"] def check_codespell_install(): diff --git a/test/lint/lint-submodule.py b/test/lint/lint-submodule.py index 89d4c80f55..4d2fbf088f 100755 --- a/test/lint/lint-submodule.py +++ b/test/lint/lint-submodule.py @@ -13,7 +13,7 @@ import sys def main(): submodules_list = subprocess.check_output(['git', 'submodule', 'status', '--recursive'], - universal_newlines = True, encoding = 'utf8').rstrip('\n') + text = True, encoding = 'utf8').rstrip('\n') if submodules_list: print("These submodules were found, delete them:\n", submodules_list) sys.exit(1) diff --git a/test/lint/lint-tests.py b/test/lint/lint-tests.py index 849ddcb961..1eeb7bb014 100755 --- a/test/lint/lint-tests.py +++ b/test/lint/lint-tests.py @@ -23,7 +23,7 @@ def grep_boost_fixture_test_suite(): "src/test/**.cpp", "src/wallet/test/**.cpp", ] - return subprocess.check_output(command, universal_newlines=True, encoding="utf8") + return subprocess.check_output(command, text=True, encoding="utf8") def check_matching_test_names(test_suite_list): diff --git a/test/lint/lint-whitespace.py b/test/lint/lint-whitespace.py index 3fb5b80013..f5e4a776d0 100755 --- a/test/lint/lint-whitespace.py +++ b/test/lint/lint-whitespace.py @@ -80,7 +80,7 @@ def get_diff(commit_range, check_only_code): else: what_files = ["."] - diff = check_output(["git", "diff", "-U0", commit_range, "--"] + what_files + exclude_args, universal_newlines=True, encoding="utf8") + diff = check_output(["git", "diff", "-U0", commit_range, "--"] + what_files + exclude_args, text=True, encoding="utf8") return diff @@ -93,10 +93,12 @@ def main(): commit_range = "HEAD~" + args.prev_commits + "...HEAD" else: # This assumes that the target branch of the pull request will be master. - merge_base = check_output(["git", "merge-base", "HEAD", "master"], universal_newlines=True, encoding="utf8").rstrip("\n") + merge_base = check_output(["git", "merge-base", "HEAD", "master"], text=True, encoding="utf8").rstrip("\n") commit_range = merge_base + "..HEAD" else: commit_range = os.getenv("COMMIT_RANGE") + if commit_range == "SKIP_EMPTY_NOT_A_PR": + sys.exit(0) whitespace_selection = [] tab_selection = [] diff --git a/test/lint/run-lint-format-strings.py b/test/lint/run-lint-format-strings.py index b814446125..57eefb00f2 100755 --- a/test/lint/run-lint-format-strings.py +++ b/test/lint/run-lint-format-strings.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (c) 2018-2019 The Bitcoin Core developers +# Copyright (c) 2018-2022 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # diff --git a/test/lint/spelling.ignore-words.txt b/test/lint/spelling.ignore-words.txt index 82f18010c1..d44dd70684 100644 --- a/test/lint/spelling.ignore-words.txt +++ b/test/lint/spelling.ignore-words.txt @@ -4,6 +4,7 @@ blockin bu cachable clen +crypted fo fpr hights diff --git a/test/util/test_runner.py b/test/util/test_runner.py index 03db05c563..ea3626fa65 100755 --- a/test/util/test_runner.py +++ b/test/util/test_runner.py @@ -107,7 +107,7 @@ def bctest(testDir, testObj, buildenv): raise Exception # Run the test - proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) try: outs = proc.communicate(input=inputData) except OSError: |