aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rwxr-xr-xcontrib/guix/guix-build10
-rwxr-xr-xcontrib/guix/guix-codesign392
-rwxr-xr-xcontrib/guix/libexec/codesign.sh103
-rw-r--r--contrib/guix/manifest.scm430
-rw-r--r--contrib/guix/patches/gcc-8-sort-libtool-find-output.patch392
-rw-r--r--contrib/guix/patches/oscrypto-hard-code-openssl.patch13
-rwxr-xr-xcontrib/windeploy/detached-sig-create.sh2
-rw-r--r--src/addrdb.cpp4
-rw-r--r--src/index/blockfilterindex.cpp2
-rw-r--r--src/index/coinstatsindex.cpp2
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp11
-rw-r--r--src/init/common.cpp2
-rw-r--r--src/net.cpp14
-rw-r--r--src/net.h78
-rw-r--r--src/net_processing.cpp296
-rw-r--r--src/policy/feerate.cpp21
-rw-r--r--src/policy/feerate.h11
-rw-r--r--src/policy/fees.cpp4
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/clientmodel.cpp2
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/intro.h2
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/qt/paymentserver.cpp4
-rw-r--r--src/qt/test/apptests.cpp2
-rw-r--r--src/rpc/blockchain.cpp4
-rw-r--r--src/test/amount_tests.cpp2
-rw-r--r--src/test/dbwrapper_tests.cpp18
-rw-r--r--src/test/denialofservice_tests.cpp4
-rw-r--r--src/test/flatfile_tests.cpp8
-rw-r--r--src/test/fs_tests.cpp2
-rw-r--r--src/test/fuzz/banman.cpp2
-rw-r--r--src/test/fuzz/connman.cpp3
-rw-r--r--src/test/fuzz/fee_rate.cpp4
-rw-r--r--src/test/fuzz/i2p.cpp2
-rw-r--r--src/test/fuzz/net.cpp22
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp2
-rw-r--r--src/test/i2p_tests.cpp2
-rw-r--r--src/test/settings_tests.cpp2
-rw-r--r--src/test/util/setup_common.cpp2
-rw-r--r--src/test/util_tests.cpp20
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/util/system.cpp25
-rw-r--r--src/util/system.h27
-rw-r--r--src/validation.cpp10
-rw-r--r--src/validation.h2
-rw-r--r--src/wallet/rpcwallet.cpp16
-rw-r--r--src/wallet/test/db_tests.cpp12
-rw-r--r--src/wallet/test/init_test_fixture.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp2
-rw-r--r--src/wallet/walletutil.cpp2
-rwxr-xr-xtest/functional/feature_cltv.py7
-rwxr-xr-xtest/functional/feature_csv_activation.py21
-rwxr-xr-xtest/functional/feature_includeconf.py9
-rw-r--r--test/functional/test_framework/wallet.py64
58 files changed, 1688 insertions, 421 deletions
diff --git a/Makefile.am b/Makefile.am
index 5e453b9ae1..d84dab1842 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -149,7 +149,7 @@ $(APP_DIST_DIR)/Applications:
$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt
$(OSX_TEMP_ISO): $(APP_DIST_EXTRAS)
- $(XORRISOFS) -D -l -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -o $@ dist -- $(if $(SOURCE_DATE_EPOCH),-volume_date all_file_dates =$(SOURCE_DATE_EPOCH))
+ $(XORRISOFS) -D -l -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -o $@ $(APP_DIST_DIR) -- $(if $(SOURCE_DATE_EPOCH),-volume_date all_file_dates =$(SOURCE_DATE_EPOCH))
$(OSX_DMG): $(OSX_TEMP_ISO)
$(DMG) dmg "$<" "$@"
diff --git a/contrib/guix/guix-build b/contrib/guix/guix-build
index 5b3c20b234..69c244a6fa 100755
--- a/contrib/guix/guix-build
+++ b/contrib/guix/guix-build
@@ -267,20 +267,20 @@ for host in $HOSTS; do
make -C "${PWD}/depends" -j"$JOBS" download-"$(host_to_commonname "$host")" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"}
done
-# Usage: outdir_for_host HOST
+# Usage: outdir_for_host HOST SUFFIX
#
# HOST: The current platform triple we're building for
#
outdir_for_host() {
- echo "${OUTDIR_BASE}/${1}"
+ echo "${OUTDIR_BASE}/${1}${2:+-${2}}"
}
-# Usage: profiledir_for_host HOST COMMAND
+# Usage: profiledir_for_host HOST SUFFIX
#
# HOST: The current platform triple we're building for
#
profiledir_for_host() {
- echo "${PROFILES_BASE}/${2}-${1}"
+ echo "${PROFILES_BASE}/${1}${2:+-${2}}"
}
@@ -412,7 +412,7 @@ EOF
--keep-failed \
--fallback \
--link-profile \
- --root="$(profiledir_for_host "${HOST}" build)" \
+ --root="$(profiledir_for_host "${HOST}")" \
${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
-- env HOST="$host" \
diff --git a/contrib/guix/guix-codesign b/contrib/guix/guix-codesign
new file mode 100755
index 0000000000..62853dbf4d
--- /dev/null
+++ b/contrib/guix/guix-codesign
@@ -0,0 +1,392 @@
+#!/usr/bin/env bash
+export LC_ALL=C
+set -e -o pipefail
+
+# Source the common prelude, which:
+# 1. Checks if we're at the top directory of the Bitcoin Core repository
+# 2. Defines a few common functions and variables
+#
+# shellcheck source=libexec/prelude.bash
+source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
+
+
+###################
+## SANITY CHECKS ##
+###################
+
+################
+# Required non-builtin commands should be invocable
+################
+
+check_tools cat mkdir git guix
+
+################
+# Required env vars should be non-empty
+################
+
+cmd_usage() {
+ cat <<EOF
+Synopsis:
+
+ env DETACHED_SIGS_REPO=<path/to/bitcoin-detached-sigs> \\
+ ./contrib/guix/guix-codesign
+
+EOF
+}
+
+if [ -z "$DETACHED_SIGS_REPO" ]; then
+ cmd_usage
+ exit 1
+fi
+
+################
+# GUIX_BUILD_OPTIONS should be empty
+################
+#
+# GUIX_BUILD_OPTIONS is an environment variable recognized by guix commands that
+# can perform builds. This seems like what we want instead of
+# ADDITIONAL_GUIX_COMMON_FLAGS, but the value of GUIX_BUILD_OPTIONS is actually
+# _appended_ to normal command-line options. Meaning that they will take
+# precedence over the command-specific ADDITIONAL_GUIX_<CMD>_FLAGS.
+#
+# This seems like a poor user experience. Thus we check for GUIX_BUILD_OPTIONS's
+# existence here and direct users of this script to use our (more flexible)
+# custom environment variables.
+if [ -n "$GUIX_BUILD_OPTIONS" ]; then
+cat << EOF
+Error: Environment variable GUIX_BUILD_OPTIONS is not empty:
+ '$GUIX_BUILD_OPTIONS'
+
+Unfortunately this script is incompatible with GUIX_BUILD_OPTIONS, please unset
+GUIX_BUILD_OPTIONS and use ADDITIONAL_GUIX_COMMON_FLAGS to set build options
+across guix commands or ADDITIONAL_GUIX_<CMD>_FLAGS to set build options for a
+specific guix command.
+
+See contrib/guix/README.md for more details.
+EOF
+exit 1
+fi
+
+################
+# The codesignature git worktree should not be dirty
+################
+
+if ! git -C "$DETACHED_SIGS_REPO" diff-index --quiet HEAD -- && [ -z "$FORCE_DIRTY_WORKTREE" ]; then
+ cat << EOF
+ERR: The DETACHED CODESIGNATURE git worktree is dirty, which may lead to broken builds.
+
+ Aborting...
+
+Hint: To make your git worktree clean, You may want to:
+ 1. Commit your changes,
+ 2. Stash your changes, or
+ 3. Set the 'FORCE_DIRTY_WORKTREE' environment variable if you insist on
+ using a dirty worktree
+EOF
+ exit 1
+fi
+
+################
+# Build directories should not exist
+################
+
+# Default to building for all supported HOSTs (overridable by environment)
+export HOSTS="${HOSTS:-x86_64-w64-mingw32 x86_64-apple-darwin18}"
+
+# Usage: distsrc_for_host HOST
+#
+# HOST: The current platform triple we're building for
+#
+distsrc_for_host() {
+ echo "${DISTSRC_BASE}/distsrc-${VERSION}-${1}-codesigned"
+}
+
+# Accumulate a list of build directories that already exist...
+hosts_distsrc_exists=""
+for host in $HOSTS; do
+ if [ -e "$(distsrc_for_host "$host")" ]; then
+ hosts_distsrc_exists+=" ${host}"
+ fi
+done
+
+if [ -n "$hosts_distsrc_exists" ]; then
+# ...so that we can print them out nicely in an error message
+cat << EOF
+ERR: Build directories for this commit already exist for the following platform
+ triples you're attempting to build, probably because of previous builds.
+ Please remove, or otherwise deal with them prior to starting another build.
+
+ Aborting...
+
+Hint: To blow everything away, you may want to use:
+
+ $ ./contrib/guix/guix-clean
+
+Specifically, this will remove all files without an entry in the index,
+excluding the SDK directory, the depends download cache, the depends built
+packages cache, the garbage collector roots for Guix environments, and the
+output directory.
+EOF
+for host in $hosts_distsrc_exists; do
+ echo " ${host} '$(distsrc_for_host "$host")'"
+done
+exit 1
+else
+ mkdir -p "$DISTSRC_BASE"
+fi
+
+
+################
+# Unsigned tarballs SHOULD exist
+################
+
+# Usage: outdir_for_host HOST SUFFIX
+#
+# HOST: The current platform triple we're building for
+#
+outdir_for_host() {
+ echo "${OUTDIR_BASE}/${1}${2:+-${2}}"
+}
+
+
+unsigned_tarball_for_host() {
+ case "$1" in
+ *mingw*)
+ echo "$(outdir_for_host "$1")/${DISTNAME}-win-unsigned.tar.gz"
+ ;;
+ *darwin*)
+ echo "$(outdir_for_host "$1")/${DISTNAME}-osx-unsigned.tar.gz"
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+}
+
+# Accumulate a list of build directories that already exist...
+hosts_unsigned_tarball_missing=""
+for host in $HOSTS; do
+ if [ ! -e "$(unsigned_tarball_for_host "$host")" ]; then
+ hosts_unsigned_tarball_missing+=" ${host}"
+ fi
+done
+
+if [ -n "$hosts_unsigned_tarball_missing" ]; then
+ # ...so that we can print them out nicely in an error message
+ cat << EOF
+ERR: Unsigned tarballs do not exist
+...
+
+EOF
+for host in $hosts_unsigned_tarball_missing; do
+ echo " ${host} '$(unsigned_tarball_for_host "$host")'"
+done
+exit 1
+fi
+
+################
+# Check that we can connect to the guix-daemon
+################
+
+cat << EOF
+Checking that we can connect to the guix-daemon...
+
+Hint: If this hangs, you may want to try turning your guix-daemon off and on
+ again.
+
+EOF
+if ! guix gc --list-failures > /dev/null; then
+ cat << EOF
+
+ERR: Failed to connect to the guix-daemon, please ensure that one is running and
+ reachable.
+EOF
+ exit 1
+fi
+
+# Developer note: we could use `guix repl` for this check and run:
+#
+# (import (guix store)) (close-connection (open-connection))
+#
+# However, the internal API is likely to change more than the CLI invocation
+
+
+#########
+# SETUP #
+#########
+
+# Determine the maximum number of jobs to run simultaneously (overridable by
+# environment)
+JOBS="${JOBS:-$(nproc)}"
+
+# Determine the reference time used for determinism (overridable by environment)
+SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log --format=%at -1)}"
+
+# Execute "$@" in a pinned, possibly older version of Guix, for reproducibility
+# across time.
+time-machine() {
+ # shellcheck disable=SC2086
+ guix time-machine --url=https://github.com/dongcarl/guix.git \
+ --commit=490e39ff303f4f6873a04bfb8253755bdae1b29c \
+ --cores="$JOBS" \
+ --keep-failed \
+ --fallback \
+ ${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
+ ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_TIMEMACHINE_FLAGS} \
+ -- "$@"
+}
+
+# Make sure an output directory exists for our builds
+OUTDIR_BASE="${OUTDIR_BASE:-${VERSION_BASE}/output}"
+mkdir -p "$OUTDIR_BASE"
+
+# Usage: profiledir_for_host HOST SUFFIX
+#
+# HOST: The current platform triple we're building for
+#
+profiledir_for_host() {
+ echo "${PROFILES_BASE}/${1}${2:+-${2}}"
+}
+
+#########
+# BUILD #
+#########
+
+# Function to be called when codesigning for host ${1} and the user interrupts
+# the codesign
+int_trap() {
+cat << EOF
+** INT received while codesigning ${1}, you may want to clean up the relevant
+ work directories (e.g. distsrc-*) before recodesigning
+
+Hint: To blow everything away, you may want to use:
+
+ $ ./contrib/guix/guix-clean
+
+Specifically, this will remove all files without an entry in the index,
+excluding the SDK directory, the depends download cache, the depends built
+packages cache, the garbage collector roots for Guix environments, and the
+output directory.
+EOF
+}
+
+# Deterministically build Bitcoin Core
+# shellcheck disable=SC2153
+for host in $HOSTS; do
+
+ # Display proper warning when the user interrupts the build
+ trap 'int_trap ${host}' INT
+
+ (
+ # Required for 'contrib/guix/manifest.scm' to output the right manifest
+ # for the particular $HOST we're building for
+ export HOST="$host"
+
+ # shellcheck disable=SC2030
+cat << EOF
+INFO: Codesigning ${VERSION:?not set} for platform triple ${HOST:?not set}:
+ ...using reference timestamp: ${SOURCE_DATE_EPOCH:?not set}
+ ...from worktree directory: '${PWD}'
+ ...bind-mounted in container to: '/bitcoin'
+ ...in build directory: '$(distsrc_for_host "$HOST")'
+ ...bind-mounted in container to: '$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")'
+ ...outputting in: '$(outdir_for_host "$HOST" codesigned)'
+ ...bind-mounted in container to: '$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST" codesigned)'
+ ...using detached signatures in: '${DETACHED_SIGS_REPO:?not set}'
+ ...bind-mounted in container to: '/detached-sigs'
+EOF
+
+
+ # Run the build script 'contrib/guix/libexec/build.sh' in the build
+ # container specified by 'contrib/guix/manifest.scm'.
+ #
+ # Explanation of `guix environment` flags:
+ #
+ # --container run command within an isolated container
+ #
+ # Running in an isolated container minimizes build-time differences
+ # between machines and improves reproducibility
+ #
+ # --pure unset existing environment variables
+ #
+ # Same rationale as --container
+ #
+ # --no-cwd do not share current working directory with an
+ # isolated container
+ #
+ # When --container is specified, the default behavior is to share
+ # the current working directory with the isolated container at the
+ # same exact path (e.g. mapping '/home/satoshi/bitcoin/' to
+ # '/home/satoshi/bitcoin/'). This means that the $PWD inside the
+ # container becomes a source of irreproducibility. --no-cwd disables
+ # this behaviour.
+ #
+ # --share=SPEC for containers, share writable host file system
+ # according to SPEC
+ #
+ # --share="$PWD"=/bitcoin
+ #
+ # maps our current working directory to /bitcoin
+ # inside the isolated container, which we later cd
+ # into.
+ #
+ # While we don't want to map our current working directory to the
+ # same exact path (as this introduces irreproducibility), we do want
+ # it to be at a _fixed_ path _somewhere_ inside the isolated
+ # container so that we have something to build. '/bitcoin' was
+ # chosen arbitrarily.
+ #
+ # ${SOURCES_PATH:+--share="$SOURCES_PATH"}
+ #
+ # make the downloaded depends sources path available
+ # inside the isolated container
+ #
+ # The isolated container has no network access as it's in a
+ # different network namespace from the main machine, so we have to
+ # make the downloaded depends sources available to it. The sources
+ # should have been downloaded prior to this invocation.
+ #
+ # ${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"}
+ #
+ # fetch substitute from SUBSTITUTE_URLS if they are
+ # authorized
+ #
+ # Depending on the user's security model, it may be desirable to use
+ # substitutes (pre-built packages) from servers that the user trusts.
+ # Please read the README.md in the same directory as this file for
+ # more information.
+ #
+ # shellcheck disable=SC2086,SC2031
+ time-machine environment --manifest="${PWD}/contrib/guix/manifest.scm" \
+ --container \
+ --pure \
+ --no-cwd \
+ --share="$PWD"=/bitcoin \
+ --share="$DISTSRC_BASE"=/distsrc-base \
+ --share="$OUTDIR_BASE"=/outdir-base \
+ --share="$DETACHED_SIGS_REPO"=/detached-sigs \
+ --expose="$(git rev-parse --git-common-dir)" \
+ --expose="$(git -C "$DETACHED_SIGS_REPO" rev-parse --git-common-dir)" \
+ ${SOURCES_PATH:+--share="$SOURCES_PATH"} \
+ --cores="$JOBS" \
+ --keep-failed \
+ --fallback \
+ --link-profile \
+ --root="$(profiledir_for_host "${HOST}" codesigned)" \
+ ${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
+ ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
+ -- env HOST="$host" \
+ DISTNAME="$DISTNAME" \
+ JOBS="$JOBS" \
+ SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:?unable to determine value}" \
+ ${V:+V=1} \
+ ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"} \
+ DISTSRC="$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")" \
+ OUTDIR="$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST" codesigned)" \
+ DIST_ARCHIVE_BASE=/outdir-base/dist-archive \
+ DETACHED_SIGS_REPO=/detached-sigs \
+ UNSIGNED_TARBALL="$(OUTDIR_BASE=/outdir-base && unsigned_tarball_for_host "$HOST")" \
+ bash -c "cd /bitcoin && bash contrib/guix/libexec/codesign.sh"
+ )
+
+done
diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh
new file mode 100755
index 0000000000..46b42a5712
--- /dev/null
+++ b/contrib/guix/libexec/codesign.sh
@@ -0,0 +1,103 @@
+#!/usr/bin/env bash
+export LC_ALL=C
+set -e -o pipefail
+export TZ=UTC
+
+# Although Guix _does_ set umask when building its own packages (in our case,
+# this is all packages in manifest.scm), it does not set it for `guix
+# environment`. It does make sense for at least `guix environment --container`
+# to set umask, so if that change gets merged upstream and we bump the
+# time-machine to a commit which includes the aforementioned change, we can
+# remove this line.
+#
+# This line should be placed before any commands which creates files.
+umask 0022
+
+if [ -n "$V" ]; then
+ # Print both unexpanded (-v) and expanded (-x) forms of commands as they are
+ # read from this file.
+ set -vx
+ # Set VERBOSE for CMake-based builds
+ export VERBOSE="$V"
+fi
+
+# Check that required environment variables are set
+cat << EOF
+Required environment variables as seen inside the container:
+ UNSIGNED_TARBALL: ${UNSIGNED_TARBALL:?not set}
+ DETACHED_SIGS_REPO: ${DETACHED_SIGS_REPO:?not set}
+ DIST_ARCHIVE_BASE: ${DIST_ARCHIVE_BASE:?not set}
+ DISTNAME: ${DISTNAME:?not set}
+ HOST: ${HOST:?not set}
+ SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:?not set}
+ DISTSRC: ${DISTSRC:?not set}
+ OUTDIR: ${OUTDIR:?not set}
+EOF
+
+ACTUAL_OUTDIR="${OUTDIR}"
+OUTDIR="${DISTSRC}/output"
+
+git_head_version() {
+ local recent_tag
+ if recent_tag="$(git -C "$1" describe --exact-match HEAD 2> /dev/null)"; then
+ echo "${recent_tag#v}"
+ else
+ git -C "$1" rev-parse --short=12 HEAD
+ fi
+}
+
+CODESIGNATURE_GIT_ARCHIVE="${DIST_ARCHIVE_BASE}/${DISTNAME}-codesignatures-$(git_head_version "$DETACHED_SIGS_REPO").tar.gz"
+
+# Create the codesignature tarball if not already there
+if [ ! -e "$CODESIGNATURE_GIT_ARCHIVE" ]; then
+ mkdir -p "$(dirname "$CODESIGNATURE_GIT_ARCHIVE")"
+ git -C "$DETACHED_SIGS_REPO" archive --output="$CODESIGNATURE_GIT_ARCHIVE" HEAD
+fi
+
+mkdir -p "$OUTDIR"
+cat << EOF > "$OUTDIR"/inputs.SHA256SUMS
+$(sha256sum "$UNSIGNED_TARBALL" | cut -d' ' -f1) inputs/$(basename "$UNSIGNED_TARBALL")
+$(sha256sum "$CODESIGNATURE_GIT_ARCHIVE" | cut -d' ' -f1) inputs/$(basename "$CODESIGNATURE_GIT_ARCHIVE")
+EOF
+
+mkdir -p "$DISTSRC"
+(
+ cd "$DISTSRC"
+
+ tar -xf "$UNSIGNED_TARBALL"
+
+ mkdir -p codesignatures
+ tar -C codesignatures -xf "$CODESIGNATURE_GIT_ARCHIVE"
+
+ case "$HOST" in
+ *mingw*)
+ find "$PWD" -name "*-unsigned.exe" | while read -r infile; do
+ infile_base="$(basename "$infile")"
+
+ # Codesigned *-unsigned.exe and output to OUTDIR
+ osslsigncode attach-signature \
+ -in "$infile" \
+ -out "${OUTDIR}/${infile_base/-unsigned}" \
+ -sigin codesignatures/win/"$infile_base".pem
+ done
+ ;;
+ *darwin*)
+ # Apply detached codesignatures to dist/ (in-place)
+ signapple apply dist/Bitcoin-Qt.app codesignatures/osx/dist
+
+ # Make an uncompressed DMG from dist/
+ xorrisofs -D -l -V "$(< osx_volname)" -no-pad -r -dir-mode 0755 \
+ -o uncompressed.dmg \
+ dist \
+ -- -volume_date all_file_dates ="$SOURCE_DATE_EPOCH"
+
+ # Compress uncompressed.dmg and output to OUTDIR
+ ./dmg dmg uncompressed.dmg "${OUTDIR}/${DISTNAME}-osx-signed.dmg"
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+) # $DISTSRC
+
+mv --no-target-directory "$OUTDIR" "$ACTUAL_OUTDIR"
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index f98f2b9422..d2bc789b60 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -4,12 +4,14 @@
(gnu packages base)
(gnu packages bash)
(gnu packages bison)
+ (gnu packages certs)
(gnu packages cdrom)
(gnu packages check)
(gnu packages cmake)
(gnu packages commencement)
(gnu packages compression)
(gnu packages cross-base)
+ (gnu packages curl)
(gnu packages file)
(gnu packages gawk)
(gnu packages gcc)
@@ -23,7 +25,9 @@
(gnu packages perl)
(gnu packages pkg-config)
(gnu packages python)
+ (gnu packages python-web)
(gnu packages shells)
+ (gnu packages tls)
(gnu packages version-control)
(guix build-system font)
(guix build-system gnu)
@@ -52,28 +56,28 @@ we link against libssp.so, and thus will ensure that this works properly.
Taken from:
http://www.linuxfromscratch.org/hlfs/view/development/chapter05/gcc-pass1.html"
(package
- (inherit xgcc)
- (arguments
- (substitute-keyword-arguments (package-arguments xgcc)
- ((#:make-flags flags)
- `(cons "gcc_cv_libc_provides_ssp=yes" ,flags))))))
+ (inherit xgcc)
+ (arguments
+ (substitute-keyword-arguments (package-arguments xgcc)
+ ((#:make-flags flags)
+ `(cons "gcc_cv_libc_provides_ssp=yes" ,flags))))))
(define (make-gcc-rpath-link xgcc)
"Given a XGCC package, return a modified package that replace each instance of
-rpath in the default system spec that's inserted by Guix with -rpath-link"
(package
- (inherit xgcc)
- (arguments
- (substitute-keyword-arguments (package-arguments xgcc)
- ((#:phases phases)
- `(modify-phases ,phases
- (add-after 'pre-configure 'replace-rpath-with-rpath-link
- (lambda _
- (substitute* (cons "gcc/config/rs6000/sysv4.h"
- (find-files "gcc/config"
- "^gnu-user.*\\.h$"))
- (("-rpath=") "-rpath-link="))
- #t))))))))
+ (inherit xgcc)
+ (arguments
+ (substitute-keyword-arguments (package-arguments xgcc)
+ ((#:phases phases)
+ `(modify-phases ,phases
+ (add-after 'pre-configure 'replace-rpath-with-rpath-link
+ (lambda _
+ (substitute* (cons "gcc/config/rs6000/sysv4.h"
+ (find-files "gcc/config"
+ "^gnu-user.*\\.h$"))
+ (("-rpath=") "-rpath-link="))
+ #t))))))))
(define (make-cross-toolchain target
base-gcc-for-libc
@@ -126,19 +130,23 @@ chain for " target " development."))
(home-page (package-home-page xgcc))
(license (package-license xgcc)))))
+(define base-gcc
+ (package-with-extra-patches gcc-8
+ (search-our-patches "gcc-8-sort-libtool-find-output.patch")))
+
(define* (make-bitcoin-cross-toolchain target
- #:key
- (base-gcc-for-libc gcc-7)
- (base-kernel-headers linux-libre-headers-5.4)
- (base-libc glibc) ; glibc 2.31
- (base-gcc (make-gcc-rpath-link gcc-8)))
+ #:key
+ (base-gcc-for-libc gcc-7)
+ (base-kernel-headers linux-libre-headers-5.4)
+ (base-libc glibc) ; glibc 2.31
+ (base-gcc (make-gcc-rpath-link base-gcc)))
"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values
desirable for building Bitcoin Core release binaries."
(make-cross-toolchain target
- base-gcc-for-libc
- base-kernel-headers
- base-libc
- base-gcc))
+ base-gcc-for-libc
+ base-kernel-headers
+ base-libc
+ base-gcc))
(define (make-gcc-with-pthreads gcc)
(package-with-extra-configure-variable gcc "--enable-threads" "posix"))
@@ -149,7 +157,7 @@ desirable for building Bitcoin Core release binaries."
(pthreads-xlibc mingw-w64-x86_64-winpthreads)
(pthreads-xgcc (make-gcc-with-pthreads
(cross-gcc target
- #:xgcc (make-ssp-fixed-gcc gcc-8)
+ #:xgcc (make-ssp-fixed-gcc base-gcc)
#:xbinutils xbinutils
#:libc pthreads-xlibc))))
;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and
@@ -177,22 +185,22 @@ chain for " target " development."))
(define-public font-tuffy
(package
- (name "font-tuffy")
- (version "20120614")
- (source
- (origin
- (method url-fetch)
- (uri (string-append "http://tulrich.com/fonts/tuffy-" version ".tar.gz"))
- (file-name (string-append name "-" version ".tar.gz"))
- (sha256
- (base32
- "02vf72bgrp30vrbfhxjw82s115z27dwfgnmmzfb0n9wfhxxfpyf6"))))
- (build-system font-build-system)
- (home-page "http://tulrich.com/fonts/")
- (synopsis "The Tuffy Truetype Font Family")
- (description
- "Thatcher Ulrich's first outline font design. He started with the goal of producing a neutral, readable sans-serif text font. There are lots of \"expressive\" fonts out there, but he wanted to start with something very plain and clean, something he might want to actually use. ")
- (license license:public-domain)))
+ (name "font-tuffy")
+ (version "20120614")
+ (source
+ (origin
+ (method url-fetch)
+ (uri (string-append "http://tulrich.com/fonts/tuffy-" version ".tar.gz"))
+ (file-name (string-append name "-" version ".tar.gz"))
+ (sha256
+ (base32
+ "02vf72bgrp30vrbfhxjw82s115z27dwfgnmmzfb0n9wfhxxfpyf6"))))
+ (build-system font-build-system)
+ (home-page "http://tulrich.com/fonts/")
+ (synopsis "The Tuffy Truetype Font Family")
+ (description
+ "Thatcher Ulrich's first outline font design. He started with the goal of producing a neutral, readable sans-serif text font. There are lots of \"expressive\" fonts out there, but he wanted to start with something very plain and clean, something he might want to actually use. ")
+ (license license:public-domain)))
(define-public lief
(package
@@ -217,6 +225,337 @@ chain for " target " development."))
parse, modify and abstract ELF, PE and MachO formats.")
(license license:asl2.0)))
+(define osslsigncode
+ (package
+ (name "osslsigncode")
+ (version "2.0")
+ (source (origin
+ (method url-fetch)
+ (uri (string-append "https://github.com/mtrojnar/"
+ name "/archive/" version ".tar.gz"))
+ (sha256
+ (base32
+ "0byri6xny770wwb2nciq44j5071122l14bvv65axdd70nfjf0q2s"))))
+ (build-system gnu-build-system)
+ (native-inputs
+ `(("pkg-config" ,pkg-config)
+ ("autoconf" ,autoconf)
+ ("automake" ,automake)
+ ("libtool" ,libtool)))
+ (inputs
+ `(("openssl" ,openssl)))
+ (arguments
+ `(#:configure-flags
+ `("--without-gsf"
+ "--without-curl"
+ "--disable-dependency-tracking")))
+ (home-page "https://github.com/mtrojnar/osslsigncode")
+ (synopsis "Authenticode signing and timestamping tool")
+ (description "osslsigncode is a small tool that implements part of the
+functionality of the Microsoft tool signtool.exe - more exactly the Authenticode
+signing and timestamping. But osslsigncode is based on OpenSSL and cURL, and
+thus should be able to compile on most platforms where these exist.")
+ (license license:gpl3+))) ; license is with openssl exception
+
+(define-public python-asn1crypto
+ (package
+ (name "python-asn1crypto")
+ (version "1.4.0")
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/wbond/asn1crypto")
+ (commit version)))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "19abibn6jw20mzi1ln4n9jjvpdka8ygm4m439hplyrdfqbvgm01r"))))
+ (build-system python-build-system)
+ (arguments
+ '(#:phases
+ (modify-phases %standard-phases
+ (replace 'check
+ (lambda _
+ (invoke "python" "run.py" "tests"))))))
+ (home-page "https://github.com/wbond/asn1crypto")
+ (synopsis "ASN.1 parser and serializer in Python")
+ (description "asn1crypto is an ASN.1 parser and serializer with definitions
+for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7,
+PKCS#8, PKCS#12, PKCS#5, X.509 and TSP.")
+ (license license:expat)))
+
+(define-public python-elfesteem
+ (let ((commit "87bbd79ab7e361004c98cc8601d4e5f029fd8bd5"))
+ (package
+ (name "python-elfesteem")
+ (version (git-version "0.1" "1" commit))
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/LRGH/elfesteem")
+ (commit commit)))
+ (file-name (git-file-name name commit))
+ (sha256
+ (base32
+ "1nyvjisvyxyxnd0023xjf5846xd03lwawp5pfzr8vrky7wwm5maz"))))
+ (build-system python-build-system)
+ ;; There are no tests, but attempting to run python setup.py test leads to
+ ;; PYTHONPATH problems, just disable the test
+ (arguments '(#:tests? #f))
+ (home-page "https://github.com/LRGH/elfesteem")
+ (synopsis "ELF/PE/Mach-O parsing library")
+ (description "elfesteem parses ELF, PE and Mach-O files.")
+ (license license:lgpl2.1))))
+
+(define-public python-oscrypto
+ (package
+ (name "python-oscrypto")
+ (version "1.2.1")
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/wbond/oscrypto")
+ (commit version)))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "1d4d8s4z340qhvb3g5m5v3436y3a71yc26wk4749q64m09kxqc3l"))
+ (patches (search-our-patches "oscrypto-hard-code-openssl.patch"))))
+ (build-system python-build-system)
+ (native-search-paths
+ (list (search-path-specification
+ (variable "SSL_CERT_FILE")
+ (file-type 'regular)
+ (separator #f) ;single entry
+ (files '("etc/ssl/certs/ca-certificates.crt")))))
+
+ (propagated-inputs
+ `(("python-asn1crypto" ,python-asn1crypto)
+ ("openssl" ,openssl)))
+ (arguments
+ `(#:phases
+ (modify-phases %standard-phases
+ (add-after 'unpack 'hard-code-path-to-libscrypt
+ (lambda* (#:key inputs #:allow-other-keys)
+ (let ((openssl (assoc-ref inputs "openssl")))
+ (substitute* "oscrypto/__init__.py"
+ (("@GUIX_OSCRYPTO_USE_OPENSSL@")
+ (string-append openssl "/lib/libcrypto.so" "," openssl "/lib/libssl.so")))
+ #t)))
+ (add-after 'unpack 'disable-broken-tests
+ (lambda _
+ ;; This test is broken as there is no keyboard interrupt.
+ (substitute* "tests/test_trust_list.py"
+ (("^(.*)class TrustListTests" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ (substitute* "tests/test_tls.py"
+ (("^(.*)class TLSTests" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ #t))
+ (replace 'check
+ (lambda _
+ (invoke "python" "run.py" "tests")
+ #t)))))
+ (home-page "https://github.com/wbond/oscrypto")
+ (synopsis "Compiler-free Python crypto library backed by the OS")
+ (description "oscrypto is a compilation-free, always up-to-date encryption library for Python.")
+ (license license:expat)))
+
+(define-public python-oscryptotests
+ (package (inherit python-oscrypto)
+ (name "python-oscryptotests")
+ (arguments
+ `(#:tests? #f
+ #:phases
+ (modify-phases %standard-phases
+ (add-after 'unpack 'hard-code-path-to-libscrypt
+ (lambda* (#:key inputs #:allow-other-keys)
+ (chdir "tests")
+ #t)))))))
+
+(define-public python-certvalidator
+ (let ((commit "e5bdb4bfcaa09fa0af355eb8867d00dfeecba08c"))
+ (package
+ (name "python-certvalidator")
+ (version (git-version "0.1" "1" commit))
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/achow101/certvalidator")
+ (commit commit)))
+ (file-name (git-file-name name commit))
+ (sha256
+ (base32
+ "18pvxkvpkfkzgvfylv0kx65pmxfcv1hpsg03cip93krfvrrl4c75"))))
+ (build-system python-build-system)
+ (propagated-inputs
+ `(("python-asn1crypto" ,python-asn1crypto)
+ ("python-oscrypto" ,python-oscrypto)
+ ("python-oscryptotests", python-oscryptotests))) ;; certvalidator tests import oscryptotests
+ (arguments
+ `(#:phases
+ (modify-phases %standard-phases
+ (add-after 'unpack 'disable-broken-tests
+ (lambda _
+ (substitute* "tests/test_certificate_validator.py"
+ (("^(.*)class CertificateValidatorTests" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ (substitute* "tests/test_crl_client.py"
+ (("^(.*)def test_fetch_crl" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ (substitute* "tests/test_ocsp_client.py"
+ (("^(.*)def test_fetch_ocsp" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ (substitute* "tests/test_registry.py"
+ (("^(.*)def test_build_paths" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ (substitute* "tests/test_validate.py"
+ (("^(.*)def test_revocation_mode_hard" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ #t))
+ (replace 'check
+ (lambda _
+ (invoke "python" "run.py" "tests")
+ #t)))))
+ (home-page "https://github.com/wbond/certvalidator")
+ (synopsis "Python library for validating X.509 certificates and paths")
+ (description "certvalidator is a Python library for validating X.509
+certificates or paths. Supports various options, including: validation at a
+specific moment in time, whitelisting and revocation checks.")
+ (license license:expat))))
+
+(define-public python-requests-2.25.1
+ (package (inherit python-requests)
+ (version "2.25.1")
+ (source (origin
+ (method url-fetch)
+ (uri (pypi-uri "requests" version))
+ (sha256
+ (base32
+ "015qflyqsgsz09gnar69s6ga74ivq5kch69s4qxz3904m7a3v5r7"))))))
+
+(define-public python-altgraph
+ (package
+ (name "python-altgraph")
+ (version "0.17")
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/ronaldoussoren/altgraph")
+ (commit (string-append "v" version))))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "09sm4srvvkw458pn48ga9q7ykr4xlz7q8gh1h9w7nxpf001qgpwb"))))
+ (build-system python-build-system)
+ (home-page "https://github.com/ronaldoussoren/altgraph")
+ (synopsis "Python graph (network) package")
+ (description "altgraph is a fork of graphlib: a graph (network) package for
+constructing graphs, BFS and DFS traversals, topological sort, shortest paths,
+etc. with graphviz output.")
+ (license license:expat)))
+
+
+(define-public python-macholib
+ (package
+ (name "python-macholib")
+ (version "1.14")
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/ronaldoussoren/macholib")
+ (commit (string-append "v" version))))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "0aislnnfsza9wl4f0vp45ivzlc0pzhp9d4r08700slrypn5flg42"))))
+ (build-system python-build-system)
+ (propagated-inputs
+ `(("python-altgraph" ,python-altgraph)))
+ (arguments
+ '(#:phases
+ (modify-phases %standard-phases
+ (add-after 'unpack 'disable-broken-tests
+ (lambda _
+ ;; This test is broken as there is no keyboard interrupt.
+ (substitute* "macholib_tests/test_command_line.py"
+ (("^(.*)class TestCmdLine" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line)))
+ (substitute* "macholib_tests/test_dyld.py"
+ (("^(.*)def test_\\S+_find" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line))
+ (("^(.*)def testBasic" line indent)
+ (string-append indent
+ "@unittest.skip(\"Disabled by Guix\")\n"
+ line))
+ )
+ #t)))))
+ (home-page "https://github.com/ronaldoussoren/macholib")
+ (synopsis "Python library for analyzing and editing Mach-O headers")
+ (description "macholib is a Macho-O header analyzer and editor. It's
+typically used as a dependency analysis tool, and also to rewrite dylib
+references in Mach-O headers to be @executable_path relative. Though this tool
+targets a platform specific file format, it is pure python code that is platform
+and endian independent.")
+ (license license:expat)))
+
+(define-public python-signapple
+ (let ((commit "4ff1c1754e37042c002a3f6375c47fd931f2030b"))
+ (package
+ (name "python-signapple")
+ (version (git-version "0.1" "1" commit))
+ (source
+ (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/dongcarl/signapple")
+ (commit commit)))
+ (file-name (git-file-name name commit))
+ (sha256
+ (base32
+ "043czyzfm04rcx5xsp59vsppla3vm5g45dbp1npy2hww4066rlnh"))))
+ (build-system python-build-system)
+ (propagated-inputs
+ `(("python-asn1crypto" ,python-asn1crypto)
+ ("python-oscrypto" ,python-oscrypto)
+ ("python-certvalidator" ,python-certvalidator)
+ ("python-elfesteem" ,python-elfesteem)
+ ("python-requests" ,python-requests-2.25.1)
+ ("python-macholib" ,python-macholib)
+ ("libcrypto" ,openssl)))
+ ;; There are no tests, but attempting to run python setup.py test leads to
+ ;; problems, just disable the test
+ (arguments '(#:tests? #f))
+ (home-page "https://github.com/achow101/signapple")
+ (synopsis "Mach-O binary signature tool")
+ (description "signapple is a Python tool for creating, verifying, and
+inspecting signatures in Mach-O binaries.")
+ (license license:expat))))
+
(packages->manifest
(append
(list ;; The Basics
@@ -262,9 +601,10 @@ parse, modify and abstract ELF, PE and MachO formats.")
;; Windows
(list zip
(make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32")
- (make-nsis-with-sde-support nsis-x86_64)))
+ (make-nsis-with-sde-support nsis-x86_64)
+ osslsigncode))
((string-contains target "-linux-")
(list (make-bitcoin-cross-toolchain target)))
((string-contains target "darwin")
- (list clang-toolchain-10 binutils imagemagick libtiff librsvg font-tuffy cmake xorriso))
+ (list clang-toolchain-10 binutils imagemagick libtiff librsvg font-tuffy cmake xorriso python-signapple))
(else '())))))
diff --git a/contrib/guix/patches/gcc-8-sort-libtool-find-output.patch b/contrib/guix/patches/gcc-8-sort-libtool-find-output.patch
new file mode 100644
index 0000000000..1dfe3ba132
--- /dev/null
+++ b/contrib/guix/patches/gcc-8-sort-libtool-find-output.patch
@@ -0,0 +1,392 @@
+diff --git a/gcc/configure b/gcc/configure
+index 97ba7d7d69c..e37a96f0c0c 100755
+--- a/gcc/configure
++++ b/gcc/configure
+@@ -19720,20 +19720,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libcc1/configure b/libcc1/configure
+index f53a121611c..5740ca90cab 100755
+--- a/libcc1/configure
++++ b/libcc1/configure
+@@ -12221,20 +12221,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libffi/configure b/libffi/configure
+index 790a291011f..54b1ac18306 100755
+--- a/libffi/configure
++++ b/libffi/configure
+@@ -12661,20 +12661,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libgo/config/libtool.m4 b/libgo/config/libtool.m4
+index f7005947454..8a84417b828 100644
+--- a/libgo/config/libtool.m4
++++ b/libgo/config/libtool.m4
+@@ -6010,20 +6010,20 @@ if test "$_lt_caught_CXX_error" != yes; then
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libgo/config/ltmain.sh b/libgo/config/ltmain.sh
+index ce66b44906a..0f81c401407 100644
+--- a/libgo/config/ltmain.sh
++++ b/libgo/config/ltmain.sh
+@@ -2917,7 +2917,7 @@ func_extract_archives ()
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+- darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
++ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+@@ -2932,7 +2932,7 @@ func_extract_archives ()
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+- my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
++ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
+diff --git a/libhsail-rt/configure b/libhsail-rt/configure
+index a4fcc10c1f9..8e671229fcd 100755
+--- a/libhsail-rt/configure
++++ b/libhsail-rt/configure
+@@ -12244,20 +12244,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libitm/configure b/libitm/configure
+index dbf386db434..29d4f10611f 100644
+--- a/libitm/configure
++++ b/libitm/configure
+@@ -13067,20 +13067,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/liboffloadmic/configure b/liboffloadmic/configure
+index f873716991b..7aa9186b10e 100644
+--- a/liboffloadmic/configure
++++ b/liboffloadmic/configure
+@@ -12379,20 +12379,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/liboffloadmic/plugin/configure b/liboffloadmic/plugin/configure
+index c031eb3e7fa..67fc7368f21 100644
+--- a/liboffloadmic/plugin/configure
++++ b/liboffloadmic/plugin/configure
+@@ -12086,20 +12086,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libsanitizer/configure b/libsanitizer/configure
+index 4695bc7d4f7..cb7d25c07e6 100755
+--- a/libsanitizer/configure
++++ b/libsanitizer/configure
+@@ -13308,20 +13308,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
+index 61457e940ec..21ef1f61e41 100755
+--- a/libstdc++-v3/configure
++++ b/libstdc++-v3/configure
+@@ -13087,20 +13087,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libtool.m4 b/libtool.m4
+index 24d13f34409..940faaa161d 100644
+--- a/libtool.m4
++++ b/libtool.m4
+@@ -6005,20 +6005,20 @@ if test "$_lt_caught_CXX_error" != yes; then
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/libvtv/configure b/libvtv/configure
+index a197f750453..31ab3a0637b 100755
+--- a/libvtv/configure
++++ b/libvtv/configure
+@@ -13339,20 +13339,20 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+- compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+diff --git a/ltmain.sh b/ltmain.sh
+index 9503ec85d70..79f9ba89af5 100644
+--- a/ltmain.sh
++++ b/ltmain.sh
+@@ -2917,7 +2917,7 @@ func_extract_archives ()
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+- darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
++ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+@@ -2932,7 +2932,7 @@ func_extract_archives ()
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+- my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
++ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
diff --git a/contrib/guix/patches/oscrypto-hard-code-openssl.patch b/contrib/guix/patches/oscrypto-hard-code-openssl.patch
new file mode 100644
index 0000000000..32027f2d09
--- /dev/null
+++ b/contrib/guix/patches/oscrypto-hard-code-openssl.patch
@@ -0,0 +1,13 @@
+diff --git a/oscrypto/__init__.py b/oscrypto/__init__.py
+index eb27313..371ab24 100644
+--- a/oscrypto/__init__.py
++++ b/oscrypto/__init__.py
+@@ -302,3 +302,8 @@ def load_order():
+ 'oscrypto._win.tls',
+ 'oscrypto.tls',
+ ]
++
++
++paths = '@GUIX_OSCRYPTO_USE_OPENSSL@'.split(',')
++assert len(paths) == 2, 'Value for OSCRYPTO_USE_OPENSSL env var must be two paths separated by a comma'
++use_openssl(*paths)
diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh
index 31720e72e7..29802e622e 100755
--- a/contrib/windeploy/detached-sig-create.sh
+++ b/contrib/windeploy/detached-sig-create.sh
@@ -25,7 +25,7 @@ CERTFILE="win-codesign.cert"
mkdir -p "${OUTSUBDIR}"
basename -a $(ls -1 "${SRCDIR}"/*-unsigned.exe) | while read UNSIGNED; do
echo Signing "${UNSIGNED}"
- "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"
+ "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -h sha256 -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"
"${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}"
done
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 0922c1c432..c376aced10 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -43,7 +43,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
std::string tmpfn = strprintf("%s.%04x", prefix, randv);
// open temp output file, and associate with CAutoFile
- fs::path pathTmp = GetDataDir() / tmpfn;
+ fs::path pathTmp = gArgs.GetDataDirNet() / tmpfn;
FILE *file = fsbridge::fopen(pathTmp, "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
if (fileout.IsNull()) {
@@ -135,7 +135,7 @@ bool CBanDB::Read(banmap_t& banSet)
CAddrDB::CAddrDB()
{
- pathAddr = GetDataDir() / "peers.dat";
+ pathAddr = gArgs.GetDataDirNet() / "peers.dat";
}
bool CAddrDB::Write(const CAddrMan& addr)
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index b82b9915d5..b485776732 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -98,7 +98,7 @@ BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
const std::string& filter_name = BlockFilterTypeName(filter_type);
if (filter_name.empty()) throw std::invalid_argument("unknown filter_type");
- fs::path path = GetDataDir() / "indexes" / "blockfilter" / filter_name;
+ fs::path path = gArgs.GetDataDirNet() / "indexes" / "blockfilter" / filter_name;
fs::create_directories(path);
m_name = filter_name + " block filter index";
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index 7c8b2b186e..e046527283 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -97,7 +97,7 @@ std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
{
- fs::path path{GetDataDir() / "indexes" / "coinstats"};
+ fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
fs::create_directories(path);
m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 3feefe8619..d9e437ad10 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -37,7 +37,7 @@ public:
};
TxIndex::DB::DB(size_t n_cache_size, bool f_memory, bool f_wipe) :
- BaseIndex::DB(GetDataDir() / "indexes" / "txindex", n_cache_size, f_memory, f_wipe)
+ BaseIndex::DB(gArgs.GetDataDirNet() / "indexes" / "txindex", n_cache_size, f_memory, f_wipe)
{}
bool TxIndex::DB::ReadTxPos(const uint256 &txid, CDiskTxPos& pos) const
diff --git a/src/init.cpp b/src/init.cpp
index 89e152e56f..a835df0572 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -390,7 +390,6 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -1015,7 +1014,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
static bool LockDataDirectory(bool probeOnly)
{
// Make sure only a single Bitcoin process is using the data directory.
- fs::path datadir = GetDataDir();
+ fs::path datadir = gArgs.GetDataDirNet();
if (!DirIsWritable(datadir)) {
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
}
@@ -1166,7 +1165,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
assert(!node.addrman);
node.addrman = std::make_unique<CAddrMan>();
assert(!node.banman);
- node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
+ node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman, args.GetBoolArg("-networkactive", true));
@@ -1276,7 +1275,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
asmap_path = DEFAULT_ASMAP_FILENAME;
}
if (!asmap_path.is_absolute()) {
- asmap_path = GetDataDir() / asmap_path;
+ asmap_path = gArgs.GetDataDirNet() / asmap_path;
}
if (!fs::exists(asmap_path)) {
InitError(strprintf(_("Could not find asmap file %s"), asmap_path));
@@ -1600,8 +1599,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 11: import blocks
- if (!CheckDiskSpace(GetDataDir())) {
- InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
+ if (!CheckDiskSpace(gArgs.GetDataDirNet())) {
+ InitError(strprintf(_("Error: Disk space is low for %s"), gArgs.GetDataDirNet()));
return false;
}
if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
diff --git a/src/init/common.cpp b/src/init/common.cpp
index 79e0c9da78..5c1f469081 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -134,7 +134,7 @@ bool StartLogging(const ArgsManager& args)
if (!LogInstance().m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
- LogPrintf("Using data directory %s\n", GetDataDir().string());
+ LogPrintf("Using data directory %s\n", gArgs.GetDataDirNet().string());
// Only log conf file usage message if conf file actually exists.
fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
diff --git a/src/net.cpp b/src/net.cpp
index 1322c971fb..1b6f04dead 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1638,7 +1638,7 @@ void CConnman::ThreadDNSAddressSeed()
{
LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) {
- if (pnode->fSuccessfullyConnected && pnode->IsOutboundOrBlockRelayConn()) ++nRelevant;
+ if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
}
}
if (nRelevant >= 2) {
@@ -2461,7 +2461,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
proxyType i2p_sam;
if (GetProxy(NET_I2P, i2p_sam)) {
- m_i2p_sam_session = std::make_unique<i2p::sam::Session>(GetDataDir() / "i2p_private_key",
+ m_i2p_sam_session = std::make_unique<i2p::sam::Session>(gArgs.GetDataDirNet() / "i2p_private_key",
i2p_sam.proxy, &interruptNet);
}
@@ -2487,7 +2487,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (m_use_addrman_outgoing) {
// Load addresses from anchors.dat
- m_anchors = ReadAnchors(GetDataDir() / ANCHORS_DATABASE_FILENAME);
+ m_anchors = ReadAnchors(gArgs.GetDataDirNet() / ANCHORS_DATABASE_FILENAME);
if (m_anchors.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) {
m_anchors.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS);
}
@@ -2627,7 +2627,7 @@ void CConnman::StopNodes()
if (anchors_to_dump.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) {
anchors_to_dump.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS);
}
- DumpAnchors(GetDataDir() / ANCHORS_DATABASE_FILENAME, anchors_to_dump);
+ DumpAnchors(gArgs.GetDataDirNet() / ANCHORS_DATABASE_FILENAME, anchors_to_dump);
}
}
@@ -2929,10 +2929,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const
m_tx_relay = std::make_unique<TxRelay>();
}
- if (RelayAddrsWithConn()) {
- m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
- }
-
for (const std::string &msg : getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
@@ -3043,7 +3039,7 @@ void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Spa
std::string clean_addr = addr.ToString();
std::replace(clean_addr.begin(), clean_addr.end(), ':', '_');
- fs::path base_path = GetDataDir() / "message_capture" / clean_addr;
+ fs::path base_path = gArgs.GetDataDirNet() / "message_capture" / clean_addr;
fs::create_directories(base_path);
fs::path path = base_path / (is_incoming ? "msgs_recv.dat" : "msgs_sent.dat");
diff --git a/src/net.h b/src/net.h
index 28f2d9ace6..b43916c55e 100644
--- a/src/net.h
+++ b/src/net.h
@@ -54,8 +54,6 @@ static const int TIMEOUT_INTERVAL = 20 * 60;
static constexpr auto FEELER_INTERVAL = 2min;
/** Run the extra block-relay-only connection loop once every 5 minutes. **/
static constexpr auto EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL = 5min;
-/** The maximum number of addresses from our addrman to return in response to a getaddr message. */
-static constexpr size_t MAX_ADDR_TO_SEND = 1000;
/** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
/** Maximum length of the user agent string in `version` message */
@@ -447,17 +445,11 @@ public:
}
bool fClient{false}; // set by version message
bool m_limited_node{false}; //after BIP159, set by version message
- /**
- * Whether the peer has signaled support for receiving ADDRv2 (BIP155)
- * messages, implying a preference to receive ADDRv2 instead of ADDR ones.
- */
- std::atomic_bool m_wants_addrv2{false};
/** fSuccessfullyConnected is set to true on receiving VERACK from the peer. */
std::atomic_bool fSuccessfullyConnected{false};
// Setting fDisconnect to true will cause the node to be disconnected the
// next time DisconnectNodes() runs
std::atomic_bool fDisconnect{false};
- bool fSentAddr{false};
CSemaphoreGrant grantOutbound;
std::atomic<int> nRefCount{0};
@@ -504,15 +496,6 @@ public:
return m_conn_type == ConnectionType::INBOUND;
}
- /* Whether we send addr messages over this connection */
- bool RelayAddrsWithConn() const
- {
- // Don't relay addr messages to peers that we connect to as block-relay-only
- // peers (to prevent adversaries from inferring these links from addr
- // traffic).
- return m_conn_type != ConnectionType::BLOCK_RELAY;
- }
-
bool ExpectServicesFromConn() const {
switch (m_conn_type) {
case ConnectionType::INBOUND:
@@ -545,14 +528,6 @@ public:
// Peer selected us as (compact blocks) high-bandwidth peer (BIP152)
std::atomic<bool> m_bip152_highbandwidth_from{false};
- // flood relay
- std::vector<CAddress> vAddrToSend;
- std::unique_ptr<CRollingBloomFilter> m_addr_known{nullptr};
- bool fGetAddr{false};
- Mutex m_addr_send_times_mutex;
- std::chrono::microseconds m_next_addr_send GUARDED_BY(m_addr_send_times_mutex){0};
- std::chrono::microseconds m_next_local_addr_send GUARDED_BY(m_addr_send_times_mutex){0};
-
struct TxRelay {
mutable RecursiveMutex cs_filter;
// We use fRelayTxes for two purposes -
@@ -657,37 +632,6 @@ public:
nRefCount--;
}
- void AddAddressKnown(const CAddress& _addr)
- {
- assert(m_addr_known);
- m_addr_known->insert(_addr.GetKey());
- }
-
- /**
- * Whether the peer supports the address. For example, a peer that does not
- * implement BIP155 cannot receive Tor v3 addresses because it requires
- * ADDRv2 (BIP155) encoding.
- */
- bool IsAddrCompatible(const CAddress& addr) const
- {
- return m_wants_addrv2 || addr.IsAddrV1Compatible();
- }
-
- void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)
- {
- // Known checking here is only to save space from duplicates.
- // SendMessages will filter it again for knowns that were added
- // after addresses were pushed.
- assert(m_addr_known);
- if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey()) && IsAddrCompatible(_addr)) {
- if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
- vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
- } else {
- vAddrToSend.push_back(_addr);
- }
- }
- }
-
void AddKnownTx(const uint256& hash)
{
if (m_tx_relay != nullptr) {
@@ -900,28 +844,6 @@ public:
}
};
- template<typename Callable, typename CallableAfter>
- void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
- if (NodeFullyConnected(node))
- pre(node);
- }
- post();
- };
-
- template<typename Callable, typename CallableAfter>
- void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
- if (NodeFullyConnected(node))
- pre(node);
- }
- post();
- };
-
// Addrman functions
/**
* Return all or many randomly selected addresses, optionally by network.
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index cee2419610..0b83f756b3 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -152,6 +152,8 @@ static constexpr uint32_t MAX_GETCFILTERS_SIZE = 1000;
static constexpr uint32_t MAX_GETCFHEADERS_SIZE = 2000;
/** the maximum percentage of addresses from our addrman to return in response to a getaddr message. */
static constexpr size_t MAX_PCT_ADDR_TO_SEND = 23;
+/** The maximum number of address records permitted in an ADDR message. */
+static constexpr size_t MAX_ADDR_TO_SEND{1000};
// Internal stuff
namespace {
@@ -212,6 +214,25 @@ struct Peer {
/** Whether a ping has been requested by the user */
std::atomic<bool> m_ping_queued{false};
+ /** A vector of addresses to send to the peer, limited to MAX_ADDR_TO_SEND. */
+ std::vector<CAddress> m_addrs_to_send;
+ /** Probabilistic filter of addresses that this peer already knows.
+ * Used to avoid relaying addresses to this peer more than once. */
+ const std::unique_ptr<CRollingBloomFilter> m_addr_known;
+ /** Whether a getaddr request to this peer is outstanding. */
+ bool m_getaddr_sent{false};
+ /** Guards address sending timers. */
+ mutable Mutex m_addr_send_times_mutex;
+ /** Time point to send the next ADDR message to this peer. */
+ std::chrono::microseconds m_next_addr_send GUARDED_BY(m_addr_send_times_mutex){0};
+ /** Time point to possibly re-announce our local address to this peer. */
+ std::chrono::microseconds m_next_local_addr_send GUARDED_BY(m_addr_send_times_mutex){0};
+ /** Whether the peer has signaled support for receiving ADDRv2 (BIP155)
+ * messages, indicating a preference to receive ADDRv2 instead of ADDR ones. */
+ std::atomic_bool m_wants_addrv2{false};
+ /** Whether this peer has already sent us a getaddr message. */
+ bool m_getaddr_recvd{false};
+
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
@@ -220,7 +241,10 @@ struct Peer {
/** Work queue of items requested by this peer **/
std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
- explicit Peer(NodeId id) : m_id(id) {}
+ explicit Peer(NodeId id, bool addr_relay)
+ : m_id(id)
+ , m_addr_known{addr_relay ? std::make_unique<CRollingBloomFilter>(5000, 0.001) : nullptr}
+ {}
};
using PeerRef = std::shared_ptr<Peer>;
@@ -329,7 +353,19 @@ private:
void MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now);
/** Send `addr` messages on a regular schedule. */
- void MaybeSendAddr(CNode& node, std::chrono::microseconds current_time);
+ void MaybeSendAddr(CNode& node, Peer& peer, std::chrono::microseconds current_time);
+
+ /** Relay (gossip) an address to a few randomly chosen nodes.
+ *
+ * @param[in] originator The id of the peer that sent us the address. We don't want to relay it back.
+ * @param[in] addr Address to relay.
+ * @param[in] fReachable Whether the address' network is reachable. We relay unreachable
+ * addresses less.
+ */
+ void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable);
+
+ /** Send `feefilter` message. */
+ void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
const CChainParams& m_chainparams;
CConnman& m_connman;
@@ -675,6 +711,42 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
return &it->second;
}
+static bool RelayAddrsWithPeer(const Peer& peer)
+{
+ return peer.m_addr_known != nullptr;
+}
+
+/**
+ * Whether the peer supports the address. For example, a peer that does not
+ * implement BIP155 cannot receive Tor v3 addresses because it requires
+ * ADDRv2 (BIP155) encoding.
+ */
+static bool IsAddrCompatible(const Peer& peer, const CAddress& addr)
+{
+ return peer.m_wants_addrv2 || addr.IsAddrV1Compatible();
+}
+
+static void AddAddressKnown(Peer& peer, const CAddress& addr)
+{
+ assert(peer.m_addr_known);
+ peer.m_addr_known->insert(addr.GetKey());
+}
+
+static void PushAddress(Peer& peer, const CAddress& addr, FastRandomContext& insecure_rand)
+{
+ // Known checking here is only to save space from duplicates.
+ // Before sending, we'll filter it again for known addresses that were
+ // added after addresses were pushed.
+ assert(peer.m_addr_known);
+ if (addr.IsValid() && !peer.m_addr_known->contains(addr.GetKey()) && IsAddrCompatible(peer, addr)) {
+ if (peer.m_addrs_to_send.size() >= MAX_ADDR_TO_SEND) {
+ peer.m_addrs_to_send[insecure_rand.randrange(peer.m_addrs_to_send.size())] = addr;
+ } else {
+ peer.m_addrs_to_send.push_back(addr);
+ }
+ }
+}
+
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
nPreferredDownload -= state->fPreferredDownload;
@@ -1001,7 +1073,9 @@ void PeerManagerImpl::InitializeNode(CNode *pnode)
assert(m_txrequest.Count(nodeid) == 0);
}
{
- PeerRef peer = std::make_shared<Peer>(nodeid);
+ // Addr relay is disabled for outbound block-relay-only peers to
+ // prevent adversaries from inferring these links from addr traffic.
+ PeerRef peer = std::make_shared<Peer>(nodeid, /* addr_relay = */ !pnode->IsBlockOnlyConn());
LOCK(m_peer_mutex);
m_peer_map.emplace_hint(m_peer_map.end(), nodeid, std::move(peer));
}
@@ -1534,59 +1608,49 @@ void PeerManagerImpl::_RelayTransaction(const uint256& txid, const uint256& wtxi
});
}
-/**
- * Relay (gossip) an address to a few randomly chosen nodes.
- * We choose the same nodes within a given 24h window (if the list of connected
- * nodes does not change) and we don't relay to nodes that already know an
- * address. So within 24h we will likely relay a given address once. This is to
- * prevent a peer from unjustly giving their address better propagation by sending
- * it to us repeatedly.
- * @param[in] originator The peer that sent us the address. We don't want to relay it back.
- * @param[in] addr Address to relay.
- * @param[in] fReachable Whether the address' network is reachable. We relay unreachable
- * addresses less.
- * @param[in] connman Connection manager to choose nodes to relay to.
- */
-static void RelayAddress(const CNode& originator,
- const CAddress& addr,
- bool fReachable,
- const CConnman& connman)
+void PeerManagerImpl::RelayAddress(NodeId originator,
+ const CAddress& addr,
+ bool fReachable)
{
+ // We choose the same nodes within a given 24h window (if the list of connected
+ // nodes does not change) and we don't relay to nodes that already know an
+ // address. So within 24h we will likely relay a given address once. This is to
+ // prevent a peer from unjustly giving their address better propagation by sending
+ // it to us repeatedly.
+
if (!fReachable && !addr.IsRelayable()) return;
// Relay to a limited number of other nodes
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the m_addr_knowns of the chosen nodes prevent repeats
uint64_t hashAddr = addr.GetHash();
- const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
+ const CSipHasher hasher = m_connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
FastRandomContext insecure_rand;
// Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers.
unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
- std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
+ std::array<std::pair<uint64_t, Peer*>, 2> best{{{0, nullptr}, {0, nullptr}}};
assert(nRelayNodes <= best.size());
- auto sortfunc = [&best, &hasher, nRelayNodes, &originator, &addr](CNode* pnode) {
- if (pnode->RelayAddrsWithConn() && pnode != &originator && pnode->IsAddrCompatible(addr)) {
- uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
+ LOCK(m_peer_mutex);
+
+ for (auto& [id, peer] : m_peer_map) {
+ if (RelayAddrsWithPeer(*peer) && id != originator && IsAddrCompatible(*peer, addr)) {
+ uint64_t hashKey = CSipHasher(hasher).Write(id).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) {
std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);
- best[i] = std::make_pair(hashKey, pnode);
+ best[i] = std::make_pair(hashKey, peer.get());
break;
}
}
}
};
- auto pushfunc = [&addr, &best, nRelayNodes, &insecure_rand] {
- for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
- best[i].second->PushAddress(addr, insecure_rand);
- }
- };
-
- connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+ for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
+ PushAddress(*best[i].second, addr, insecure_rand);
+ }
}
void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv)
@@ -2481,17 +2545,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (addr.IsRoutable())
{
LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom.PushAddress(addr, insecure_rand);
+ PushAddress(*peer, addr, insecure_rand);
} else if (IsPeerAddrLocalGood(&pfrom)) {
addr.SetIP(addrMe);
LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom.PushAddress(addr, insecure_rand);
+ PushAddress(*peer, addr, insecure_rand);
}
}
// Get recent addresses
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
- pfrom.fGetAddr = true;
+ peer->m_getaddr_sent = true;
}
if (!pfrom.IsInboundConn()) {
@@ -2650,7 +2714,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.fDisconnect = true;
return;
}
- pfrom.m_wants_addrv2 = true;
+ peer->m_wants_addrv2 = true;
return;
}
@@ -2672,7 +2736,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
s >> vAddr;
- if (!pfrom.RelayAddrsWithConn()) {
+ if (!RelayAddrsWithPeer(*peer)) {
LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId());
return;
}
@@ -2699,24 +2763,22 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
- pfrom.AddAddressKnown(addr);
+ AddAddressKnown(*peer, addr);
if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {
// Do not process banned/discouraged addresses beyond remembering we received them
continue;
}
bool fReachable = IsReachable(addr);
- if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
- {
+ if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes
- RelayAddress(pfrom, addr, fReachable, m_connman);
+ RelayAddress(pfrom.GetId(), addr, fReachable);
}
// Do not store addresses outside our network
if (fReachable)
vAddrOk.push_back(addr);
}
m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
- if (vAddr.size() < 1000)
- pfrom.fGetAddr = false;
+ if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
if (pfrom.IsAddrFetchConn()) {
LogPrint(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
@@ -3576,14 +3638,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
// Only send one GetAddr response per connection to reduce resource waste
- // and discourage addr stamping of INV announcements.
- if (pfrom.fSentAddr) {
+ // and discourage addr stamping of INV announcements.
+ if (peer->m_getaddr_recvd) {
LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom.GetId());
return;
}
- pfrom.fSentAddr = true;
+ peer->m_getaddr_recvd = true;
- pfrom.vAddrToSend.clear();
+ peer->m_addrs_to_send.clear();
std::vector<CAddress> vAddr;
if (pfrom.HasPermission(NetPermissionFlags::Addr)) {
vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND, /* network */ std::nullopt);
@@ -3592,7 +3654,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr) {
- pfrom.PushAddress(addr, insecure_rand);
+ PushAddress(*peer, addr, insecure_rand);
}
return;
}
@@ -4150,72 +4212,113 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::mic
}
}
-void PeerManagerImpl::MaybeSendAddr(CNode& node, std::chrono::microseconds current_time)
+void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::microseconds current_time)
{
// Nothing to do for non-address-relay peers
- if (!node.RelayAddrsWithConn()) return;
+ if (!RelayAddrsWithPeer(peer)) return;
- assert(node.m_addr_known);
-
- LOCK(node.m_addr_send_times_mutex);
+ LOCK(peer.m_addr_send_times_mutex);
// Periodically advertise our local address to the peer.
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
- node.m_next_local_addr_send < current_time) {
+ peer.m_next_local_addr_send < current_time) {
// If we've sent before, clear the bloom filter for the peer, so that our
// self-announcement will actually go out.
// This might be unnecessary if the bloom filter has already rolled
// over since our last self-announcement, but there is only a small
// bandwidth cost that we can incur by doing this (which happens
// once a day on average).
- if (node.m_next_local_addr_send != 0us) {
- node.m_addr_known->reset();
+ if (peer.m_next_local_addr_send != 0us) {
+ peer.m_addr_known->reset();
}
if (std::optional<CAddress> local_addr = GetLocalAddrForPeer(&node)) {
FastRandomContext insecure_rand;
- node.PushAddress(*local_addr, insecure_rand);
+ PushAddress(peer, *local_addr, insecure_rand);
}
- node.m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
+ peer.m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
// We sent an `addr` message to this peer recently. Nothing more to do.
- if (current_time <= node.m_next_addr_send) return;
+ if (current_time <= peer.m_next_addr_send) return;
- node.m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
+ peer.m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
- if (!Assume(node.vAddrToSend.size() <= MAX_ADDR_TO_SEND)) {
+ if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) {
// Should be impossible since we always check size before adding to
- // vAddrToSend. Recover by trimming the vector.
- node.vAddrToSend.resize(MAX_ADDR_TO_SEND);
+ // m_addrs_to_send. Recover by trimming the vector.
+ peer.m_addrs_to_send.resize(MAX_ADDR_TO_SEND);
}
// Remove addr records that the peer already knows about, and add new
// addrs to the m_addr_known filter on the same pass.
- auto addr_already_known = [&node](const CAddress& addr) {
- bool ret = node.m_addr_known->contains(addr.GetKey());
- if (!ret) node.m_addr_known->insert(addr.GetKey());
+ auto addr_already_known = [&peer](const CAddress& addr) {
+ bool ret = peer.m_addr_known->contains(addr.GetKey());
+ if (!ret) peer.m_addr_known->insert(addr.GetKey());
return ret;
};
- node.vAddrToSend.erase(std::remove_if(node.vAddrToSend.begin(), node.vAddrToSend.end(), addr_already_known),
- node.vAddrToSend.end());
+ peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(), peer.m_addrs_to_send.end(), addr_already_known),
+ peer.m_addrs_to_send.end());
// No addr messages to send
- if (node.vAddrToSend.empty()) return;
+ if (peer.m_addrs_to_send.empty()) return;
const char* msg_type;
int make_flags;
- if (node.m_wants_addrv2) {
+ if (peer.m_wants_addrv2) {
msg_type = NetMsgType::ADDRV2;
make_flags = ADDRV2_FORMAT;
} else {
msg_type = NetMsgType::ADDR;
make_flags = 0;
}
- m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(make_flags, msg_type, node.vAddrToSend));
- node.vAddrToSend.clear();
+ m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(make_flags, msg_type, peer.m_addrs_to_send));
+ peer.m_addrs_to_send.clear();
// we only send the big addr message once
- if (node.vAddrToSend.capacity() > 40) {
- node.vAddrToSend.shrink_to_fit();
+ if (peer.m_addrs_to_send.capacity() > 40) {
+ peer.m_addrs_to_send.shrink_to_fit();
+ }
+}
+
+void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds current_time)
+{
+ AssertLockHeld(cs_main);
+
+ if (m_ignore_incoming_txs) return;
+ if (!pto.m_tx_relay) return;
+ if (pto.GetCommonVersion() < FEEFILTER_VERSION) return;
+ // peers with the forcerelay permission should not filter txs to us
+ if (pto.HasPermission(NetPermissionFlags::ForceRelay)) return;
+
+ CAmount currentFilter = m_mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
+ static FeeFilterRounder g_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}};
+
+ if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
+ // Received tx-inv messages are discarded when the active
+ // chainstate is in IBD, so tell the peer to not send them.
+ currentFilter = MAX_MONEY;
+ } else {
+ static const CAmount MAX_FILTER{g_filter_rounder.round(MAX_MONEY)};
+ if (pto.m_tx_relay->lastSentFeeFilter == MAX_FILTER) {
+ // Send the current filter if we sent MAX_FILTER previously
+ // and made it out of IBD.
+ pto.m_tx_relay->m_next_send_feefilter = 0us;
+ }
+ }
+ if (current_time > pto.m_tx_relay->m_next_send_feefilter) {
+ CAmount filterToSend = g_filter_rounder.round(currentFilter);
+ // We always have a fee filter of at least minRelayTxFee
+ filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
+ if (filterToSend != pto.m_tx_relay->lastSentFeeFilter) {
+ m_connman.PushMessage(&pto, CNetMsgMaker(pto.GetCommonVersion()).Make(NetMsgType::FEEFILTER, filterToSend));
+ pto.m_tx_relay->lastSentFeeFilter = filterToSend;
+ }
+ pto.m_tx_relay->m_next_send_feefilter = PoissonNextSend(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL);
+ }
+ // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
+ // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
+ else if (current_time + MAX_FEEFILTER_CHANGE_DELAY < pto.m_tx_relay->m_next_send_feefilter &&
+ (currentFilter < 3 * pto.m_tx_relay->lastSentFeeFilter / 4 || currentFilter > 4 * pto.m_tx_relay->lastSentFeeFilter / 3)) {
+ pto.m_tx_relay->m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY);
}
}
@@ -4264,7 +4367,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// MaybeSendPing may have marked peer for disconnection
if (pto->fDisconnect) return true;
- MaybeSendAddr(*pto, current_time);
+ MaybeSendAddr(*pto, *peer, current_time);
{
LOCK(cs_main);
@@ -4705,46 +4808,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (!vGetData.empty())
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
- //
- // Message: feefilter
- //
- if (pto->m_tx_relay != nullptr &&
- !m_ignore_incoming_txs &&
- pto->GetCommonVersion() >= FEEFILTER_VERSION &&
- gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
- !pto->HasPermission(NetPermissionFlags::ForceRelay) // peers with the forcerelay permission should not filter txs to us
- ) {
- CAmount currentFilter = m_mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- static FeeFilterRounder g_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}};
- if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
- // Received tx-inv messages are discarded when the active
- // chainstate is in IBD, so tell the peer to not send them.
- currentFilter = MAX_MONEY;
- } else {
- static const CAmount MAX_FILTER{g_filter_rounder.round(MAX_MONEY)};
- if (pto->m_tx_relay->lastSentFeeFilter == MAX_FILTER) {
- // Send the current filter if we sent MAX_FILTER previously
- // and made it out of IBD.
- pto->m_tx_relay->m_next_send_feefilter = 0us;
- }
- }
- if (current_time > pto->m_tx_relay->m_next_send_feefilter) {
- CAmount filterToSend = g_filter_rounder.round(currentFilter);
- // We always have a fee filter of at least minRelayTxFee
- filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
- if (filterToSend != pto->m_tx_relay->lastSentFeeFilter) {
- m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
- pto->m_tx_relay->lastSentFeeFilter = filterToSend;
- }
- pto->m_tx_relay->m_next_send_feefilter = PoissonNextSend(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL);
- }
- // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
- // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
- else if (current_time + MAX_FEEFILTER_CHANGE_DELAY < pto->m_tx_relay->m_next_send_feefilter &&
- (currentFilter < 3 * pto->m_tx_relay->lastSentFeeFilter / 4 || currentFilter > 4 * pto->m_tx_relay->lastSentFeeFilter / 3)) {
- pto->m_tx_relay->m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY);
- }
- }
+ MaybeSendFeefilter(*pto, current_time);
} // release cs_main
return true;
}
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index 3da85fedf9..25b9282b4e 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -7,29 +7,26 @@
#include <tinyformat.h>
-CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
+CFeeRate::CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes)
{
- assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
- int64_t nSize = int64_t(nBytes_);
+ const int64_t nSize{num_bytes};
- if (nSize > 0)
+ if (nSize > 0) {
nSatoshisPerK = nFeePaid * 1000 / nSize;
- else
+ } else {
nSatoshisPerK = 0;
+ }
}
-CAmount CFeeRate::GetFee(size_t nBytes_) const
+CAmount CFeeRate::GetFee(uint32_t num_bytes) const
{
- assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
- int64_t nSize = int64_t(nBytes_);
+ const int64_t nSize{num_bytes};
CAmount nFee = nSatoshisPerK * nSize / 1000;
if (nFee == 0 && nSize != 0) {
- if (nSatoshisPerK > 0)
- nFee = CAmount(1);
- if (nSatoshisPerK < 0)
- nFee = CAmount(-1);
+ if (nSatoshisPerK > 0) nFee = CAmount(1);
+ if (nSatoshisPerK < 0) nFee = CAmount(-1);
}
return nFee;
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 0e4f9914b8..d296d32774 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -39,20 +39,17 @@ public:
// We've previously had bugs creep in from silent double->int conversion...
static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
}
- /** Constructor for a fee rate in satoshis per kvB (sat/kvB). The size in bytes must not exceed (2^63 - 1).
+ /** Constructor for a fee rate in satoshis per kvB (sat/kvB).
*
- * Passing an nBytes value of COIN (1e8) returns a fee rate in satoshis per vB (sat/vB),
+ * Passing a num_bytes value of COIN (1e8) returns a fee rate in satoshis per vB (sat/vB),
* e.g. (nFeePaid * 1e8 / 1e3) == (nFeePaid / 1e5),
* where 1e5 is the ratio to convert from BTC/kvB to sat/vB.
- *
- * @param[in] nFeePaid CAmount fee rate to construct with
- * @param[in] nBytes size_t bytes (units) to construct with
*/
- CFeeRate(const CAmount& nFeePaid, size_t nBytes);
+ CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes);
/**
* Return the fee in satoshis for the given size in bytes.
*/
- CAmount GetFee(size_t nBytes) const;
+ CAmount GetFee(uint32_t num_bytes) const;
/**
* Return the fee in satoshis for a size of 1000 bytes
*/
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 7da171d2e1..52c3362166 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -504,7 +504,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
// If the fee estimation file is present, read recorded estimations
- fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", est_filepath.string());
@@ -864,7 +864,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
void CBlockPolicyEstimator::Flush() {
FlushUnconfirmed();
- fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Write(est_file)) {
LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", est_filepath.string());
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 686772e6bb..dffdd5158b 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -536,7 +536,7 @@ int GuiMain(int argc, char* argv[])
if (!Intro::showIfNeeded(did_show_intro, prune_MiB)) return EXIT_SUCCESS;
/// 6. Determine availability of data directory and parse bitcoin.conf
- /// - Do not call GetDataDir(true) before this step finishes
+ /// - Do not call gArgs.GetDataDirNet() before this step finishes
if (!CheckDataDirOption()) {
InitError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", "")));
QMessageBox::critical(nullptr, PACKAGE_NAME,
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 04161020b2..bb2073b9fe 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -221,7 +221,7 @@ QString ClientModel::formatClientStartupTime() const
QString ClientModel::dataDir() const
{
- return GUIUtil::boostPathToQString(GetDataDir());
+ return GUIUtil::boostPathToQString(gArgs.GetDataDirNet());
}
QString ClientModel::blocksDir() const
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 4691937380..0d73ea0ed0 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -405,7 +405,7 @@ void handleCloseWindowShortcut(QWidget* w)
void openDebugLogfile()
{
- fs::path pathDebug = GetDataDir() / "debug.log";
+ fs::path pathDebug = gArgs.GetDataDirNet() / "debug.log";
/* Open debug.log with the associated application */
if (fs::exists(pathDebug))
diff --git a/src/qt/intro.h b/src/qt/intro.h
index 88fe2b722d..91d57690b7 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -45,7 +45,7 @@ public:
* @returns true if a data directory was selected, false if the user cancelled the selection
* dialog.
*
- * @note do NOT call global GetDataDir() before calling this function, this
+ * @note do NOT call global gArgs.GetDataDirNet() before calling this function, this
* will cause the wrong path to be cached.
*/
static bool showIfNeeded(bool& did_show_intro, int64_t& prune_MiB);
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d51a5b06ff..70762ab6bc 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -195,7 +195,7 @@ void OptionsModel::Reset()
QSettings settings;
// Backup old settings to chain-specific datadir for troubleshooting
- BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
+ BackupSettings(gArgs.GetDataDirNet() / "guisettings.ini.bak", settings);
// Save the strDataDir setting
QString dataDir = GUIUtil::getDefaultDataDirectory();
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index d58d13f722..098fe5ac61 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -49,9 +49,9 @@ static QString ipcServerName()
QString name("BitcoinQt");
// Append a simple hash of the datadir
- // Note that GetDataDir(true) returns a different path
+ // Note that gArgs.GetDataDirNet() returns a different path
// for -testnet versus main net
- QString ddir(GUIUtil::boostPathToQString(GetDataDir(true)));
+ QString ddir(GUIUtil::boostPathToQString(gArgs.GetDataDirNet()));
name.append(QString::number(qHash(ddir)));
return name;
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
index 36b9024541..c1d5f84be5 100644
--- a/src/qt/test/apptests.cpp
+++ b/src/qt/test/apptests.cpp
@@ -65,7 +65,7 @@ void AppTests::appTests()
fs::create_directories([] {
BasicTestingSetup test{CBaseChainParams::REGTEST}; // Create a temp data directory to backup the gui settings to
- return GetDataDir() / "blocks";
+ return gArgs.GetDataDirNet() / "blocks";
}());
qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 63826c49e1..03f28239ba 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -2540,10 +2540,10 @@ static RPCHelpMan dumptxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const fs::path path = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str());
+ const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str());
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption.
- const fs::path temppath = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str() + ".incomplete");
+ const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), request.params[0].get_str() + ".incomplete");
if (fs::exists(path)) {
throw JSONRPCError(
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index 1a39498899..65ba2bab15 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK(CFeeRate(CAmount(26), 789) == CFeeRate(32));
BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34));
// Maximum size in bytes, should not crash
- CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();
+ CFeeRate(MAX_MONEY, std::numeric_limits<uint32_t>::max()).GetFeePerK();
}
BOOST_AUTO_TEST_CASE(BinaryOperatorTest)
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index b5f3bb2fa4..e2e7644dfa 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
+ fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
uint256 in = InsecureRand256();
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
{
// Perform tests both obfuscated and non-obfuscated.
for (bool obfuscate : {false, true}) {
- fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");
+ fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), false, true, obfuscate);
uint256 res;
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
+ fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = m_args.GetDataDirPath() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
+ fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
@@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = m_args.GetDataDirPath() / "existing_data_no_obfuscate";
+ fs::path ph = m_args.GetDataDirBase() / "existing_data_no_obfuscate";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = m_args.GetDataDirPath() / "existing_data_reindex";
+ fs::path ph = m_args.GetDataDirBase() / "existing_data_reindex";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- fs::path ph = m_args.GetDataDirPath() / "iterator_ordering";
+ fs::path ph = m_args.GetDataDirBase() / "iterator_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
@@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- fs::path ph = m_args.GetDataDirPath() / "iterator_string_ordering";
+ fs::path ph = m_args.GetDataDirBase() / "iterator_string_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) {
@@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(unicodepath)
// On Windows this test will fail if the directory is created using
// the ANSI CreateDirectoryA call and the code page isn't UTF8.
// It will succeed if created with CreateDirectoryW.
- fs::path ph = m_args.GetDataDirPath() / "test_runner_₿_🏃_20191128_104644";
+ fs::path ph = m_args.GetDataDirBase() / "test_runner_₿_🏃_20191128_104644";
CDBWrapper dbw(ph, (1 << 20));
fs::path lockPath = ph / "LOCK";
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index ddf0e0ca90..a56ce51acb 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_AUTO_TEST_CASE(peer_discouragement)
{
const CChainParams& chainparams = Params();
- auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
@@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
const CChainParams& chainparams = Params();
- auto banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.scheduler, *m_node.chainman, *m_node.mempool, false);
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 9194ed8130..f4bc320f3c 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -14,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(flatfile_filename)
{
- const auto data_dir = m_args.GetDataDirPath();
+ const auto data_dir = m_args.GetDataDirBase();
FlatFilePos pos(456, 789);
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename)
BOOST_AUTO_TEST_CASE(flatfile_open)
{
- const auto data_dir = m_args.GetDataDirPath();
+ const auto data_dir = m_args.GetDataDirBase();
FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online "
@@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
BOOST_AUTO_TEST_CASE(flatfile_allocate)
{
- const auto data_dir = m_args.GetDataDirPath();
+ const auto data_dir = m_args.GetDataDirBase();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
@@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate)
BOOST_AUTO_TEST_CASE(flatfile_flush)
{
- const auto data_dir = m_args.GetDataDirPath();
+ const auto data_dir = m_args.GetDataDirBase();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 452bc06bbb..526a3c27be 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -13,7 +13,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
- fs::path tmpfolder = m_args.GetDataDirPath();
+ fs::path tmpfolder = m_args.GetDataDirBase();
// tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃";
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index 8bf484722c..4a04eed463 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -34,7 +34,7 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
- const fs::path banlist_file = GetDataDir() / "fuzzed_banlist.dat";
+ const fs::path banlist_file = gArgs.GetDataDirNet() / "fuzzed_banlist.dat";
fs::remove(banlist_file);
{
BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)};
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 3e9998af30..bbec5943af 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -65,9 +65,6 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
connman.ForEachNode([](auto) {});
},
[&] {
- connman.ForEachNodeThen([](auto) {}, []() {});
- },
- [&] {
(void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
},
[&] {
diff --git a/src/test/fuzz/fee_rate.cpp b/src/test/fuzz/fee_rate.cpp
index 2955213635..dff0e58000 100644
--- a/src/test/fuzz/fee_rate.cpp
+++ b/src/test/fuzz/fee_rate.cpp
@@ -20,8 +20,8 @@ FUZZ_TARGET(fee_rate)
const CFeeRate fee_rate{satoshis_per_k};
(void)fee_rate.GetFeePerK();
- const size_t bytes = fuzzed_data_provider.ConsumeIntegral<size_t>();
- if (!MultiplicationOverflow(static_cast<int64_t>(bytes), satoshis_per_k) && bytes <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+ const auto bytes = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ if (!MultiplicationOverflow(int64_t{bytes}, satoshis_per_k)) {
(void)fee_rate.GetFee(bytes);
}
(void)fee_rate.ToString();
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
index e0d62fb493..fb6d23aca5 100644
--- a/src/test/fuzz/i2p.cpp
+++ b/src/test/fuzz/i2p.cpp
@@ -30,7 +30,7 @@ FUZZ_TARGET_INIT(i2p, initialize_i2p)
const CService sam_proxy;
CThreadInterrupt interrupt;
- i2p::sam::Session sess{GetDataDir() / "fuzzed_i2p_private_key", sam_proxy, &interrupt};
+ i2p::sam::Session sess{gArgs.GetDataDirNet() / "fuzzed_i2p_private_key", sam_proxy, &interrupt};
i2p::Connection conn;
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 272f6415a9..20d8581312 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -58,27 +58,6 @@ FUZZ_TARGET_INIT(net, initialize_net)
}
},
[&] {
- if (node.m_addr_known == nullptr) {
- return;
- }
- const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!addr_opt) {
- return;
- }
- node.AddAddressKnown(*addr_opt);
- },
- [&] {
- if (node.m_addr_known == nullptr) {
- return;
- }
- const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!addr_opt) {
- return;
- }
- FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
- node.PushAddress(*addr_opt, fast_random_context);
- },
- [&] {
const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
if (!inv_opt) {
return;
@@ -110,7 +89,6 @@ FUZZ_TARGET_INIT(net, initialize_net)
const int ref_count = node.GetRefCount();
assert(ref_count >= 0);
(void)node.GetCommonVersion();
- (void)node.RelayAddrsWithConn();
const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
(void)node.HasPermission(net_permission_flags);
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 0b42282b34..6f2bc081c6 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -30,7 +30,7 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain)
const auto& node = setup->m_node;
auto& chainman{*node.chainman};
- const auto snapshot_path = GetDataDir() / "fuzzed_snapshot.dat";
+ const auto snapshot_path = gArgs.GetDataDirNet() / "fuzzed_snapshot.dat";
Assert(!chainman.SnapshotBlockhash());
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
index 334f71106c..bd9ba4b8f7 100644
--- a/src/test/i2p_tests.cpp
+++ b/src/test/i2p_tests.cpp
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
};
CThreadInterrupt interrupt;
- i2p::sam::Session session(GetDataDir() / "test_i2p_private_key", CService{}, &interrupt);
+ i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", CService{}, &interrupt);
{
ASSERT_DEBUG_LOG("Creating SAM session");
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index f5ae9f86d1..340ce33d91 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(ReadWrite)
{
- fs::path path = m_args.GetDataDirPath() / "settings.json";
+ fs::path path = m_args.GetDataDirBase() / "settings.json";
WriteText(path, R"({
"string": "string",
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index f92e4c4b99..7bf7f9e0ba 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -195,7 +195,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
}
m_node.addrman = std::make_unique<CAddrMan>();
- m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirPath() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
m_node.banman.get(), *m_node.scheduler, *m_node.chainman,
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 534d28e5de..aa95bc37e5 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -53,23 +53,23 @@ BOOST_AUTO_TEST_CASE(util_datadir)
ArgsManager args;
args.ForceSetArg("-datadir", m_path_root.string());
- const fs::path dd_norm = args.GetDataDirPath();
+ const fs::path dd_norm = args.GetDataDirBase();
args.ForceSetArg("-datadir", dd_norm.string() + "/");
args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
args.ForceSetArg("-datadir", dd_norm.string() + "/.");
args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
args.ForceSetArg("-datadir", dd_norm.string() + "/./");
args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
args.ForceSetArg("-datadir", dd_norm.string() + "/.//");
args.ClearPathCache();
- BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirPath());
+ BOOST_CHECK_EQUAL(dd_norm, args.GetDataDirBase());
}
BOOST_AUTO_TEST_CASE(util_check)
@@ -1159,10 +1159,10 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
// Test error logging, and remove previously written setting.
{
ASSERT_DEBUG_LOG("Failed renaming settings file");
- fs::remove(args1.GetDataDirPath() / "settings.json");
- fs::create_directory(args1.GetDataDirPath() / "settings.json");
+ fs::remove(args1.GetDataDirBase() / "settings.json");
+ fs::create_directory(args1.GetDataDirBase() / "settings.json");
args2.WriteSettingsFile();
- fs::remove(args1.GetDataDirPath() / "settings.json");
+ fs::remove(args1.GetDataDirBase() / "settings.json");
}
}
@@ -1810,7 +1810,7 @@ static constexpr char ExitCommand = 'X';
BOOST_AUTO_TEST_CASE(test_LockDirectory)
{
- fs::path dirname = m_args.GetDataDirPath() / "lock_dir";
+ fs::path dirname = m_args.GetDataDirBase() / "lock_dir";
const std::string lockname = ".lock";
#ifndef WIN32
// Revert SIGCHLD to default, otherwise boost.test will catch and fail on
@@ -1899,7 +1899,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_AUTO_TEST_CASE(test_DirIsWritable)
{
// Should be able to write to the data dir.
- fs::path tmpdirname = m_args.GetDataDirPath();
+ fs::path tmpdirname = m_args.GetDataDirBase();
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 19d0a5da81..a0499fa51f 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -563,7 +563,7 @@ void TorController::Reconnect()
fs::path TorController::GetPrivateKeyFile()
{
- return GetDataDir() / "onion_v3_private_key";
+ return gArgs.GetDataDirNet() / "onion_v3_private_key";
}
void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 3a08e28c01..c11d46cf88 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -146,7 +146,7 @@ size_t CCoinsViewDB::EstimateSize() const
return m_db->EstimateSize(DB_COIN, (char)(DB_COIN+1));
}
-CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
+CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(gArgs.GetDataDirNet() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
}
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 9b3bd46b38..5b87806a45 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -366,14 +366,12 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
}
// we do not allow -includeconf from command line
- bool success = true;
if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
- for (const auto& include : util::SettingsSpan(*includes)) {
- error += "-includeconf cannot be used from commandline; -includeconf=" + include.get_str() + "\n";
- success = false;
- }
+ const auto& include{*util::SettingsSpan(*includes).begin()}; // pick first value as example
+ error = "-includeconf cannot be used from commandline; -includeconf=" + include.write();
+ return false;
}
- return success;
+ return true;
}
std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
@@ -388,7 +386,7 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co
return std::nullopt;
}
-const fs::path& ArgsManager::GetBlocksDirPath()
+const fs::path& ArgsManager::GetBlocksDirPath() const
{
LOCK(cs_args);
fs::path& path = m_cached_blocks_path;
@@ -404,7 +402,7 @@ const fs::path& ArgsManager::GetBlocksDirPath()
return path;
}
} else {
- path = GetDataDirPath(false);
+ path = GetDataDirBase();
}
path /= BaseParams().DataDir();
@@ -414,7 +412,7 @@ const fs::path& ArgsManager::GetBlocksDirPath()
return path;
}
-const fs::path& ArgsManager::GetDataDirPath(bool net_specific) const
+const fs::path& ArgsManager::GetDataDir(bool net_specific) const
{
LOCK(cs_args);
fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
@@ -513,7 +511,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
}
if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
- *filepath = fsbridge::AbsPathJoin(GetDataDirPath(/* net_specific= */ true), temp ? settings + ".tmp" : settings);
+ *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings);
}
return true;
}
@@ -802,11 +800,6 @@ fs::path GetDefaultDataDir()
#endif
}
-const fs::path &GetDataDir(bool fNetSpecific)
-{
- return gArgs.GetDataDirPath(fNetSpecific);
-}
-
bool CheckDataDirOption()
{
std::string datadir = gArgs.GetArg("-datadir", "");
@@ -1361,7 +1354,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
if (path.is_absolute()) {
return path;
}
- return fsbridge::AbsPathJoin(GetDataDir(net_specific), path);
+ return fsbridge::AbsPathJoin(net_specific ? gArgs.GetDataDirNet() : gArgs.GetDataDirBase(), path);
}
void ScheduleBatchPriority()
diff --git a/src/util/system.h b/src/util/system.h
index f68975ffa3..c4317c62d0 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -90,7 +90,6 @@ void ReleaseDirectoryLocks();
bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
-const fs::path &GetDataDir(bool fNetSpecific = true);
// Return true if -datadir option points to a valid directory or is not specified.
bool CheckDataDirOption();
fs::path GetConfigFile(const std::string& confPath);
@@ -119,7 +118,7 @@ UniValue RunCommandParseJSON(const std::string& str_command, const std::string&
* the datadir if they are not absolute.
*
* @param path The path to be conditionally prefixed with datadir.
- * @param net_specific Forwarded to GetDataDir().
+ * @param net_specific Use network specific datadir variant
* @return The normalized path.
*/
fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific = true);
@@ -195,7 +194,7 @@ protected:
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
bool m_accept_any_command GUARDED_BY(cs_args){true};
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
- fs::path m_cached_blocks_path GUARDED_BY(cs_args);
+ mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
@@ -266,16 +265,23 @@ public:
*
* @return Blocks path which is network specific
*/
- const fs::path& GetBlocksDirPath();
+ const fs::path& GetBlocksDirPath() const;
/**
* Get data directory path
*
- * @param net_specific Append network identifier to the returned path
* @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
* @post Returned directory path is created unless it is empty
*/
- const fs::path& GetDataDirPath(bool net_specific = true) const;
+ const fs::path& GetDataDirBase() const { return GetDataDir(false); }
+
+ /**
+ * Get data directory path with appended network identifier
+ *
+ * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
+ * @post Returned directory path is created unless it is empty
+ */
+ const fs::path& GetDataDirNet() const { return GetDataDir(true); }
/**
* Clear cached directory paths
@@ -437,6 +443,15 @@ public:
void LogArgs() const;
private:
+ /**
+ * Get data directory path
+ *
+ * @param net_specific Append network identifier to the returned path
+ * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
+ * @post Returned directory path is created unless it is empty
+ */
+ const fs::path& GetDataDir(bool net_specific) const;
+
// Helper function for LogArgs().
void logArgsPrefix(
const std::string& prefix,
diff --git a/src/validation.cpp b/src/validation.cpp
index 4f9b8687b7..f591e64fd4 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1150,7 +1150,7 @@ CoinsViews::CoinsViews(
size_t cache_size_bytes,
bool in_memory,
bool should_wipe) : m_dbview(
- GetDataDir() / ldb_name, cache_size_bytes, in_memory, should_wipe),
+ gArgs.GetDataDirNet() / ldb_name, cache_size_bytes, in_memory, should_wipe),
m_catcherview(&m_dbview) {}
void CoinsViews::InitCache()
@@ -2128,7 +2128,7 @@ bool CChainState::FlushStateToDisk(
// twice (once in the log, and once in the tables). This is already
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
- if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
+ if (!CheckDiskSpace(gArgs.GetDataDirNet(), 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
}
// Flush the chainstate (which may refer to block index entries).
@@ -4501,7 +4501,7 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mocka
{
const CChainParams& chainparams = Params();
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
- FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat", "rb")};
+ FILE* filestr{mockable_fopen_function(gArgs.GetDataDirNet() / "mempool.dat", "rb")};
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
@@ -4605,7 +4605,7 @@ bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function, bool s
int64_t mid = GetTimeMicros();
try {
- FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat.new", "wb")};
+ FILE* filestr{mockable_fopen_function(gArgs.GetDataDirNet() / "mempool.dat.new", "wb")};
if (!filestr) {
return false;
}
@@ -4631,7 +4631,7 @@ bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function, bool s
if (!skip_file_commit && !FileCommit(file.Get()))
throw std::runtime_error("FileCommit failed");
file.fclose();
- if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) {
+ if (!RenameOver(gArgs.GetDataDirNet() / "mempool.dat.new", gArgs.GetDataDirNet() / "mempool.dat")) {
throw std::runtime_error("Rename failed");
}
int64_t last = GetTimeMicros();
diff --git a/src/validation.h b/src/validation.h
index 1b50644185..adc3d282b6 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -82,8 +82,6 @@ static constexpr bool DEFAULT_COINSTATSINDEX{false};
static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
/** Default for -persistmempool */
static const bool DEFAULT_PERSIST_MEMPOOL = true;
-/** Default for using fee filter */
-static const bool DEFAULT_FEEFILTER = true;
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ::ChainActive().Tip() will not be pruned. */
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 4e3c8ce49d..a2124cc05e 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3430,12 +3430,10 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
"options"},
},
RPCResult{
- RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
- {
- {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction."},
- },
- want_psbt ? std::vector<RPCResult>{} : std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."}}
- ),
+ RPCResult::Type::OBJ, "", "", Cat(
+ want_psbt ?
+ std::vector<RPCResult>{{RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction."}} :
+ std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction."}},
{
{RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
{RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
@@ -3446,7 +3444,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
})
},
RPCExamples{
- "\nBump the fee, get the new transaction\'s" + std::string(want_psbt ? "psbt" : "txid") + "\n" +
+ "\nBump the fee, get the new transaction\'s " + std::string(want_psbt ? "psbt" : "txid") + "\n" +
HelpExampleCli(method_name, "<txid>")
},
[want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
@@ -3528,8 +3526,8 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
UniValue result(UniValue::VOBJ);
- // If wallet private keys are enabled, return the new transaction id,
- // otherwise return the base64-encoded unsigned PSBT of the new transaction.
+ // For bumpfee, return the new transaction id.
+ // For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
if (!want_psbt) {
if (!feebumper::SignTransaction(*pwallet, mtx)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index b2eb8e4bca..17f5264b45 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -23,7 +23,7 @@ static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, s
BOOST_AUTO_TEST_CASE(getwalletenv_file)
{
std::string test_name = "test_name.dat";
- const fs::path datadir = GetDataDir();
+ const fs::path datadir = gArgs.GetDataDirNet();
fs::path file_path = datadir / test_name;
std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR);
f.close();
@@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file)
BOOST_AUTO_TEST_CASE(getwalletenv_directory)
{
std::string expected_name = "wallet.dat";
- const fs::path datadir = GetDataDir();
+ const fs::path datadir = gArgs.GetDataDirNet();
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(datadir, filename);
@@ -47,8 +47,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_directory)
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
{
- fs::path datadir = GetDataDir() / "1";
- fs::path datadir_2 = GetDataDir() / "2";
+ fs::path datadir = gArgs.GetDataDirNet() / "1";
+ fs::path datadir_2 = gArgs.GetDataDirNet() / "2";
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env_1 = GetWalletEnv(datadir, filename);
@@ -61,8 +61,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance)
{
- fs::path datadir = GetDataDir() / "1";
- fs::path datadir_2 = GetDataDir() / "2";
+ fs::path datadir = gArgs.GetDataDirNet() / "1";
+ fs::path datadir_2 = gArgs.GetDataDirNet() / "2";
std::string filename;
std::shared_ptr <BerkeleyEnvironment> env_1_a = GetWalletEnv(datadir, filename);
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index f035a70a20..dd9354848d 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -16,7 +16,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
std::string sep;
sep += fs::path::preferred_separator;
- m_datadir = GetDataDir();
+ m_datadir = gArgs.GetDataDirNet();
m_cwd = fs::current_path();
m_walletdir_path_cases["default"] = m_datadir / "wallets";
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 512374c34f..34bb29f79f 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -253,7 +253,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
SetMockTime(KEY_TIME);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- std::string backup_file = (GetDataDir() / "wallet.backup").string();
+ std::string backup_file = (gArgs.GetDataDirNet() / "wallet.backup").string();
// Import key into wallet and call dumpwallet to create backup file.
{
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index dd2f071b6c..1c518daba6 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -19,7 +19,7 @@ fs::path GetWalletDir()
path = "";
}
} else {
- path = GetDataDir();
+ path = gArgs.GetDataDirNet();
// If a wallets directory exists, use that, otherwise default to GetDataDir
if (fs::is_directory(path / "wallets")) {
path /= "wallets";
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 6c51944d81..d25aaa070d 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -26,7 +26,10 @@ from test_framework.script import (
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
-from test_framework.wallet import MiniWallet
+from test_framework.wallet import (
+ MiniWallet,
+ MiniWalletMode,
+)
CLTV_HEIGHT = 1351
@@ -97,7 +100,7 @@ class BIP65Test(BitcoinTestFramework):
def run_test(self):
peer = self.nodes[0].add_p2p_connection(P2PInterface())
- wallet = MiniWallet(self.nodes[0], raw_script=True)
+ wallet = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_OP_TRUE)
self.test_cltv_info(is_active=False)
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index 28062590fd..5081867319 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -55,7 +55,10 @@ from test_framework.util import (
assert_equal,
softfork_active,
)
-from test_framework.wallet import MiniWallet
+from test_framework.wallet import (
+ MiniWallet,
+ MiniWalletMode,
+)
TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above)
COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs
@@ -90,7 +93,6 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.setup_clean_chain = True
self.extra_args = [[
'-whitelist=noban@127.0.0.1',
- '-acceptnonstdtxn=1',
'-par=1', # Use only one script thread to get the exact reject reason for testing
]]
self.supports_cli = False
@@ -103,12 +105,14 @@ class BIP68_112_113Test(BitcoinTestFramework):
def create_bip112special(self, input, txversion):
tx = self.create_self_transfer_from_utxo(input)
tx.nVersion = txversion
+ self.miniwallet.sign_tx(tx)
tx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig)))
return tx
def create_bip112emptystack(self, input, txversion):
tx = self.create_self_transfer_from_utxo(input)
tx.nVersion = txversion
+ self.miniwallet.sign_tx(tx)
tx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(tx.vin[0].scriptSig)))
return tx
@@ -126,6 +130,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
tx = self.create_self_transfer_from_utxo(bip68inputs[i])
tx.nVersion = txversion
tx.vin[0].nSequence = locktime + locktime_delta
+ self.miniwallet.sign_tx(tx)
tx.rehash()
txs.append({'tx': tx, 'sdf': sdf, 'stf': stf})
@@ -143,6 +148,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
else: # vary nSequence instead, OP_CSV is fixed
tx.vin[0].nSequence = locktime + locktime_delta
tx.nVersion = txversion
+ self.miniwallet.sign_tx(tx)
if (varyOP_CSV):
tx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig)))
else:
@@ -178,7 +184,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
def run_test(self):
self.helper_peer = self.nodes[0].add_p2p_connection(P2PDataStore())
- self.miniwallet = MiniWallet(self.nodes[0], raw_script=True)
+ self.miniwallet = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_P2PK)
self.log.info("Generate blocks in the past for coinbase outputs.")
long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future
@@ -285,7 +291,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
success_txs = []
# BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
- bip113tx_v1.rehash()
+ self.miniwallet.sign_tx(bip113tx_v1)
success_txs.append(bip113tx_v1)
success_txs.append(bip112tx_special_v1)
success_txs.append(bip112tx_emptystack_v1)
@@ -305,7 +311,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
success_txs = []
# BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
- bip113tx_v2.rehash()
+ self.miniwallet.sign_tx(bip113tx_v2)
success_txs.append(bip113tx_v2)
success_txs.append(bip112tx_special_v2)
success_txs.append(bip112tx_emptystack_v2)
@@ -331,16 +337,20 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.log.info("BIP 113 tests")
# BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
+ self.miniwallet.sign_tx(bip113tx_v1)
bip113tx_v1.rehash()
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
+ self.miniwallet.sign_tx(bip113tx_v2)
bip113tx_v2.rehash()
for bip113tx in [bip113tx_v1, bip113tx_v2]:
self.send_blocks([self.create_test_block([bip113tx])], success=False, reject_reason='bad-txns-nonfinal')
# BIP 113 tests should now pass if the locktime is < MTP
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
+ self.miniwallet.sign_tx(bip113tx_v1)
bip113tx_v1.rehash()
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
+ self.miniwallet.sign_tx(bip113tx_v2)
bip113tx_v2.rehash()
for bip113tx in [bip113tx_v1, bip113tx_v2]:
self.send_blocks([self.create_test_block([bip113tx])])
@@ -465,6 +475,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
time_txs = []
for tx in [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]:
tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG
+ self.miniwallet.sign_tx(tx)
tx.rehash()
time_txs.append(tx)
diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py
index f22b7f266a..448182eded 100755
--- a/test/functional/feature_includeconf.py
+++ b/test/functional/feature_includeconf.py
@@ -42,7 +42,14 @@ class IncludeConfTest(BitcoinTestFramework):
self.log.info("-includeconf cannot be used as command-line arg")
self.stop_node(0)
- self.nodes[0].assert_start_raises_init_error(extra_args=["-includeconf=relative2.conf"], expected_msg="Error: Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=relative2.conf")
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=['-noincludeconf=0'],
+ expected_msg='Error: Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=true',
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=['-includeconf=relative2.conf', '-includeconf=no_warn.conf'],
+ expected_msg='Error: Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf="relative2.conf"',
+ )
self.log.info("-includeconf cannot be used recursively. subversion should end with 'main; relative)/'")
with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "a", encoding="utf8") as f:
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 57b0a170f0..05bda5d899 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -5,7 +5,9 @@
"""A limited-functionality wallet, which may replace a real wallet in tests"""
from decimal import Decimal
+from enum import Enum
from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
+from test_framework.key import ECKey
from test_framework.messages import (
COIN,
COutPoint,
@@ -16,8 +18,11 @@ from test_framework.messages import (
)
from test_framework.script import (
CScript,
+ LegacySignatureHash,
+ OP_CHECKSIG,
OP_TRUE,
OP_NOP,
+ SIGHASH_ALL,
)
from test_framework.util import (
assert_equal,
@@ -26,14 +31,46 @@ from test_framework.util import (
)
+class MiniWalletMode(Enum):
+ """Determines the transaction type the MiniWallet is creating and spending.
+
+ For most purposes, the default mode ADDRESS_OP_TRUE should be sufficient;
+ it simply uses a fixed bech32 P2WSH address whose coins are spent with a
+ witness stack of OP_TRUE, i.e. following an anyone-can-spend policy.
+ However, if the transactions need to be modified by the user (e.g. prepending
+ scriptSig for testing opcodes that are activated by a soft-fork), or the txs
+ should contain an actual signature, the raw modes RAW_OP_TRUE and RAW_P2PK
+ can be useful. Summary of modes:
+
+ | output | | tx is | can modify | needs
+ mode | description | address | standard | scriptSig | signing
+ ----------------+-------------------+-----------+----------+------------+----------
+ ADDRESS_OP_TRUE | anyone-can-spend | bech32 | yes | no | no
+ RAW_OP_TRUE | anyone-can-spend | - (raw) | no | yes | no
+ RAW_P2PK | pay-to-public-key | - (raw) | yes | yes | yes
+ """
+ ADDRESS_OP_TRUE = 1
+ RAW_OP_TRUE = 2
+ RAW_P2PK = 3
+
+
class MiniWallet:
- def __init__(self, test_node, *, raw_script=False):
+ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE):
self._test_node = test_node
self._utxos = []
- if raw_script:
- self._address = None
+ self._priv_key = None
+ self._address = None
+
+ assert isinstance(mode, MiniWalletMode)
+ if mode == MiniWalletMode.RAW_OP_TRUE:
self._scriptPubKey = bytes(CScript([OP_TRUE]))
- else:
+ elif mode == MiniWalletMode.RAW_P2PK:
+ # use simple deterministic private key (k=1)
+ self._priv_key = ECKey()
+ self._priv_key.set((1).to_bytes(32, 'big'), True)
+ pub_key = self._priv_key.get_pubkey()
+ self._scriptPubKey = bytes(CScript([pub_key.get_bytes(), OP_CHECKSIG]))
+ elif mode == MiniWalletMode.ADDRESS_OP_TRUE:
self._address = ADDRESS_BCRT1_P2WSH_OP_TRUE
self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey'])
@@ -50,6 +87,13 @@ class MiniWallet:
if out['scriptPubKey']['hex'] == self._scriptPubKey.hex():
self._utxos.append({'txid': tx['txid'], 'vout': out['n'], 'value': out['value']})
+ def sign_tx(self, tx):
+ """Sign tx that has been created by MiniWallet in P2PK mode"""
+ assert self._priv_key is not None
+ (sighash, err) = LegacySignatureHash(CScript(self._scriptPubKey), tx, 0, SIGHASH_ALL)
+ assert err is None
+ tx.vin[0].scriptSig = CScript([self._priv_key.sign_ecdsa(sighash) + bytes(bytearray([SIGHASH_ALL]))])
+
def generate(self, num_blocks):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
blocks = self._test_node.generatetodescriptor(num_blocks, f'raw({self._scriptPubKey.hex()})')
@@ -99,7 +143,12 @@ class MiniWallet:
tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)]
if not self._address:
# raw script
- tx.vin[0].scriptSig = CScript([OP_NOP] * 35) # pad to identical size
+ if self._priv_key is not None:
+ # P2PK, need to sign
+ self.sign_tx(tx)
+ else:
+ # anyone-can-spend
+ tx.vin[0].scriptSig = CScript([OP_NOP] * 35) # pad to identical size
else:
tx.wit.vtxinwit = [CTxInWitness()]
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
@@ -108,7 +157,10 @@ class MiniWallet:
tx_info = from_node.testmempoolaccept([tx_hex])[0]
assert_equal(mempool_valid, tx_info['allowed'])
if mempool_valid:
- assert_equal(tx_info['vsize'], vsize)
+ # TODO: for P2PK, vsize is not constant due to varying scriptSig length,
+ # so only check this for anyone-can-spend outputs right now
+ if self._priv_key is None:
+ assert_equal(tx_info['vsize'], vsize)
assert_equal(tx_info['fees']['base'], fee)
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}