aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--REVIEWERS2
-rw-r--r--configure.ac4
-rw-r--r--contrib/devtools/README.md15
-rwxr-xr-xcontrib/devtools/copyright_header.py10
-rwxr-xr-xcontrib/devtools/gen-bitcoin-conf.sh83
-rwxr-xr-xcontrib/guix/libexec/build.sh4
-rw-r--r--contrib/guix/manifest.scm5
-rwxr-xr-xcontrib/linearize/linearize-data.py37
-rwxr-xr-xcontrib/linearize/linearize-hashes.py25
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus2
-rwxr-xr-xcontrib/verify-commits/verify-commits.py15
-rw-r--r--depends/Makefile3
-rw-r--r--depends/builders/darwin.mk2
-rw-r--r--depends/builders/default.mk4
-rw-r--r--depends/config.site.in23
-rw-r--r--depends/funcs.mk2
-rw-r--r--depends/hosts/darwin.mk2
-rw-r--r--depends/hosts/default.mk4
-rw-r--r--depends/packages/libmultiprocess.mk10
-rw-r--r--doc/bitcoin-conf.md10
-rw-r--r--doc/dependencies.md1
-rw-r--r--doc/release-process.md1
-rw-r--r--share/examples/bitcoin.conf192
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/bench/strencodings.cpp18
-rw-r--r--src/bitcoind.cpp3
-rw-r--r--src/core_read.cpp8
-rw-r--r--src/fs.cpp3
-rw-r--r--src/httprpc.cpp8
-rw-r--r--src/init.cpp8
-rw-r--r--src/net.cpp32
-rw-r--r--src/net.h14
-rw-r--r--src/netgroup.cpp2
-rw-r--r--src/node/miner.h2
-rw-r--r--src/rpc/net.cpp18
-rw-r--r--src/test/fuzz/string.cpp7
-rw-r--r--src/test/miner_tests.cpp185
-rw-r--r--src/test/util_tests.cpp31
-rw-r--r--src/torcontrol.cpp4
-rw-r--r--src/util/sock.cpp16
-rw-r--r--src/util/spanparsing.h20
-rw-r--r--src/util/strencodings.cpp33
-rw-r--r--src/util/string.cpp7
-rw-r--r--src/util/string.h10
-rw-r--r--src/util/syserror.cpp34
-rw-r--r--src/util/syserror.h16
-rw-r--r--src/util/system.cpp6
-rw-r--r--src/validation.cpp5
-rw-r--r--src/wallet/wallet.cpp14
-rw-r--r--test/README.md2
-rwxr-xr-xtest/functional/feature_config_args.py3
-rwxr-xr-xtest/functional/feature_versionbits_warning.py3
-rwxr-xr-xtest/lint/lint-includes.py5
-rwxr-xr-xtest/lint/lint-locale-dependence.py8
-rwxr-xr-xtest/lint/lint-shell.py93
-rwxr-xr-xtest/lint/lint-shell.sh33
-rwxr-xr-xtest/util/test_runner.py12
59 files changed, 688 insertions, 438 deletions
diff --git a/Makefile.am b/Makefile.am
index dd658170b3..05e89f12b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -133,7 +133,7 @@ $(OSX_DMG): deploydir
$(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))
$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING)
- INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR)
+ INSTALL_NAME_TOOL=$(INSTALL_NAME_TOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR)
deploydir: $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt
endif !BUILD_DARWIN
diff --git a/REVIEWERS b/REVIEWERS
index a4b05f86c0..dd962947ff 100644
--- a/REVIEWERS
+++ b/REVIEWERS
@@ -112,7 +112,7 @@
/src/dbwrapper.* @jamesob
# Linter
-/test/lint/lint-shell.sh @hebasto
+/test/lint/lint-shell.py @hebasto
# Bech32
/src/bech32.* @sipa
diff --git a/configure.ac b/configure.ac
index ea97b1b1d9..0539826edf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -108,8 +108,6 @@ LT_INIT([pic-only win32-dll])
dnl Check/return PATH for base programs.
AC_PATH_TOOL([AR], [ar])
-AC_PATH_TOOL([RANLIB], [ranlib])
-AC_PATH_TOOL([STRIP], [strip])
AC_PATH_TOOL([GCOV], [gcov])
AC_PATH_TOOL([LLVM_COV], [llvm-cov])
AC_PATH_PROG([LCOV], [lcov])
@@ -781,7 +779,7 @@ case $host in
;;
*)
AC_PATH_TOOL([DSYMUTIL], [dsymutil], [dsymutil])
- AC_PATH_TOOL([INSTALLNAMETOOL], [install_name_tool], [install_name_tool])
+ AC_PATH_TOOL([INSTALL_NAME_TOOL], [install_name_tool], [install_name_tool])
AC_PATH_TOOL([OTOOL], [otool], [otool])
AC_PATH_PROGS([XORRISOFS], [xorrisofs], [xorrisofs])
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index 79b0134adc..54b1a85588 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -90,6 +90,21 @@ example:
BUILDDIR=$PWD/build contrib/devtools/gen-manpages.py
```
+gen-bitcoin-conf.sh
+===================
+
+Generates a bitcoin.conf file in `share/examples/` by parsing the output from `bitcoind --help`. This script is run during the
+release process to include a bitcoin.conf with the release binaries and can also be run by users to generate a file locally.
+When generating a file as part of the release process, make sure to commit the changes after running the script.
+
+With in-tree builds this tool can be run from any directory within the
+repository. To use this tool with out-of-tree builds set `BUILDDIR`. For
+example:
+
+```bash
+BUILDDIR=$PWD/build contrib/devtools/gen-bitcoin-conf.sh
+```
+
security-check.py and test-security-check.py
============================================
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index 38f3df77c9..e20eb4b0d2 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -320,15 +320,13 @@ def get_most_recent_git_change_year(filename):
################################################################################
def read_file_lines(filename):
- f = open(filename, 'r', encoding="utf8")
- file_lines = f.readlines()
- f.close()
+ with open(filename, 'r', encoding="utf8") as f:
+ file_lines = f.readlines()
return file_lines
def write_file_lines(filename, file_lines):
- f = open(filename, 'w', encoding="utf8")
- f.write(''.join(file_lines))
- f.close()
+ with open(filename, 'w', encoding="utf8") as f:
+ f.write(''.join(file_lines))
################################################################################
# update header years execution
diff --git a/contrib/devtools/gen-bitcoin-conf.sh b/contrib/devtools/gen-bitcoin-conf.sh
new file mode 100755
index 0000000000..2ebbd42022
--- /dev/null
+++ b/contrib/devtools/gen-bitcoin-conf.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+export LC_ALL=C
+TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
+BUILDDIR=${BUILDDIR:-$TOPDIR}
+BINDIR=${BINDIR:-$BUILDDIR/src}
+BITCOIND=${BITCOIND:-$BINDIR/bitcoind}
+SHARE_EXAMPLES_DIR=${SHARE_EXAMPLES_DIR:-$TOPDIR/share/examples}
+EXAMPLE_CONF_FILE=${EXAMPLE_CONF_FILE:-$SHARE_EXAMPLES_DIR/bitcoin.conf}
+
+[ ! -x "$BITCOIND" ] && echo "$BITCOIND not found or not executable." && exit 1
+
+DIRTY=""
+VERSION_OUTPUT=$($BITCOIND --version)
+if [[ $VERSION_OUTPUT == *"dirty"* ]]; then
+ DIRTY="${DIRTY}${BITCOIND}\n"
+fi
+
+if [ -n "$DIRTY" ]
+then
+ echo -e "WARNING: $BITCOIND was built from a dirty tree.\n"
+ echo -e "To safely generate a bitcoin.conf file, please commit your changes to $BITCOIND, rebuild, then run this script again.\n"
+fi
+
+echo 'Generating example bitcoin.conf file in share/examples/'
+
+# create the directory, if it doesn't exist
+mkdir -p "${SHARE_EXAMPLES_DIR}"
+
+# create the header text
+cat > "${EXAMPLE_CONF_FILE}" << 'EOF'
+##
+## bitcoin.conf configuration file.
+## Generated by contrib/devtools/gen-bitcoin-conf.sh.
+##
+## Lines beginning with # are comments.
+## All possible configuration options are provided. To use, copy this file
+## to your data directory (default or specified by -datadir), uncomment
+## options you would like to change, and save the file.
+##
+
+
+### Options
+EOF
+
+# parse the output from bitcoind --help
+# adding newlines is a bit funky to ensure portability for BSD
+# see here for more details: https://stackoverflow.com/a/24575385
+${BITCOIND} --help \
+ | sed '1,/Print this help message and exit/d' \
+ | sed -E 's/^[[:space:]]{2}\-/#/' \
+ | sed -E 's/^[[:space:]]{7}/# /' \
+ | sed -E '/[=[:space:]]/!s/#.*$/&=1/' \
+ | awk '/^#[a-z]/{x=$0;next}{if (NF==0) print x"\n",x="";else print}' \
+ | sed 's,\(^[[:upper:]].*\)\:$,\
+### \1,' \
+ | sed 's/[[:space:]]*$//' >> "${EXAMPLE_CONF_FILE}"
+
+# create the footer text
+cat >> "${EXAMPLE_CONF_FILE}" << 'EOF'
+
+# [Sections]
+# Most options will apply to all networks. To confine an option to a specific
+# network, add it under the relevant section below.
+#
+# Note: If not specified under a network section, the options addnode, connect,
+# port, bind, rpcport, rpcbind, and wallet will only apply to mainnet.
+
+# Options for mainnet
+[main]
+
+# Options for testnet
+[test]
+
+# Options for signet
+[signet]
+
+# Options for regtest
+[regtest]
+EOF
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 2757d10a7c..cdf0020d4d 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -368,6 +368,10 @@ mkdir -p "$DISTSRC"
;;
esac
+ # copy over the example bitcoin.conf file. if contrib/devtools/gen-bitcoin-conf.sh
+ # has not been run before buildling, this file will be a stub
+ cp "${DISTSRC}/share/examples/bitcoin.conf" "${DISTNAME}/"
+
# Finally, deterministically produce {non-,}debug binary tarballs ready
# for release
case "$HOST" in
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 9f8a4008cf..b61c2b8899 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -130,6 +130,7 @@ chain for " target " development."))
(license (package-license xgcc)))))
(define base-gcc gcc-10)
+(define base-linux-kernel-headers linux-libre-headers-5.15)
;; Building glibc with stack smashing protector first landed in glibc 2.25, use
;; this function to disable for older glibcs
@@ -148,7 +149,7 @@ chain for " target " development."))
(define* (make-bitcoin-cross-toolchain target
#:key
(base-gcc-for-libc gcc-7)
- (base-kernel-headers linux-libre-headers-4.9)
+ (base-kernel-headers base-linux-kernel-headers)
(base-libc (make-glibc-without-ssp glibc-2.24))
(base-gcc (make-gcc-rpath-link base-gcc)))
"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values
@@ -604,7 +605,7 @@ inspecting signatures in Mach-O binaries.")
(cond ((string-contains target "riscv64-")
(make-bitcoin-cross-toolchain target
#:base-libc glibc-2.27/bitcoin-patched
- #:base-kernel-headers linux-libre-headers-4.19))
+ #:base-kernel-headers base-linux-kernel-headers))
(else
(make-bitcoin-cross-toolchain target)))))
((string-contains target "darwin")
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 7510204bb1..b72c7b0d08 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -34,12 +34,12 @@ def get_blk_dt(blk_hdr):
# When getting the list of block hashes, undo any byte reversals.
def get_block_hashes(settings):
blkindex = []
- f = open(settings['hashlist'], "r", encoding="utf8")
- for line in f:
- line = line.rstrip()
- if settings['rev_hash_bytes'] == 'true':
- line = bytes.fromhex(line)[::-1].hex()
- blkindex.append(line)
+ with open(settings['hashlist'], "r", encoding="utf8") as f:
+ for line in f:
+ line = line.rstrip()
+ if settings['rev_hash_bytes'] == 'true':
+ line = bytes.fromhex(line)[::-1].hex()
+ blkindex.append(line)
print("Read " + str(len(blkindex)) + " hashes")
@@ -249,19 +249,18 @@ if __name__ == '__main__':
print("Usage: linearize-data.py CONFIG-FILE")
sys.exit(1)
- f = open(sys.argv[1], encoding="utf8")
- for line in f:
- # skip comment lines
- m = re.search(r'^\s*#', line)
- if m:
- continue
-
- # parse key=value lines
- m = re.search(r'^(\w+)\s*=\s*(\S.*)$', line)
- if m is None:
- continue
- settings[m.group(1)] = m.group(2)
- f.close()
+ with open(sys.argv[1], encoding="utf8") as f:
+ for line in f:
+ # skip comment lines
+ m = re.search(r'^\s*#', line)
+ if m:
+ continue
+
+ # parse key=value lines
+ m = re.search(r'^(\w+)\s*=\s*(\S.*)$', line)
+ if m is None:
+ continue
+ settings[m.group(1)] = m.group(2)
# Force hash byte format setting to be lowercase to make comparisons easier.
# Also place upfront in case any settings need to know about it.
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 0a316eb818..5959300e74 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -98,19 +98,18 @@ if __name__ == '__main__':
print("Usage: linearize-hashes.py CONFIG-FILE")
sys.exit(1)
- f = open(sys.argv[1], encoding="utf8")
- for line in f:
- # skip comment lines
- m = re.search(r'^\s*#', line)
- if m:
- continue
-
- # parse key=value lines
- m = re.search(r'^(\w+)\s*=\s*(\S.*)$', line)
- if m is None:
- continue
- settings[m.group(1)] = m.group(2)
- f.close()
+ with open(sys.argv[1], encoding="utf8") as f:
+ for line in f:
+ # skip comment lines
+ m = re.search(r'^\s*#', line)
+ if m:
+ continue
+
+ # parse key=value lines
+ m = re.search(r'^(\w+)\s*=\s*(\S.*)$', line)
+ if m is None:
+ continue
+ settings[m.group(1)] = m.group(2)
if 'host' not in settings:
settings['host'] = '127.0.0.1'
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index cc24e0317b..2420539b7c 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -211,7 +211,7 @@ def getFrameworks(binaryPath: str, verbose: int) -> List[FrameworkInfo]:
return libraries
def runInstallNameTool(action: str, *args):
- installnametoolbin=os.getenv("INSTALLNAMETOOL", "install_name_tool")
+ installnametoolbin=os.getenv("INSTALL_NAME_TOOL", "install_name_tool")
run([installnametoolbin, "-"+action] + list(args), check=True)
def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int):
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index 7e46c6fd47..2ff14c1f86 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -82,11 +82,16 @@ def main():
# get directory of this program and read data files
dirname = os.path.dirname(os.path.abspath(__file__))
print("Using verify-commits data from " + dirname)
- verified_root = open(dirname + "/trusted-git-root", "r", encoding="utf8").read().splitlines()[0]
- verified_sha512_root = open(dirname + "/trusted-sha512-root-commit", "r", encoding="utf8").read().splitlines()[0]
- revsig_allowed = open(dirname + "/allow-revsig-commits", "r", encoding="utf-8").read().splitlines()
- unclean_merge_allowed = open(dirname + "/allow-unclean-merge-commits", "r", encoding="utf-8").read().splitlines()
- incorrect_sha512_allowed = open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf-8").read().splitlines()
+ with open(dirname + "/trusted-git-root", "r", encoding="utf8") as f:
+ verified_root = f.read().splitlines()[0]
+ with open(dirname + "/trusted-sha512-root-commit", "r", encoding="utf8") as f:
+ verified_sha512_root = f.read().splitlines()[0]
+ with open(dirname + "/allow-revsig-commits", "r", encoding="utf8") as f:
+ revsig_allowed = f.read().splitlines()
+ with open(dirname + "/allow-unclean-merge-commits", "r", encoding="utf8") as f:
+ unclean_merge_allowed = f.read().splitlines()
+ with open(dirname + "/allow-incorrect-sha512-commits", "r", encoding="utf8") as f:
+ incorrect_sha512_allowed = f.read().splitlines()
# Set commit and branch and set variables
current_commit = args.commit
diff --git a/depends/Makefile b/depends/Makefile
index b901533786..20f5f6b2c6 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -222,6 +222,9 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@RANLIB@|$(host_RANLIB)|' \
-e 's|@NM@|$(host_NM)|' \
-e 's|@STRIP@|$(host_STRIP)|' \
+ -e 's|@OTOOL@|$(host_OTOOL)|' \
+ -e 's|@INSTALL_NAME_TOOL@|$(host_INSTALL_NAME_TOOL)|' \
+ -e 's|@DSYMUTIL@|$(host_DSYMUTIL)|' \
-e 's|@build_os@|$(build_os)|' \
-e 's|@host_os@|$(host_os)|' \
-e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \
diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk
index ced01229dd..8ed82b276d 100644
--- a/depends/builders/darwin.mk
+++ b/depends/builders/darwin.mk
@@ -6,6 +6,7 @@ build_darwin_STRIP:=$(shell xcrun -f strip)
build_darwin_OTOOL:=$(shell xcrun -f otool)
build_darwin_NM:=$(shell xcrun -f nm)
build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool)
+build_darwin_DSYMUTIL:=$(shell xcrun -f dsymutil)
build_darwin_SHA256SUM=shasum -a 256
build_darwin_DOWNLOAD=curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o
@@ -19,6 +20,7 @@ darwin_LIBTOOL:=$(shell xcrun -f libtool)
darwin_OTOOL:=$(shell xcrun -f otool)
darwin_NM:=$(shell xcrun -f nm)
darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool)
+darwin_DSYMUTIL:=$(shell xcrun -f dsymutil)
darwin_native_binutils=
darwin_native_toolchain=
diff --git a/depends/builders/default.mk b/depends/builders/default.mk
index 0370fb9acb..cc6dec66c2 100644
--- a/depends/builders/default.mk
+++ b/depends/builders/default.mk
@@ -5,15 +5,13 @@ default_build_TAR = tar
default_build_RANLIB = ranlib
default_build_STRIP = strip
default_build_NM = nm
-default_build_OTOOL = otool
-default_build_INSTALL_NAME_TOOL = install_name_tool
define add_build_tool_func
build_$(build_os)_$1 ?= $$(default_build_$1)
build_$(build_arch)_$(build_os)_$1 ?= $$(build_$(build_os)_$1)
build_$1=$$(build_$(build_arch)_$(build_os)_$1)
endef
-$(foreach var,CC CXX AR TAR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL,$(eval $(call add_build_tool_func,$(var))))
+$(foreach var,CC CXX AR TAR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL DSYMUTIL,$(eval $(call add_build_tool_func,$(var))))
define add_build_flags_func
build_$(build_arch)_$(build_os)_$1 += $(build_$(build_os)_$1)
build_$1=$$(build_$(build_arch)_$(build_os)_$1)
diff --git a/depends/config.site.in b/depends/config.site.in
index 95e6ae85cf..03dabeea0a 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -78,7 +78,6 @@ if test "@host_os@" = darwin; then
BREW=no
fi
-PATH="${depends_prefix}/native/bin:${PATH}"
PKG_CONFIG="$(which pkg-config) --static"
# These two need to remain exported because pkg-config does not see them
@@ -115,6 +114,28 @@ if test -n "@NM@"; then
ac_cv_path_ac_pt_NM="${NM}"
fi
+if test -n "@STRIP@"; then
+ STRIP="@STRIP@"
+ ac_cv_path_ac_pt_STRIP="${STRIP}"
+fi
+
+if test "@host_os@" = darwin; then
+ if test -n "@OTOOL@"; then
+ OTOOL="@OTOOL@"
+ ac_cv_path_ac_pt_OTOOL="${OTOOL}"
+ fi
+
+ if test -n "@INSTALL_NAME_TOOL@"; then
+ INSTALL_NAME_TOOL="@INSTALL_NAME_TOOL@"
+ ac_cv_path_ac_pt_INSTALL_NAME_TOOL="${INSTALL_NAME_TOOL}"
+ fi
+
+ if test -n "@DSYMUTIL@"; then
+ DSYMUTIL="@DSYMUTIL@"
+ ac_cv_path_ac_pt_DSYMUTIL="${DSYMUTIL}"
+ fi
+fi
+
if test -n "@debug@"; then
enable_reduce_exports=no
fi
diff --git a/depends/funcs.mk b/depends/funcs.mk
index 75fa1ed43f..a00f380236 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -175,7 +175,7 @@ $(1)_cmake=env CC="$$($(1)_cc)" \
CXX="$$($(1)_cxx)" \
CXXFLAGS="$$($(1)_cppflags) $$($(1)_cxxflags)" \
LDFLAGS="$$($(1)_ldflags)" \
- cmake -DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)"
+ cmake -DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" $$($(1)_cmake_opts)
ifeq ($($(1)_type),build)
$(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH="$$($($(1)_type)_prefix)/lib"
else
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 6bf30b499a..bf9b7625f2 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -38,7 +38,7 @@ clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++")
clang_resource_dir=$(shell clang -print-resource-dir)
endif
-cctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL
+cctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL DSYMUTIL
# Make-only lowercase function
lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk
index 258619a9d0..ea60f025de 100644
--- a/depends/hosts/default.mk
+++ b/depends/hosts/default.mk
@@ -8,8 +8,6 @@ default_host_AR = $(host_toolchain)ar
default_host_RANLIB = $(host_toolchain)ranlib
default_host_STRIP = $(host_toolchain)strip
default_host_LIBTOOL = $(host_toolchain)libtool
-default_host_INSTALL_NAME_TOOL = $(host_toolchain)install_name_tool
-default_host_OTOOL = $(host_toolchain)otool
default_host_NM = $(host_toolchain)nm
define add_host_tool_func
@@ -35,5 +33,5 @@ host_$1 = $$($(host_arch)_$(host_os)_$1)
host_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1)
endef
-$(foreach tool,CC CXX AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL,$(eval $(call add_host_tool_func,$(tool))))
+$(foreach tool,CC CXX AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL DSYMUTIL,$(eval $(call add_host_tool_func,$(tool))))
$(foreach flags,CFLAGS CXXFLAGS CPPFLAGS LDFLAGS, $(eval $(call add_host_flags_func,$(flags))))
diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk
index 864e33bc9a..9b66207fc5 100644
--- a/depends/packages/libmultiprocess.mk
+++ b/depends/packages/libmultiprocess.mk
@@ -4,6 +4,16 @@ $(package)_download_path=$(native_$(package)_download_path)
$(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_dependencies=native_$(package) capnp
+ifneq ($(host),$(build))
+$(package)_dependencies += native_capnp
+endif
+
+define $(package)_set_vars :=
+ifneq ($(host),$(build))
+$(package)_cmake_opts := -DCAPNP_EXECUTABLE="$$(native_capnp_prefixbin)/capnp"
+$(package)_cmake_opts += -DCAPNPC_CXX_EXECUTABLE="$$(native_capnp_prefixbin)/capnpc-c++"
+endif
+endef
define $(package)_config_cmds
$($(package)_cmake) .
diff --git a/doc/bitcoin-conf.md b/doc/bitcoin-conf.md
index 8c9035c45b..acd767f234 100644
--- a/doc/bitcoin-conf.md
+++ b/doc/bitcoin-conf.md
@@ -61,4 +61,12 @@ Windows | `%APPDATA%\Bitcoin\` | `C:\Users\username\AppData\Roaming\Bitcoin\bitc
Linux | `$HOME/.bitcoin/` | `/home/username/.bitcoin/bitcoin.conf`
macOS | `$HOME/Library/Application Support/Bitcoin/` | `/Users/username/Library/Application Support/Bitcoin/bitcoin.conf`
-You can find an example bitcoin.conf file in [share/examples/bitcoin.conf](../share/examples/bitcoin.conf).
+An example configuration file can be generated by [contrib/devtools/gen-bitcoin-conf.sh](../contrib/devtools/gen-bitcoin-conf.sh).
+Run this script after compiling to generate an up-to-date configuration file.
+The output is placed under `share/examples/bitcoin.conf`.
+To use the generated configuration file, copy the example file into your data directory and edit it there, like so:
+
+```
+# example copy command for linux user
+cp share/examples/bitcoin.conf ~/.bitcoin
+```
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 392078bfaf..697d432520 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -20,6 +20,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.77.0](https://github.com/bitcoin/bitcoin/pull/24383) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No |
| [libevent](../depends/packages/libevent.mk) | [link](https://github.com/libevent/libevent/releases) | [2.1.12-stable](https://github.com/bitcoin/bitcoin/pull/21991) | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No |
| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.18](https://github.com/bitcoin/bitcoin/pull/23511) | Yes |
+| Linux Kernel | [link](https://www.kernel.org/) | N/A | 3.2.0 | Yes |
## Optional
diff --git a/doc/release-process.md b/doc/release-process.md
index 2f3a163a8e..03cea6f194 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -8,6 +8,7 @@ Release Process
* Update translations see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#synchronising-translations).
* Update release candidate version in `configure.ac` (`CLIENT_VERSION_RC`).
* Update manpages (after rebuilding the binaries), see [gen-manpages.py](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagespy).
+* Update bitcoin.conf and commit, see [gen-bitcoin-conf.sh](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-bitcoin-confsh).
### Before every major and minor release
diff --git a/share/examples/bitcoin.conf b/share/examples/bitcoin.conf
index c5b79709c7..5bee4bf92e 100644
--- a/share/examples/bitcoin.conf
+++ b/share/examples/bitcoin.conf
@@ -1,191 +1 @@
-##
-## bitcoin.conf configuration file. Lines beginning with # are comments.
-##
-
-# Network-related settings:
-
-# Note that if you use testnet, signet or regtest, particularly with the options
-# addnode, connect, port, bind, rpcport, rpcbind or wallet, you will also
-# want to read "[Sections]" further down.
-
-# Run on the testnet network
-#testnet=0
-
-# Run on a signet network
-#signet=0
-
-# Run a regression test network
-#regtest=0
-
-# Connect via a SOCKS5 proxy
-#proxy=127.0.0.1:9050
-
-# Bind to given address and always listen on it. Use [host]:port notation for IPv6
-#bind=<addr>
-
-# Bind to given address and add permission flags to peers connecting to it. Use [host]:port notation for IPv6
-#whitebind=perm@<addr>
-
-##############################################################
-## Quick Primer on addnode vs connect ##
-## Let's say for instance you use addnode=4.2.2.4 ##
-## addnode will connect you to and tell you about the ##
-## nodes connected to 4.2.2.4. In addition it will tell ##
-## the other nodes connected to it that you exist so ##
-## they can connect to you. ##
-## connect will not do the above when you 'connect' to it. ##
-## It will *only* connect you to 4.2.2.4 and no one else.##
-## ##
-## So if you're behind a firewall, or have other problems ##
-## finding nodes, add some using 'addnode'. ##
-## ##
-## If you want to stay private, use 'connect' to only ##
-## connect to "trusted" nodes. ##
-## ##
-## If you run multiple nodes on a LAN, there's no need for ##
-## all of them to open lots of connections. Instead ##
-## 'connect' them all to one node that is port forwarded ##
-## and has lots of connections. ##
-## Thanks goes to [Noodle] on Freenode. ##
-##############################################################
-
-# Use as many addnode= settings as you like to connect to specific peers
-#addnode=69.164.218.197
-#addnode=10.0.0.2:8333
-
-# Alternatively use as many connect= settings as you like to connect ONLY to specific peers
-#connect=69.164.218.197
-#connect=10.0.0.1:8333
-
-# Listening mode, enabled by default except when 'connect' is being used
-#listen=1
-
-# Port on which to listen for connections (default: 8333, testnet: 18333, signet: 38333, regtest: 18444)
-#port=
-
-# Maximum number of inbound + outbound connections (default: 125). This option
-# applies only if inbound connections are enabled; otherwise, the number of connections
-# will not be more than 11: 8 full-relay connections, 2 block-relay-only ones, and
-# occasionally 1 short-lived feeler or extra outbound block-relay-only connection.
-# These limits do not apply to connections added manually with the -addnode
-# configuration option or the addnode RPC, which have a separate limit of 8 connections.
-#maxconnections=
-
-# Maximum upload bandwidth target in MiB per day (e.g. 'maxuploadtarget=1024' is 1 GiB per day).
-# This limits the upload bandwidth for those with bandwidth limits. 0 = no limit (default: 0).
-# -maxuploadtarget does not apply to peers with 'download' permission.
-# For more information on reducing bandwidth utilization, see: doc/reduce-traffic.md.
-#maxuploadtarget=
-
-#
-# JSON-RPC options (for controlling a running Bitcoin/bitcoind process)
-#
-
-# server=1 tells Bitcoin-Qt and bitcoind to accept JSON-RPC commands
-#server=0
-
-# Bind to given address to listen for JSON-RPC connections.
-# Refer to the manpage or bitcoind -help for further details.
-#rpcbind=<addr>
-
-# If no rpcpassword is set, rpc cookie auth is sought. The default `-rpccookiefile` name
-# is .cookie and found in the `-datadir` being used for bitcoind. This option is typically used
-# when the server and client are run as the same user.
-#
-# If not, you must set rpcuser and rpcpassword to secure the JSON-RPC API.
-#
-# The config option `rpcauth` can be added to server startup argument. It is set at initialization time
-# using the output from the script in share/rpcauth/rpcauth.py after providing a username:
-#
-# ./share/rpcauth/rpcauth.py alice
-# String to be appended to bitcoin.conf:
-# rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae
-# Your password:
-# DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E=
-#
-# On client-side, you add the normal user/password pair to send commands:
-#rpcuser=alice
-#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E=
-#
-# You can even add multiple entries of these to the server conf file, and client can use any of them:
-# rpcauth=bob:b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99
-
-# How many seconds bitcoin will wait for a complete RPC HTTP request.
-# after the HTTP connection is established.
-#rpcclienttimeout=30
-
-# By default, only RPC connections from localhost are allowed.
-# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
-# either as a single IPv4/IPv6 or with a subnet specification.
-
-# NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED,
-# because the rpcpassword is transmitted over the network unencrypted.
-
-# server=1 tells Bitcoin-Qt to accept JSON-RPC commands.
-# it is also read by bitcoind to determine if RPC should be enabled
-#rpcallowip=10.1.1.34/255.255.255.0
-#rpcallowip=1.2.3.4/24
-#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
-
-# Listen for RPC connections on this TCP port:
-#rpcport=8332
-
-# You can use Bitcoin or bitcoind to send commands to Bitcoin/bitcoind
-# running on another host using this option:
-#rpcconnect=127.0.0.1
-
-# Wallet options
-
-# Specify where to find wallet, lockfile and logs. If not present, those files will be
-# created as new.
-#wallet=</path/to/dir>
-
-# Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6).
-# This setting is over-ridden by the -paytxfee option.
-#txconfirmtarget=n
-
-# Pay a transaction fee every time you send bitcoins.
-#paytxfee=0.000x
-
-# Miscellaneous options
-
-# Pre-generate this many public/private key pairs, so wallet backups will be valid for
-# both prior transactions and several dozen future transactions.
-#keypool=100
-
-# Maintain coinstats index used by the gettxoutsetinfo RPC (default: 0).
-#coinstatsindex=1
-
-# Enable pruning to reduce storage requirements by deleting old blocks.
-# This mode is incompatible with -txindex and -coinstatsindex.
-# 0 = default (no pruning).
-# 1 = allows manual pruning via RPC.
-# >=550 = target to stay under in MiB.
-#prune=550
-
-# User interface options
-
-# Start Bitcoin minimized
-#min=1
-
-# Minimize to the system tray
-#minimizetotray=1
-
-# [Sections]
-# Most options apply to mainnet, testnet, signet and regtest.
-# If you want to confine an option to just one network, you should add it in the
-# relevant section below.
-# EXCEPTIONS: The options addnode, connect, port, bind, rpcport, rpcbind and wallet
-# only apply to mainnet unless they appear in the appropriate section below.
-
-# Options only for mainnet
-[main]
-
-# Options only for testnet
-[test]
-
-# Options only for signet
-[signet]
-
-# Options only for regtest
-[regtest]
+# This is a placeholder file. Please follow the instructions in `contrib/devtools/README.md` to generate a bitcoin.conf file.
diff --git a/src/Makefile.am b/src/Makefile.am
index 85ea60c0ae..357e562c69 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -275,6 +275,7 @@ BITCOIN_CORE_H = \
util/spanparsing.h \
util/string.h \
util/syscall_sandbox.h \
+ util/syserror.h \
util/system.h \
util/thread.h \
util/threadnames.h \
@@ -657,6 +658,7 @@ libbitcoin_util_a_SOURCES = \
util/getuniquepath.cpp \
util/hasher.cpp \
util/sock.cpp \
+ util/syserror.cpp \
util/system.cpp \
util/message.cpp \
util/moneystr.cpp \
@@ -917,7 +919,9 @@ libbitcoinkernel_la_SOURCES = \
util/serfloat.cpp \
util/settings.cpp \
util/strencodings.cpp \
+ util/string.cpp \
util/syscall_sandbox.cpp \
+ util/syserror.cpp \
util/system.cpp \
util/thread.cpp \
util/threadnames.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index e90c8530d8..532f668668 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -44,6 +44,7 @@ bench_bench_bitcoin_SOURCES = \
bench/rollingbloom.cpp \
bench/rpc_blockchain.cpp \
bench/rpc_mempool.cpp \
+ bench/strencodings.cpp \
bench/util_time.cpp \
bench/verify_script.cpp
diff --git a/src/bench/strencodings.cpp b/src/bench/strencodings.cpp
new file mode 100644
index 0000000000..69b3a83cbf
--- /dev/null
+++ b/src/bench/strencodings.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <bench/data.h>
+#include <util/strencodings.h>
+
+static void HexStrBench(benchmark::Bench& bench)
+{
+ auto const& data = benchmark::data::block413567;
+ bench.batch(data.size()).unit("byte").run([&] {
+ auto hex = HexStr(data);
+ ankerl::nanobench::doNotOptimizeAway(hex);
+ });
+}
+
+BENCHMARK(HexStrBench);
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 9843382682..bc063faed1 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -20,6 +20,7 @@
#include <util/check.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
+#include <util/syserror.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <util/tokenpipe.h>
@@ -206,7 +207,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
}
break;
case -1: // Error happened.
- return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", strerror(errno))));
+ return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", SysErrorString(errno))));
default: { // Parent: wait and exit.
int token = daemon_ep.TokenRead();
if (token) { // Success
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 3bab5b5d98..77c516427a 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -14,9 +14,6 @@
#include <util/strencodings.h>
#include <version.h>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
-
#include <algorithm>
#include <string>
@@ -66,12 +63,11 @@ CScript ParseScript(const std::string& s)
{
CScript result;
- std::vector<std::string> words;
- boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on);
+ std::vector<std::string> words = SplitString(s, " \t\n");
for (const std::string& w : words) {
if (w.empty()) {
- // Empty string, ignore. (boost::split given '' will return one word)
+ // Empty string, ignore. (SplitString doesn't combine multiple separators)
} else if (std::all_of(w.begin(), w.end(), ::IsDigit) ||
(w.front() == '-' && w.size() > 1 && std::all_of(w.begin() + 1, w.end(), ::IsDigit)))
{
diff --git a/src/fs.cpp b/src/fs.cpp
index 219fdee959..b61115bf01 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <fs.h>
+#include <util/syserror.h>
#ifndef WIN32
#include <cstring>
@@ -44,7 +45,7 @@ fs::path AbsPathJoin(const fs::path& base, const fs::path& path)
static std::string GetErrorReason()
{
- return std::strerror(errno);
+ return SysErrorString(errno);
}
FileLock::FileLock(const fs::path& file)
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index af27ff3506..3bf165495c 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -21,8 +21,6 @@
#include <string>
#include <vector>
-#include <boost/algorithm/string.hpp>
-
/** WWW-Authenticate to present with 401 Unauthorized response */
static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
@@ -276,8 +274,10 @@ static bool InitRPCAuthentication()
std::set<std::string>& whitelist = g_rpc_whitelist[strUser];
if (pos != std::string::npos) {
std::string strWhitelist = strRPCWhitelist.substr(pos + 1);
- std::set<std::string> new_whitelist;
- boost::split(new_whitelist, strWhitelist, boost::is_any_of(", "));
+ std::vector<std::string> whitelist_split = SplitString(strWhitelist, ", ");
+ std::set<std::string> new_whitelist{
+ std::make_move_iterator(whitelist_split.begin()),
+ std::make_move_iterator(whitelist_split.end())};
if (intersect) {
std::set<std::string> tmp_whitelist;
std::set_intersection(new_whitelist.begin(), new_whitelist.end(),
diff --git a/src/init.cpp b/src/init.cpp
index fdcb2b8ac7..713598f411 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -65,6 +65,7 @@
#include <util/strencodings.h>
#include <util/string.h>
#include <util/syscall_sandbox.h>
+#include <util/syserror.h>
#include <util/system.h>
#include <util/thread.h>
#include <util/threadnames.h>
@@ -91,7 +92,6 @@
#include <sys/stat.h>
#endif
-#include <boost/algorithm/string/replace.hpp>
#include <boost/signals2/signal.hpp>
#if ENABLE_ZMQ
@@ -150,7 +150,7 @@ static fs::path GetPidFile(const ArgsManager& args)
#endif
return true;
} else {
- return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), std::strerror(errno)));
+ return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), SysErrorString(errno)));
}
}
@@ -408,7 +408,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Automatic broadcast and rebroadcast of any transactions from inbound peers is disabled, unless the peer has the 'forcerelay' permission. RPC transactions are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-coinstatsindex", strprintf("Maintain coinstats index used by the gettxoutsetinfo RPC (default: %u)", DEFAULT_COINSTATSINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-conf=<file>", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-conf=<file>", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location (only useable from command line, not configuration file) (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
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);
@@ -1640,7 +1640,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
uiInterface.NotifyBlockTip_connect([block_notify](SynchronizationState sync_state, const CBlockIndex* pBlockIndex) {
if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex) return;
std::string command = block_notify;
- boost::replace_all(command, "%s", pBlockIndex->GetBlockHash().GetHex());
+ ReplaceAll(command, "%s", pBlockIndex->GetBlockHash().GetHex());
std::thread t(runCommand, command);
t.detach(); // thread runs free
});
diff --git a/src/net.cpp b/src/net.cpp
index 90fe237418..46d7020c5e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -103,7 +103,7 @@ enum BindFlags {
// The sleep time needs to be small to avoid new sockets stalling
static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;
-const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
@@ -643,12 +643,12 @@ void CNode::CopyStats(CNodeStats& stats)
X(m_bip152_highbandwidth_from);
{
LOCK(cs_vSend);
- X(mapSendBytesPerMsgCmd);
+ X(mapSendBytesPerMsgType);
X(nSendBytes);
}
{
LOCK(cs_vRecv);
- X(mapRecvBytesPerMsgCmd);
+ X(mapRecvBytesPerMsgType);
X(nRecvBytes);
}
X(m_permissionFlags);
@@ -684,19 +684,19 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
bool reject_message{false};
CNetMessage msg = m_deserializer->GetMessage(time, reject_message);
if (reject_message) {
- // Message deserialization failed. Drop the message but don't disconnect the peer.
+ // Message deserialization failed. Drop the message but don't disconnect the peer.
// store the size of the corrupt message
- mapRecvBytesPerMsgCmd.at(NET_MESSAGE_COMMAND_OTHER) += msg.m_raw_message_size;
+ mapRecvBytesPerMsgType.at(NET_MESSAGE_TYPE_OTHER) += msg.m_raw_message_size;
continue;
}
- // Store received bytes per message command
- // to prevent a memory DOS, only allow valid commands
- auto i = mapRecvBytesPerMsgCmd.find(msg.m_type);
- if (i == mapRecvBytesPerMsgCmd.end()) {
- i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
+ // Store received bytes per message type.
+ // To prevent a memory DOS, only allow known message types.
+ auto i = mapRecvBytesPerMsgType.find(msg.m_type);
+ if (i == mapRecvBytesPerMsgType.end()) {
+ i = mapRecvBytesPerMsgType.find(NET_MESSAGE_TYPE_OTHER);
}
- assert(i != mapRecvBytesPerMsgCmd.end());
+ assert(i != mapRecvBytesPerMsgType.end());
i->second += msg.m_raw_message_size;
// push the message to the process queue,
@@ -781,7 +781,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
// decompose a single CNetMessage from the TransportDeserializer
CNetMessage msg(std::move(vRecv));
- // store command string, time, and sizes
+ // store message type string, time, and sizes
msg.m_type = hdr.GetCommand();
msg.m_time = time;
msg.m_message_size = hdr.nMessageSize;
@@ -792,7 +792,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
RandAddEvent(ReadLE32(hash.begin()));
- // Check checksum and header command string
+ // Check checksum and header message type string
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {
LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n",
SanitizeString(msg.m_type), msg.m_message_size,
@@ -3053,8 +3053,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> s
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
for (const std::string &msg : getAllNetMessageTypes())
- mapRecvBytesPerMsgCmd[msg] = 0;
- mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
+ mapRecvBytesPerMsgType[msg] = 0;
+ mapRecvBytesPerMsgType[NET_MESSAGE_TYPE_OTHER] = 0;
if (fLogIPs) {
LogPrint(BCLog::NET, "Added connection to %s peer=%d\n", m_addr_name, id);
@@ -3100,7 +3100,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
bool optimisticSend(pnode->vSendMsg.empty());
//log total amount of bytes per message type
- pnode->mapSendBytesPerMsgCmd[msg.m_type] += nTotalSize;
+ pnode->mapSendBytesPerMsgType[msg.m_type] += nTotalSize;
pnode->nSendSize += nTotalSize;
if (pnode->nSendSize > nSendBufferMaxSize) pnode->fPauseSend = true;
diff --git a/src/net.h b/src/net.h
index 3271930a35..5cdddf1fee 100644
--- a/src/net.h
+++ b/src/net.h
@@ -252,8 +252,8 @@ struct LocalServiceInfo {
extern Mutex g_maplocalhost_mutex;
extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
-extern const std::string NET_MESSAGE_COMMAND_OTHER;
-typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
+extern const std::string NET_MESSAGE_TYPE_OTHER;
+using mapMsgTypeSize = std::map</* message type */ std::string, /* total bytes */ uint64_t>;
class CNodeStats
{
@@ -274,9 +274,9 @@ public:
bool m_bip152_highbandwidth_from;
int m_starting_height;
uint64_t nSendBytes;
- mapMsgCmdSize mapSendBytesPerMsgCmd;
+ mapMsgTypeSize mapSendBytesPerMsgType;
uint64_t nRecvBytes;
- mapMsgCmdSize mapRecvBytesPerMsgCmd;
+ mapMsgTypeSize mapRecvBytesPerMsgType;
NetPermissionFlags m_permissionFlags;
std::chrono::microseconds m_last_ping_time;
std::chrono::microseconds m_min_ping_time;
@@ -315,7 +315,7 @@ public:
/** The TransportDeserializer takes care of holding and deserializing the
* network receive buffer. It can deserialize the network buffer into a
- * transport protocol agnostic CNetMessage (command & payload)
+ * transport protocol agnostic CNetMessage (message type & payload)
*/
class TransportDeserializer {
public:
@@ -686,8 +686,8 @@ private:
CService addrLocal GUARDED_BY(m_addr_local_mutex);
mutable Mutex m_addr_local_mutex;
- mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend);
- mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
+ mapMsgTypeSize mapSendBytesPerMsgType GUARDED_BY(cs_vSend);
+ mapMsgTypeSize mapRecvBytesPerMsgType GUARDED_BY(cs_vRecv);
};
/**
diff --git a/src/netgroup.cpp b/src/netgroup.cpp
index 5f42d6c719..96b5e29684 100644
--- a/src/netgroup.cpp
+++ b/src/netgroup.cpp
@@ -71,7 +71,7 @@ std::vector<unsigned char> NetGroupManager::GetGroup(const CNetAddr& address) co
// ...for the last byte, push nBits and for the rest of the byte push 1's
if (nBits > 0) {
assert(num_bytes < addr_bytes.size());
- vchRet.push_back(addr_bytes[num_bytes] | ((1 << (8 - nBits)) - 1));
+ vchRet.push_back(addr_bytes[num_bytes + nStartByte] | ((1 << (8 - nBits)) - 1));
}
return vchRet;
diff --git a/src/node/miner.h b/src/node/miner.h
index c8093ec883..678df815c0 100644
--- a/src/node/miner.h
+++ b/src/node/miner.h
@@ -116,7 +116,7 @@ struct update_for_parent_inclusion
void operator() (CTxMemPoolModifiedEntry &e)
{
- e.nModFeesWithAncestors -= iter->GetFee();
+ e.nModFeesWithAncestors -= iter->GetModifiedFee();
e.nSizeWithAncestors -= iter->GetTxSize();
e.nSigOpCostWithAncestors -= iter->GetSigOpCost();
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index a9f9cb0153..09dc8eb3eb 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -156,7 +156,7 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n"
"When a message type is not listed in this json object, the bytes received are 0.\n"
"Only known message types can appear as keys in the object and all bytes received\n"
- "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
+ "of unknown message types are listed under '"+NET_MESSAGE_TYPE_OTHER+"'."}
}},
{RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
"Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
@@ -243,19 +243,19 @@ static RPCHelpMan getpeerinfo()
}
obj.pushKV("permissions", permissions);
- UniValue sendPerMsgCmd(UniValue::VOBJ);
- for (const auto& i : stats.mapSendBytesPerMsgCmd) {
+ UniValue sendPerMsgType(UniValue::VOBJ);
+ for (const auto& i : stats.mapSendBytesPerMsgType) {
if (i.second > 0)
- sendPerMsgCmd.pushKV(i.first, i.second);
+ sendPerMsgType.pushKV(i.first, i.second);
}
- obj.pushKV("bytessent_per_msg", sendPerMsgCmd);
+ obj.pushKV("bytessent_per_msg", sendPerMsgType);
- UniValue recvPerMsgCmd(UniValue::VOBJ);
- for (const auto& i : stats.mapRecvBytesPerMsgCmd) {
+ UniValue recvPerMsgType(UniValue::VOBJ);
+ for (const auto& i : stats.mapRecvBytesPerMsgType) {
if (i.second > 0)
- recvPerMsgCmd.pushKV(i.first, i.second);
+ recvPerMsgType.pushKV(i.first, i.second);
}
- obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
+ obj.pushKV("bytesrecv_per_msg", recvPerMsgType);
obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type));
ret.push_back(obj);
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index e6064d19b6..94399faf04 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -224,7 +224,12 @@ FUZZ_TARGET(string)
int64_t amount_out;
(void)ParseFixedPoint(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1024), &amount_out);
}
- (void)SplitString(random_string_1, fuzzed_data_provider.ConsumeIntegral<char>());
+ {
+ const auto single_split{SplitString(random_string_1, fuzzed_data_provider.ConsumeIntegral<char>())};
+ assert(single_split.size() >= 1);
+ const auto any_split{SplitString(random_string_1, random_string_2)};
+ assert(any_split.size() >= 1);
+ }
{
(void)Untranslated(random_string_1);
const bilingual_str bs1{random_string_1, random_string_2};
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index f6c1d1efad..7e26e732f5 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -30,6 +30,8 @@ using node::CBlockTemplate;
namespace miner_tests {
struct MinerTestingSetup : public TestingSetup {
void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
+ void TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
+ void TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
bool TestSequenceLocks(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs)
{
CCoinsViewMemPool view_mempool(&m_node.chainman->ActiveChainstate().CoinsTip(), *m_node.mempool);
@@ -191,60 +193,17 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
}
-// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
-BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
+void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight)
{
- // Note that by default, these tests run with size accounting enabled.
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
- const CChainParams& chainparams = *chainParams;
- CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- std::unique_ptr<CBlockTemplate> pblocktemplate;
- CMutableTransaction tx;
- CScript script;
uint256 hash;
+ CMutableTransaction tx;
TestMemPoolEntryHelper entry;
entry.nFee = 11;
entry.nHeight = 11;
- fCheckpointsEnabled = false;
-
- // Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
-
- // We can't make transactions until we have inputs
- // Therefore, load 110 blocks :)
- static_assert(std::size(BLOCKINFO) == 110, "Should have 110 blocks to import");
- int baseheight = 0;
- std::vector<CTransactionRef> txFirst;
- for (const auto& bi : BLOCKINFO) {
- CBlock *pblock = &pblocktemplate->block; // pointer for convenience
- {
- LOCK(cs_main);
- pblock->nVersion = VERSIONBITS_TOP_BITS;
- pblock->nTime = m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1;
- CMutableTransaction txCoinbase(*pblock->vtx[0]);
- txCoinbase.nVersion = 1;
- txCoinbase.vin[0].scriptSig = CScript{} << (m_node.chainman->ActiveChain().Height() + 1) << bi.extranonce;
- txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
- txCoinbase.vout[0].scriptPubKey = CScript();
- pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
- if (txFirst.size() == 0)
- baseheight = m_node.chainman->ActiveChain().Height();
- if (txFirst.size() < 4)
- txFirst.push_back(pblock->vtx[0]);
- pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
- pblock->nNonce = bi.nonce;
- }
- std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr));
- pblock->hashPrevBlock = pblock->GetHash();
- }
-
- LOCK(cs_main);
- LOCK(m_node.mempool->cs);
-
// Just to make sure we can still make simple blocks
- BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate);
const CAmount BLOCKSUBSIDY = 50*COIN;
const CAmount LOWFEE = CENT;
@@ -386,7 +345,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
- script = CScript() << OP_0;
+ CScript script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
@@ -508,6 +467,130 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
+}
+
+void MinerTestingSetup::TestPrioritisedMining(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
+{
+ TestMemPoolEntryHelper entry;
+
+ // Test that a tx below min fee but prioritised is included
+ CMutableTransaction tx;
+ tx.vin.resize(1);
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 5000000000LL; // 0 fee
+ uint256 hashFreePrioritisedTx = tx.GetHash();
+ m_node.mempool->addUnchecked(entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);
+
+ tx.vin[0].prevout.hash = txFirst[1]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vout[0].nValue = 5000000000LL - 1000;
+ // This tx has a low fee: 1000 satoshis
+ uint256 hashParentTx = tx.GetHash(); // save this txid for later use
+ m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+
+ // This tx has a medium fee: 10000 satoshis
+ tx.vin[0].prevout.hash = txFirst[2]->GetHash();
+ tx.vout[0].nValue = 5000000000LL - 10000;
+ uint256 hashMediumFeeTx = tx.GetHash();
+ m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
+
+ // This tx also has a low fee, but is prioritised
+ tx.vin[0].prevout.hash = hashParentTx;
+ tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee
+ uint256 hashPrioritsedChild = tx.GetHash();
+ m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
+
+ // Test that transaction selection properly updates ancestor fee calculations as prioritised
+ // parents get included in a block. Create a transaction with two prioritised ancestors, each
+ // included by itself: FreeParent <- FreeChild <- FreeGrandchild.
+ // When FreeParent is added, a modified entry will be created for FreeChild + FreeGrandchild
+ // FreeParent's prioritisation should not be included in that entry.
+ // When FreeChild is included, FreeChild's prioritisation should also not be included.
+ tx.vin[0].prevout.hash = txFirst[3]->GetHash();
+ tx.vout[0].nValue = 5000000000LL; // 0 fee
+ uint256 hashFreeParent = tx.GetHash();
+ m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashFreeParent, 10 * COIN);
+
+ tx.vin[0].prevout.hash = hashFreeParent;
+ tx.vout[0].nValue = 5000000000LL; // 0 fee
+ uint256 hashFreeChild = tx.GetHash();
+ m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashFreeChild, 1 * COIN);
+
+ tx.vin[0].prevout.hash = hashFreeChild;
+ tx.vout[0].nValue = 5000000000LL; // 0 fee
+ uint256 hashFreeGrandchild = tx.GetHash();
+ m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
+
+ auto pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
+ BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashFreeParent);
+ BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashFreePrioritisedTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashParentTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashPrioritsedChild);
+ BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashFreeChild);
+ for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
+ // The FreeParent and FreeChild's prioritisations should not impact the child.
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeGrandchild);
+ // De-prioritised transaction should not be included.
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashMediumFeeTx);
+ }
+}
+
+// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
+BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
+{
+ // Note that by default, these tests run with size accounting enabled.
+ const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const CChainParams& chainparams = *chainParams;
+ CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
+
+ fCheckpointsEnabled = false;
+
+ // Simple block creation, nothing special yet:
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+
+ // We can't make transactions until we have inputs
+ // Therefore, load 110 blocks :)
+ static_assert(std::size(BLOCKINFO) == 110, "Should have 110 blocks to import");
+ int baseheight = 0;
+ std::vector<CTransactionRef> txFirst;
+ for (const auto& bi : BLOCKINFO) {
+ CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ {
+ LOCK(cs_main);
+ pblock->nVersion = VERSIONBITS_TOP_BITS;
+ pblock->nTime = m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1;
+ CMutableTransaction txCoinbase(*pblock->vtx[0]);
+ txCoinbase.nVersion = 1;
+ txCoinbase.vin[0].scriptSig = CScript{} << (m_node.chainman->ActiveChain().Height() + 1) << bi.extranonce;
+ txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
+ txCoinbase.vout[0].scriptPubKey = CScript();
+ pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
+ if (txFirst.size() == 0)
+ baseheight = m_node.chainman->ActiveChain().Height();
+ if (txFirst.size() < 4)
+ txFirst.push_back(pblock->vtx[0]);
+ pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
+ pblock->nNonce = bi.nonce;
+ }
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
+ BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr));
+ pblock->hashPrevBlock = pblock->GetHash();
+ }
+
+ LOCK(cs_main);
+ LOCK(m_node.mempool->cs);
+
+ TestBasicMining(chainparams, scriptPubKey, txFirst, baseheight);
m_node.chainman->ActiveChain().Tip()->nHeight--;
SetMockTime(0);
@@ -515,6 +598,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
TestPackageSelection(chainparams, scriptPubKey, txFirst);
+ m_node.chainman->ActiveChain().Tip()->nHeight--;
+ SetMockTime(0);
+ m_node.mempool->clear();
+
+ TestPrioritisedMining(chainparams, scriptPubKey, txFirst);
+
fCheckpointsEnabled = true;
}
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b880a7a9fd..3b2aca5887 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -198,6 +198,24 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
BOOST_CHECK_EQUAL(HexStr(in_s), out_exp);
BOOST_CHECK_EQUAL(HexStr(in_b), out_exp);
}
+
+ {
+ auto input = std::string();
+ for (size_t i=0; i<256; ++i) {
+ input.push_back(static_cast<char>(i));
+ }
+
+ auto hex = HexStr(input);
+ BOOST_TEST_REQUIRE(hex.size() == 512);
+ static constexpr auto hexmap = std::string_view("0123456789abcdef");
+ for (size_t i = 0; i < 256; ++i) {
+ auto upper = hexmap.find(hex[i * 2]);
+ auto lower = hexmap.find(hex[i * 2 + 1]);
+ BOOST_TEST_REQUIRE(upper != std::string_view::npos);
+ BOOST_TEST_REQUIRE(lower != std::string_view::npos);
+ BOOST_TEST_REQUIRE(i == upper*16 + lower);
+ }
+ }
}
BOOST_AUTO_TEST_CASE(span_write_bytes)
@@ -2396,6 +2414,19 @@ BOOST_AUTO_TEST_CASE(test_SplitString)
BOOST_CHECK_EQUAL(result.size(), 1);
BOOST_CHECK_EQUAL(result[0], "AAA");
}
+
+ // multiple split characters
+ {
+ using V = std::vector<std::string>;
+ BOOST_TEST(SplitString("a,b.c:d;e", ",;") == V({"a", "b.c:d", "e"}));
+ BOOST_TEST(SplitString("a,b.c:d;e", ",;:.") == V({"a", "b", "c", "d", "e"}));
+ BOOST_TEST(SplitString("a,b.c:d;e", "") == V({"a,b.c:d;e"}));
+ BOOST_TEST(SplitString("aaa", "bcdefg") == V({"aaa"}));
+ BOOST_TEST(SplitString("x\0a,b"s, "\0"s) == V({"x", "a,b"}));
+ BOOST_TEST(SplitString("x\0a,b"s, '\0') == V({"x", "a,b"}));
+ BOOST_TEST(SplitString("x\0a,b"s, "\0,"s) == V({"x", "a", "b"}));
+ BOOST_TEST(SplitString("abcdefg", "bcd") == V({"a", "", "", "efg"}));
+ }
}
BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index e2a7cb4066..05dbc6057f 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -24,8 +24,6 @@
#include <set>
#include <vector>
-#include <boost/algorithm/string/replace.hpp>
-
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
@@ -566,7 +564,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
if (!torpassword.empty()) {
if (methods.count("HASHEDPASSWORD")) {
LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n");
- boost::replace_all(torpassword, "\"", "\\\"");
+ ReplaceAll(torpassword, "\"", "\\\"");
_conn.Command("AUTHENTICATE \"" + torpassword + "\"", std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n");
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index b5c1e28294..3579af4458 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -7,6 +7,7 @@
#include <threadinterrupt.h>
#include <tinyformat.h>
#include <util/sock.h>
+#include <util/syserror.h>
#include <util/system.h>
#include <util/time.h>
@@ -344,19 +345,8 @@ std::string NetworkErrorString(int err)
#else
std::string NetworkErrorString(int err)
{
- char buf[256];
- buf[0] = 0;
- /* Too bad there are two incompatible implementations of the
- * thread-safe strerror. */
- const char *s;
-#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
- s = strerror_r(err, buf, sizeof(buf));
-#else /* POSIX variant always returns message in buffer */
- s = buf;
- if (strerror_r(err, buf, sizeof(buf)))
- buf[0] = 0;
-#endif
- return strprintf("%s (%d)", s, err);
+ // On BSD sockets implementations, NetworkErrorString is the same as SysErrorString.
+ return SysErrorString(err);
}
#endif
diff --git a/src/util/spanparsing.h b/src/util/spanparsing.h
index ebec8714a7..51795271de 100644
--- a/src/util/spanparsing.h
+++ b/src/util/spanparsing.h
@@ -8,6 +8,7 @@
#include <span.h>
#include <string>
+#include <string_view>
#include <vector>
namespace spanparsing {
@@ -36,7 +37,7 @@ bool Func(const std::string& str, Span<const char>& sp);
*/
Span<const char> Expr(Span<const char>& sp);
-/** Split a string on every instance of sep, returning a vector.
+/** Split a string on any char found in separators, returning a vector.
*
* If sep does not occur in sp, a singleton with the entirety of sp is returned.
*
@@ -44,13 +45,13 @@ Span<const char> Expr(Span<const char>& sp);
* "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
*/
template <typename T = Span<const char>>
-std::vector<T> Split(const Span<const char>& sp, char sep)
+std::vector<T> Split(const Span<const char>& sp, std::string_view separators)
{
std::vector<T> ret;
auto it = sp.begin();
auto start = it;
while (it != sp.end()) {
- if (*it == sep) {
+ if (separators.find(*it) != std::string::npos) {
ret.emplace_back(start, it);
start = it + 1;
}
@@ -60,6 +61,19 @@ std::vector<T> Split(const Span<const char>& sp, char sep)
return ret;
}
+/** Split a string on every instance of sep, returning a vector.
+ *
+ * If sep does not occur in sp, a singleton with the entirety of sp is returned.
+ *
+ * Note that this function does not care about braces, so splitting
+ * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
+ */
+template <typename T = Span<const char>>
+std::vector<T> Split(const Span<const char>& sp, char sep)
+{
+ return Split<T>(sp, std::string_view{&sep, 1});
+}
+
} // namespace spanparsing
#endif // BITCOIN_UTIL_SPANPARSING_H
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 35f62f0422..bcedd4f517 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -9,6 +9,7 @@
#include <tinyformat.h>
#include <algorithm>
+#include <array>
#include <cstdlib>
#include <cstring>
#include <limits>
@@ -452,17 +453,37 @@ std::string Capitalize(std::string str)
return str;
}
+namespace {
+
+using ByteAsHex = std::array<char, 2>;
+
+constexpr std::array<ByteAsHex, 256> CreateByteToHexMap()
+{
+ constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ std::array<ByteAsHex, 256> byte_to_hex{};
+ for (size_t i = 0; i < byte_to_hex.size(); ++i) {
+ byte_to_hex[i][0] = hexmap[i >> 4];
+ byte_to_hex[i][1] = hexmap[i & 15];
+ }
+ return byte_to_hex;
+}
+
+} // namespace
+
std::string HexStr(const Span<const uint8_t> s)
{
std::string rv(s.size() * 2, '\0');
- static constexpr char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- auto it = rv.begin();
+ static constexpr auto byte_to_hex = CreateByteToHexMap();
+ static_assert(sizeof(byte_to_hex) == 512);
+
+ char* it = rv.data();
for (uint8_t v : s) {
- *it++ = hexmap[v >> 4];
- *it++ = hexmap[v & 15];
+ std::memcpy(it, byte_to_hex[v].data(), 2);
+ it += 2;
}
- assert(it == rv.end());
+
+ assert(it == rv.data() + rv.size());
return rv;
}
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 8ea3a1afc6..d05222e8b8 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -3,3 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <util/string.h>
+
+#include <boost/algorithm/string/replace.hpp>
+
+void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute)
+{
+ boost::replace_all(in_out, search, substitute);
+}
diff --git a/src/util/string.h b/src/util/string.h
index 36b9787db4..df20e34ae9 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -5,22 +5,30 @@
#ifndef BITCOIN_UTIL_STRING_H
#define BITCOIN_UTIL_STRING_H
-#include <attributes.h>
#include <util/spanparsing.h>
#include <algorithm>
#include <array>
+#include <cstdint>
#include <cstring>
#include <locale>
#include <sstream>
#include <string>
+#include <string_view>
#include <vector>
+void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute);
+
[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
{
return spanparsing::Split<std::string>(str, sep);
}
+[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators)
+{
+ return spanparsing::Split<std::string>(str, separators);
+}
+
[[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
{
std::string::size_type front = str.find_first_not_of(pattern);
diff --git a/src/util/syserror.cpp b/src/util/syserror.cpp
new file mode 100644
index 0000000000..391ddd3560
--- /dev/null
+++ b/src/util/syserror.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) 2020-2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <tinyformat.h>
+#include <util/syserror.h>
+
+#include <cstring>
+
+std::string SysErrorString(int err)
+{
+ char buf[1024];
+ /* Too bad there are three incompatible implementations of the
+ * thread-safe strerror. */
+ const char *s = nullptr;
+#ifdef WIN32
+ if (strerror_s(buf, sizeof(buf), err) == 0) s = buf;
+#else
+#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
+ s = strerror_r(err, buf, sizeof(buf));
+#else /* POSIX variant always returns message in buffer */
+ if (strerror_r(err, buf, sizeof(buf)) == 0) s = buf;
+#endif
+#endif
+ if (s != nullptr) {
+ return strprintf("%s (%d)", s, err);
+ } else {
+ return strprintf("Unknown error (%d)", err);
+ }
+}
diff --git a/src/util/syserror.h b/src/util/syserror.h
new file mode 100644
index 0000000000..a54ba553ee
--- /dev/null
+++ b/src/util/syserror.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2010-2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_SYSERROR_H
+#define BITCOIN_UTIL_SYSERROR_H
+
+#include <string>
+
+/** Return system error string from errno value. Use this instead of
+ * std::strerror, which is not thread-safe. For network errors use
+ * NetworkErrorString from sock.h instead.
+ */
+std::string SysErrorString(int err);
+
+#endif // BITCOIN_UTIL_SYSERROR_H
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 0dee8f2a6d..44ebf5cb3e 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -25,6 +25,7 @@
#include <util/getuniquepath.h>
#include <util/strencodings.h>
#include <util/string.h>
+#include <util/syserror.h>
#include <util/translation.h>
@@ -75,7 +76,6 @@
#include <malloc.h>
#endif
-#include <boost/algorithm/string/replace.hpp>
#include <univalue.h>
#include <fstream>
@@ -1252,7 +1252,7 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
std::string ShellEscape(const std::string& arg)
{
std::string escaped = arg;
- boost::replace_all(escaped, "'", "'\"'\"'");
+ ReplaceAll(escaped, "'", "'\"'\"'");
return "'" + escaped + "'";
}
#endif
@@ -1374,7 +1374,7 @@ void ScheduleBatchPriority()
const static sched_param param{};
const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param);
if (rc != 0) {
- LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(rc));
+ LogPrintf("Failed to pthread_setschedparam: %s\n", SysErrorString(rc));
}
#endif
}
diff --git a/src/validation.cpp b/src/validation.cpp
index 5a2bee2418..4614fc1402 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -55,12 +55,11 @@
#include <warnings.h>
#include <algorithm>
+#include <deque>
#include <numeric>
#include <optional>
#include <string>
-#include <boost/algorithm/string/replace.hpp>
-
using node::BLOCKFILE_CHUNK_SIZE;
using node::BlockManager;
using node::BlockMap;
@@ -1577,7 +1576,7 @@ static void AlertNotify(const std::string& strMessage)
std::string singleQuote("'");
std::string safeStatus = SanitizeString(strMessage);
safeStatus = singleQuote+safeStatus+singleQuote;
- boost::replace_all(strCmd, "%s", safeStatus);
+ ReplaceAll(strCmd, "%s", safeStatus);
std::thread t(runCommand, strCmd);
t.detach(); // thread runs free
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 79faf29907..356d0ce5a0 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -44,8 +44,6 @@
#include <assert.h>
#include <optional>
-#include <boost/algorithm/string/replace.hpp>
-
using interfaces::FoundBlock;
namespace wallet {
@@ -1018,14 +1016,14 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
if (!strCmd.empty())
{
- boost::replace_all(strCmd, "%s", hash.GetHex());
+ ReplaceAll(strCmd, "%s", hash.GetHex());
if (auto* conf = wtx.state<TxStateConfirmed>())
{
- boost::replace_all(strCmd, "%b", conf->confirmed_block_hash.GetHex());
- boost::replace_all(strCmd, "%h", ToString(conf->confirmed_block_height));
+ ReplaceAll(strCmd, "%b", conf->confirmed_block_hash.GetHex());
+ ReplaceAll(strCmd, "%h", ToString(conf->confirmed_block_height));
} else {
- boost::replace_all(strCmd, "%b", "unconfirmed");
- boost::replace_all(strCmd, "%h", "-1");
+ ReplaceAll(strCmd, "%b", "unconfirmed");
+ ReplaceAll(strCmd, "%h", "-1");
}
#ifndef WIN32
// Substituting the wallet name isn't currently supported on windows
@@ -1033,7 +1031,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
// https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-537384875
// A few ways it could be implemented in the future are described in:
// https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-461288094
- boost::replace_all(strCmd, "%w", ShellEscape(GetName()));
+ ReplaceAll(strCmd, "%w", ShellEscape(GetName()));
#endif
std::thread t(runCommand, strCmd);
t.detach(); // thread runs free
diff --git a/test/README.md b/test/README.md
index d69e515acf..b2fdde96e4 100644
--- a/test/README.md
+++ b/test/README.md
@@ -309,7 +309,7 @@ Use the `-v` option for verbose output.
| [`lint-python.py`](lint/lint-python.py) | [mypy](https://github.com/python/mypy)
| [`lint-python.py`](lint/lint-python.py) | [pyzmq](https://github.com/zeromq/pyzmq)
| [`lint-python-dead-code.py`](lint/lint-python-dead-code.py) | [vulture](https://github.com/jendrikseipp/vulture)
-| [`lint-shell.sh`](lint/lint-shell.sh) | [ShellCheck](https://github.com/koalaman/shellcheck)
+| [`lint-shell.py`](lint/lint-shell.py) | [ShellCheck](https://github.com/koalaman/shellcheck)
| [`lint-spelling.py`](lint/lint-spelling.py) | [codespell](https://github.com/codespell-project/codespell)
In use versions and install instructions are available in the [CI setup](../ci/lint/04_install.sh).
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index eea5fa24ee..fe3196d5ee 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -247,7 +247,8 @@ class ConfArgsTest(BitcoinTestFramework):
conf_file = os.path.join(default_data_dir, "bitcoin.conf")
# datadir needs to be set before [chain] section
- conf_file_contents = open(conf_file, encoding='utf8').read()
+ with open(conf_file, encoding='utf8') as f:
+ conf_file_contents = f.read()
with open(conf_file, 'w', encoding='utf8') as f:
f.write(f"datadir={new_data_dir}\n")
f.write(conf_file_contents)
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index e83dd7f446..1572463308 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -58,7 +58,8 @@ class VersionBitsWarningTest(BitcoinTestFramework):
def versionbits_in_alert_file(self):
"""Test that the versionbits warning has been written to the alert file."""
- alert_text = open(self.alert_filename, 'r', encoding='utf8').read()
+ with open(self.alert_filename, 'r', encoding='utf8') as f:
+ alert_text = f.read()
return VB_PATTERN.search(alert_text) is not None
def run_test(self):
diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py
index b29c7f8b4d..ae62994642 100755
--- a/test/lint/lint-includes.py
+++ b/test/lint/lint-includes.py
@@ -21,10 +21,7 @@ EXCLUDED_DIRS = ["src/leveldb/",
"src/minisketch/",
"src/univalue/"]
-EXPECTED_BOOST_INCLUDES = ["boost/algorithm/string.hpp",
- "boost/algorithm/string/classification.hpp",
- "boost/algorithm/string/replace.hpp",
- "boost/algorithm/string/split.hpp",
+EXPECTED_BOOST_INCLUDES = ["boost/algorithm/string/replace.hpp",
"boost/date_time/posix_time/posix_time.hpp",
"boost/multi_index/hashed_index.hpp",
"boost/multi_index/ordered_index.hpp",
diff --git a/test/lint/lint-locale-dependence.py b/test/lint/lint-locale-dependence.py
index 2abf1be6b3..9b2cf4587a 100755
--- a/test/lint/lint-locale-dependence.py
+++ b/test/lint/lint-locale-dependence.py
@@ -49,7 +49,9 @@ KNOWN_VIOLATIONS = [
"src/test/fuzz/locale.cpp:.*setlocale",
"src/test/fuzz/string.cpp:.*strtol",
"src/test/fuzz/string.cpp:.*strtoul",
- "src/test/util_tests.cpp:.*strtoll"
+ "src/test/util_tests.cpp:.*strtoll",
+ "src/wallet/bdb.cpp:.*DbEnv::strerror", # False positive
+ "src/util/syserror.cpp:.*strerror", # Outside this function use `SysErrorString`
]
REGEXP_EXTERNAL_DEPENDENCIES_EXCLUSIONS = [
@@ -144,7 +146,7 @@ LOCALE_DEPENDENT_FUNCTIONS = [
"strcasecmp",
"strcasestr",
"strcoll", # LC_COLLATE
- #"strerror",
+ "strerror",
"strfmon",
"strftime", # LC_TIME
"strncasecmp",
@@ -218,7 +220,7 @@ LOCALE_DEPENDENT_FUNCTIONS = [
def find_locale_dependent_function_uses():
regexp_locale_dependent_functions = "|".join(LOCALE_DEPENDENT_FUNCTIONS)
exclude_args = [":(exclude)" + excl for excl in REGEXP_EXTERNAL_DEPENDENCIES_EXCLUSIONS]
- git_grep_command = ["git", "grep", "-E", "[^a-zA-Z0-9_\\`'\"<>](" + regexp_locale_dependent_functions + "(_r|_s)?)[^a-zA-Z0-9_\\`'\"<>]", "--", "*.cpp", "*.h"] + exclude_args
+ git_grep_command = ["git", "grep", "-E", "[^a-zA-Z0-9_\\`'\"<>](" + regexp_locale_dependent_functions + ")(_r|_s)?[^a-zA-Z0-9_\\`'\"<>]", "--", "*.cpp", "*.h"] + exclude_args
git_grep_output = list()
try:
diff --git a/test/lint/lint-shell.py b/test/lint/lint-shell.py
new file mode 100755
index 0000000000..f1e4494350
--- /dev/null
+++ b/test/lint/lint-shell.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2018-2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+"""
+Check for shellcheck warnings in shell scripts.
+"""
+
+import subprocess
+import re
+import sys
+
+# Disabled warnings:
+DISABLED = [
+ 'SC2162', # read without -r will mangle backslashes.
+]
+
+def check_shellcheck_install():
+ try:
+ subprocess.run(['shellcheck', '--version'], stdout=subprocess.DEVNULL, check=True)
+ except FileNotFoundError:
+ print('Skipping shell linting since shellcheck is not installed.')
+ sys.exit(0)
+
+def get_files(command):
+ output = subprocess.run(command, stdout=subprocess.PIPE, universal_newlines=True)
+ files = output.stdout.split('\n')
+
+ # remove whitespace element
+ files = list(filter(None, files))
+ return files
+
+def main():
+ check_shellcheck_install()
+
+ # build the `exclude` flag
+ exclude = '--exclude=' + ','.join(DISABLED)
+
+ # build the `sourced files` list
+ sourced_files_cmd = [
+ 'git',
+ 'grep',
+ '-El',
+ r'^# shellcheck shell=',
+ ]
+ sourced_files = get_files(sourced_files_cmd)
+
+ # build the `guix files` list
+ guix_files_cmd = [
+ 'git',
+ 'grep',
+ '-El',
+ r'^#!\/usr\/bin\/env bash',
+ '--',
+ 'contrib/guix',
+ 'contrib/shell',
+ ]
+ guix_files = get_files(guix_files_cmd)
+
+ # build the other script files list
+ files_cmd = [
+ 'git',
+ 'ls-files',
+ '--',
+ '*.sh',
+ ]
+ files = get_files(files_cmd)
+ # remove everything that doesn't match this regex
+ reg = re.compile(r'src/[leveldb,secp256k1,minisketch,univalue]')
+ files[:] = [file for file in files if not reg.match(file)]
+
+ # build the `shellcheck` command
+ shellcheck_cmd = [
+ 'shellcheck',
+ '--external-sources',
+ '--check-sourced',
+ '--source-path=SCRIPTDIR',
+ ]
+ shellcheck_cmd.append(exclude)
+ shellcheck_cmd.extend(sourced_files)
+ shellcheck_cmd.extend(guix_files)
+ shellcheck_cmd.extend(files)
+
+ # run the `shellcheck` command
+ try:
+ subprocess.check_call(shellcheck_cmd)
+ except subprocess.CalledProcessError:
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
deleted file mode 100755
index 5fa104fce6..0000000000
--- a/test/lint/lint-shell.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-2021 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check for shellcheck warnings in shell scripts.
-
-export LC_ALL=C
-
-# Disabled warnings:
-disabled=(
- SC2162 # read without -r will mangle backslashes.
-)
-
-EXIT_CODE=0
-
-if ! command -v shellcheck > /dev/null; then
- echo "Skipping shell linting since shellcheck is not installed."
- exit $EXIT_CODE
-fi
-
-SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced --source-path=SCRIPTDIR)
-EXCLUDE="--exclude=$(IFS=','; echo "${disabled[*]}")"
-# Check shellcheck directive used for sourced files
-mapfile -t SOURCED_FILES < <(git ls-files | xargs gawk '/^# shellcheck shell=/ {print FILENAME} {nextfile}')
-mapfile -t GUIX_FILES < <(git ls-files contrib/guix contrib/shell | xargs gawk '/^#!\/usr\/bin\/env bash/ {print FILENAME} {nextfile}')
-mapfile -t FILES < <(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|minisketch|univalue)/')
-if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" "${SOURCED_FILES[@]}" "${GUIX_FILES[@]}" "${FILES[@]}"; then
- EXIT_CODE=1
-fi
-
-exit $EXIT_CODE
diff --git a/test/util/test_runner.py b/test/util/test_runner.py
index a7fc3b1dc1..03db05c563 100755
--- a/test/util/test_runner.py
+++ b/test/util/test_runner.py
@@ -22,7 +22,8 @@ import sys
def main():
config = configparser.ConfigParser()
config.optionxform = str
- config.read_file(open(os.path.join(os.path.dirname(__file__), "../config.ini"), encoding="utf8"))
+ with open(os.path.join(os.path.dirname(__file__), "../config.ini"), encoding="utf8") as f:
+ config.read_file(f)
env_conf = dict(config.items('environment'))
parser = argparse.ArgumentParser(description=__doc__)
@@ -43,7 +44,8 @@ def main():
def bctester(testDir, input_basename, buildenv):
""" Loads and parses the input file, runs all tests and reports results"""
input_filename = os.path.join(testDir, input_basename)
- raw_data = open(input_filename, encoding="utf8").read()
+ with open(input_filename, encoding="utf8") as f:
+ raw_data = f.read()
input_data = json.loads(raw_data)
failed_testcases = []
@@ -80,7 +82,8 @@ def bctest(testDir, testObj, buildenv):
inputData = None
if "input" in testObj:
filename = os.path.join(testDir, testObj["input"])
- inputData = open(filename, encoding="utf8").read()
+ with open(filename, encoding="utf8") as f:
+ inputData = f.read()
stdinCfg = subprocess.PIPE
# Read the expected output data (if there is any)
@@ -91,7 +94,8 @@ def bctest(testDir, testObj, buildenv):
outputFn = testObj['output_cmp']
outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
try:
- outputData = open(os.path.join(testDir, outputFn), encoding="utf8").read()
+ with open(os.path.join(testDir, outputFn), encoding="utf8") as f:
+ outputData = f.read()
except:
logging.error("Output file " + outputFn + " cannot be opened")
raise