diff options
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"); @@ -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} |