aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj1
-rw-r--r--contrib/gitian-keys/keys.txt68
-rw-r--r--contrib/guix/README.md3
-rwxr-xr-xcontrib/guix/guix-build.sh24
-rw-r--r--contrib/guix/libexec/build.sh140
-rw-r--r--contrib/guix/manifest.scm50
-rw-r--r--contrib/guix/patches/nsis-SConstruct-sde-support.patch15
-rwxr-xr-xcontrib/install_db4.sh153
-rw-r--r--depends/README.md2
-rw-r--r--doc/release-process.md12
-rw-r--r--doc/tor.md154
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/bench/checkqueue.cpp10
-rw-r--r--src/bench/rpc_blockchain.cpp3
-rw-r--r--src/checkqueue.h92
-rw-r--r--src/fs.cpp6
-rw-r--r--src/fs.h11
-rw-r--r--src/init.cpp7
-rw-r--r--src/key_io.cpp46
-rw-r--r--src/key_io.h1
-rw-r--r--src/net.cpp71
-rw-r--r--src/net.h3
-rw-r--r--src/qt/bitcoingui.cpp3
-rw-r--r--src/qt/clientmodel.cpp1
-rw-r--r--src/qt/forms/createwalletdialog.ui253
-rw-r--r--src/qt/forms/overviewpage.ui15
-rw-r--r--src/qt/overviewpage.cpp40
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/transactionoverviewwidget.h41
-rw-r--r--src/qt/transactiontablemodel.cpp1
-rw-r--r--src/qt/walletframe.cpp17
-rw-r--r--src/qt/walletmodel.cpp8
-rw-r--r--src/rpc/blockchain.cpp4
-rw-r--r--src/rpc/misc.cpp15
-rw-r--r--src/scheduler.cpp1
-rw-r--r--src/sync.cpp3
-rw-r--r--src/test/checkqueue_tests.cpp55
-rw-r--r--src/test/fs_tests.cpp17
-rw-r--r--src/test/fuzz/banman.cpp2
-rw-r--r--src/test/fuzz/coins_view.cpp4
-rw-r--r--src/test/fuzz/connman.cpp2
-rw-r--r--src/test/fuzz/crypto_chacha20_poly1305_aead.cpp10
-rw-r--r--src/test/fuzz/data_stream.cpp2
-rw-r--r--src/test/fuzz/load_external_block_file.cpp2
-rw-r--r--src/test/fuzz/net.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp2
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/pow.cpp5
-rw-r--r--src/test/fuzz/process_message.cpp10
-rw-r--r--src/test/fuzz/process_messages.cpp12
-rw-r--r--src/test/fuzz/script.cpp4
-rw-r--r--src/test/fuzz/signet.cpp2
-rw-r--r--src/test/fuzz/util.h15
-rw-r--r--src/test/scheduler_tests.cpp1
-rw-r--r--src/test/sync_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp9
-rw-r--r--src/test/util/setup_common.cpp5
-rw-r--r--src/torcontrol.cpp3
-rw-r--r--src/txmempool.cpp1
-rw-r--r--src/txmempool.h2
-rw-r--r--src/util/system.cpp4
-rw-r--r--src/validation.cpp11
-rw-r--r--src/validation.h6
-rw-r--r--src/wallet/bdb.cpp17
-rw-r--r--src/wallet/bdb.h4
-rw-r--r--src/wallet/init.cpp5
-rw-r--r--src/wallet/ismine.h22
-rw-r--r--src/wallet/load.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp17
-rw-r--r--src/wallet/test/init_test_fixture.cpp4
-rw-r--r--src/wallet/wallet.cpp2
-rw-r--r--src/wallet/wallettool.cpp2
-rw-r--r--src/zmq/zmqpublishnotifier.cpp40
-rwxr-xr-xtest/functional/feature_config_args.py6
-rwxr-xr-xtest/functional/interface_zmq.py106
-rwxr-xr-xtest/functional/rpc_deprecated.py33
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py78
-rw-r--r--test/functional/test_framework/util.py21
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_basic.py2
-rwxr-xr-xtest/functional/wallet_bumpfee.py3
-rwxr-xr-xtest/fuzz/test_runner.py27
-rwxr-xr-xtest/lint/lint-includes.sh1
-rwxr-xr-xtest/lint/lint-whitespace.sh2
-rw-r--r--test/sanitizer_suppressions/ubsan59
87 files changed, 1318 insertions, 616 deletions
diff --git a/Makefile.am b/Makefile.am
index c554f630ae..7c4b971ea3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,7 +141,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
+ $(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))
$(OSX_DMG): $(OSX_TEMP_ISO)
$(DMG) dmg "$<" "$@"
diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
index 6a3c9f1dc1..490ce8b1ce 100644
--- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
+++ b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
@@ -104,6 +104,7 @@
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiondesc.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiondescdialog.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionfilterproxy.cpp" />
+ <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionoverviewwidget.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionrecord.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiontablemodel.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionview.cpp" />
diff --git a/contrib/gitian-keys/keys.txt b/contrib/gitian-keys/keys.txt
index 7e28d27454..db28cd07a0 100644
--- a/contrib/gitian-keys/keys.txt
+++ b/contrib/gitian-keys/keys.txt
@@ -1,41 +1,51 @@
9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C Aaron Clauson (sipsorcery)
-617C90010B3BD370B0AC7D424BB42E31C79111B8 Akira Takizawa
-E944AE667CF960B1004BC32FCA662BE18B877A60 Andreas Schildbach
-152812300785C96444D3334D17565732E08E5E41 Andrew Chow
+617C90010B3BD370B0AC7D424BB42E31C79111B8 Akira Takizawa (akx20000)
+E944AE667CF960B1004BC32FCA662BE18B877A60 Andreas Schildbach (aschildbach)
+152812300785C96444D3334D17565732E08E5E41 Andrew Chow (achow101)
590B7292695AFFA5B672CBB2E13FC145CD3F4304 Antoine Poinsot (darosior)
0AD83877C1F0CD1EE9BD660AD7CC770B81FD22A8 Ben Carman (benthecarman)
-912FD3228387123DC97E0E57D5566241A0295FA9 BtcDrak
+912FD3228387123DC97E0E57D5566241A0295FA9 BtcDrak (btcdrak)
C519EBCF3B926298946783EFF6430754120EC2F4 Christian Decker (cdecker)
-F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur
-C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields
-BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random
-6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark
+18AE2F798E0D239755DA4FD24B79F986CBDF8736 Chun Kuan Le (ken2812221)
+101598DC823C1B5F9A6624ABA5E0907A0380E6C3 CoinForensics (CoinForensics)
+F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur (centaur)
+C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields (cfields)
+BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random (devrandom)
+6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark (droark)
+1C6621605EC50319C463D56C7F81D87985D61612 Emanuele Cisbani (cisba)
9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos)
-D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece
-01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen
+D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece (fivepiece)
+6F993B250557E7B016ADE5713BDCDA2D87A881D9 Fuzzbawls (Fuzzbawls)
+01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen (gavinandresen)
D1DBF2C4B96F2DEBF4C16654410108112E7EA81F Hennadii Stepanov (hebasto)
-D3CC177286005BB8FF673294C5242A1AB3936517 jl2012
-82921A4B88FD454B7EB8CE3C796C4109063D4EAF Jon Atack
-32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli
-4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon
+A2FD494D0021AA9B4FA58F759102B7AE654A4A5A Ilyas Ridhuan (IlyasRidhuan)
+D3F22A3A4C366C2DCB66D3722DA9C5A7FA81EA35 Jarol Rodriguez (jarolrod)
+7480909378D544EA6B6DCEB7535B12980BB8A4D3 Jeffri H Frontz (jhfrontz)
+D3CC177286005BB8FF673294C5242A1AB3936517 jl2012 (jl2012)
+82921A4B88FD454B7EB8CE3C796C4109063D4EAF Jon Atack (jonatack)
+32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli (jonasschnelli)
+4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon (jtimon)
C42AFF7C61B3E44A1454CD3557AF762DB3353322 Karl-Johan Alm (kallewoof)
-E463A93F5F3117EEDE6C7316BD02942421F4889F Luke Dashjr
-B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B Marco Falke
+30DE693AE0DE9E37B3E7EB6BBFF0F67810C1EED1 Lisa Neigut (niftynei)
+E463A93F5F3117EEDE6C7316BD02942421F4889F Luke Dashjr (luke-jr)
+B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B Marco Falke (marco)
07DF3E57A548CCFB7530709189BBB8663E2E65CE Matt Corallo (BlueMatt)
-CA03882CB1FC067B5D3ACFE4D300116E1C875A3D MeshCollider
-E777299FC265DD04793070EB944D35F9AC3DB76A Michael Ford
+CA03882CB1FC067B5D3ACFE4D300116E1C875A3D MeshCollider (meshcollider)
+E777299FC265DD04793070EB944D35F9AC3DB76A Michael Ford (fanquake)
AD5764F4ADCE1B99BDFD179E12335A271D4D62EC Michael Tidwell (miketwenty1)
-9692B91BBF0E8D34DFD33B1882C5C009628ECF0C Michagogo
-77E72E69DA7EE0A148C06B21B34821D4944DE5F7 Nils Schneider
-F4FC70F07310028424EFC20A8E4256593F177720 Oliver Gugger
-D62A803E27E7F43486035ADBBCD04D8E9CCCAC2A Paul Rabahy
-37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04 Peter Todd
-D762373D24904A3E42F33B08B9A408E71DAAC974 Pieter Wuille (Location: Leuven, Belgium)
-133EAC179436F14A5CF1B794860FEB804E669320 Pieter Wuille
+9692B91BBF0E8D34DFD33B1882C5C009628ECF0C Michagogo (michagogo)
+C57E4B42223FDE851D4F69DD28DF2724F241D8EE midnightmagic (midnightmagic)
+F4FC70F07310028424EFC20A8E4256593F177720 Oliver Gugger (guggero, Oliver Gugger)
+D62A803E27E7F43486035ADBBCD04D8E9CCCAC2A Paul Rabahy (prab)
+37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04 Peter Todd (petertodd)
+D762373D24904A3E42F33B08B9A408E71DAAC974 Pieter Wuille [Location: Leuven, Belgium] (sipa)
+133EAC179436F14A5CF1B794860FEB804E669320 Pieter Wuille (sipa)
6A8F9C266528E25AEB1D7731C2371D91CB716EA7 Sebastian Falbesoner (theStack)
A8FC55F3B04BA3146F3492E79303B33A305224CB Sebastian Kung (TheCharlatan)
-ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost
+ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost (sjors)
+867345026B6763E8B07EE73AB6737117397F5C4F Stephan Oeste (Emzy)
9EDAFF80E080659604F4A76B2EBB056FD847F8A7 Stephan Oeste (Emzy)
-AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami
-79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko
-71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan
+6DEEF79B050C4072509B743F8C275BC595448867 Tomas Kanocz (KanoczTomas)
+AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami (wtogami)
+79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko (willyko)
+71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan (laanwj)
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index dbe1ea837b..5870deee39 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -105,7 +105,8 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
Override the space-separated list of platform triples for which to perform a
bootstrappable build. _(defaults to "x86\_64-linux-gnu arm-linux-gnueabihf
- aarch64-linux-gnu riscv64-linux-gnu x86_64-w64-mingw32")_
+ aarch64-linux-gnu riscv64-linux-gnu x86_64-w64-mingw32
+ x86_64-apple-darwin18")_
* _**SOURCES_PATH**_
diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh
index 54cc5793f6..da6bd13f6a 100755
--- a/contrib/guix/guix-build.sh
+++ b/contrib/guix/guix-build.sh
@@ -65,12 +65,13 @@ else
fi
################
-# Check 4: Make sure that build directories do no exist
+# Check 4: Make sure that build directories do not exist
################
# Default to building for all supported HOSTs (overridable by environment)
export HOSTS="${HOSTS:-x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu
- x86_64-w64-mingw32}"
+ x86_64-w64-mingw32
+ x86_64-apple-darwin18}"
DISTSRC_BASE="${DISTSRC_BASE:-${PWD}}"
@@ -105,9 +106,28 @@ for host in $hosts_distsrc_exists; do
done
exit 1
else
+
mkdir -p "$DISTSRC_BASE"
fi
+################
+# Check 5: When building for darwin, make sure that the macOS SDK exists
+################
+
+for host in $HOSTS; do
+ case "$host" in
+ *darwin*)
+ OSX_SDK="$(make -C "${PWD}/depends" --no-print-directory HOST="$host" print-OSX_SDK | sed 's@^[^=]\+=[[:space:]]\+@@g')"
+ if [ -e "$OSX_SDK" ]; then
+ echo "Found macOS SDK at '${OSX_SDK}', using..."
+ else
+ echo "macOS SDK does not exist at '${OSX_SDK}', please place the extracted, untarred SDK there to perform darwin builds, exiting..."
+ exit 1
+ fi
+ ;;
+ esac
+done
+
#########
# Setup #
#########
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index b00c42ce01..39d3cb9b50 100644
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -38,7 +38,28 @@ store_path() {
--expression='s|"[[:space:]]*$||'
}
-# Set environment variables to point Guix's cross-toolchain to the right
+
+# Set environment variables to point the NATIVE toolchain to the right
+# includes/libs
+NATIVE_GCC="$(store_path gcc-toolchain)"
+export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64"
+export CPATH="${NATIVE_GCC}/include"
+case "$HOST" in
+ *darwin*)
+ # When targeting darwin, some native tools built by depends require
+ # native packages not incorporated in depends
+ #
+ # libcap required by native_cdrkit/wodim
+ # zlib, bzip2 required by native_cdrkit/genisoimage
+ for native_pkg in libcap zlib bzip2; do
+ native_pkg_store_path=$(store_path "$native_pkg")
+ export LIBRARY_PATH="${native_pkg_store_path}/lib:${LIBRARY_PATH}"
+ export CPATH="${native_pkg_store_path}/include:${CPATH}"
+ done
+ ;;
+esac
+
+# Set environment variables to point the CROSS toolchain to the right
# includes/libs for $HOST
case "$HOST" in
*mingw*)
@@ -48,14 +69,18 @@ case "$HOST" in
CROSS_GCC_LIBS=( "${CROSS_GCC}/lib/gcc/${HOST}"/* ) # This expands to an array of directories...
CROSS_GCC_LIB="${CROSS_GCC_LIBS[0]}" # ...we just want the first one (there should only be one)
- NATIVE_GCC="$(store_path gcc-glibc-2.27-toolchain)"
- export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64"
- export CPATH="${NATIVE_GCC}/include"
-
+ # The search path ordering is generally:
+ # 1. gcc-related search paths
+ # 2. libc-related search paths
+ # 2. kernel-header-related search paths (not applicable to mingw-w64 hosts)
export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include"
export CROSS_CPLUS_INCLUDE_PATH="${CROSS_GCC}/include/c++:${CROSS_GCC}/include/c++/${HOST}:${CROSS_GCC}/include/c++/backward:${CROSS_C_INCLUDE_PATH}"
export CROSS_LIBRARY_PATH="${CROSS_GCC}/lib:${CROSS_GCC}/${HOST}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib"
;;
+ *darwin*)
+ # The CROSS toolchain for darwin uses the SDK and ignores environment variables.
+ # See depends/hosts/darwin.mk for more details.
+ ;;
*linux*)
CROSS_GLIBC="$(store_path "glibc-cross-${HOST}")"
CROSS_GLIBC_STATIC="$(store_path "glibc-cross-${HOST}" static)"
@@ -64,9 +89,7 @@ case "$HOST" in
CROSS_GCC_LIBS=( "${CROSS_GCC}/lib/gcc/${HOST}"/* ) # This expands to an array of directories...
CROSS_GCC_LIB="${CROSS_GCC_LIBS[0]}" # ...we just want the first one (there should only be one)
- # NOTE: CROSS_C_INCLUDE_PATH is missing ${CROSS_GCC_LIB}/include-fixed, because
- # the limits.h in it is missing a '#include_next <limits.h>'
- export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GLIBC}/include:${CROSS_KERNEL}/include"
+ export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include:${CROSS_KERNEL}/include"
export CROSS_CPLUS_INCLUDE_PATH="${CROSS_GCC}/include/c++:${CROSS_GCC}/include/c++/${HOST}:${CROSS_GCC}/include/c++/backward:${CROSS_C_INCLUDE_PATH}"
export CROSS_LIBRARY_PATH="${CROSS_GCC}/lib:${CROSS_GCC}/${HOST}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib:${CROSS_GLIBC_STATIC}/lib"
;;
@@ -77,14 +100,25 @@ esac
# Sanity check CROSS_*_PATH directories
IFS=':' read -ra PATHS <<< "${CROSS_C_INCLUDE_PATH}:${CROSS_CPLUS_INCLUDE_PATH}:${CROSS_LIBRARY_PATH}"
for p in "${PATHS[@]}"; do
- if [ ! -d "$p" ]; then
+ if [ -n "$p" ] && [ ! -d "$p" ]; then
echo "'$p' doesn't exist or isn't a directory... Aborting..."
exit 1
fi
done
# Disable Guix ld auto-rpath behavior
-export GUIX_LD_WRAPPER_DISABLE_RPATH=yes
+case "$HOST" in
+ *darwin*)
+ # The auto-rpath behavior is necessary for darwin builds as some native
+ # tools built by depends refer to and depend on Guix-built native
+ # libraries
+ #
+ # After the native packages in depends are built, the ld wrapper should
+ # no longer affect our build, as clang would instead reach for
+ # x86_64-apple-darwin18-ld from cctools
+ ;;
+ *) export GUIX_LD_WRAPPER_DISABLE_RPATH=yes ;;
+esac
# Make /usr/bin if it doesn't exist
[ -e /usr/bin ] || mkdir -p /usr/bin
@@ -114,6 +148,16 @@ export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name"
export TZ="UTC"
+case "$HOST" in
+ *darwin*)
+ # cctools AR, unlike GNU binutils AR, does not have a deterministic mode
+ # or a configure flag to enable determinism by default, it only
+ # understands if this env-var is set or not. See:
+ #
+ # https://github.com/tpoechtrager/cctools-port/blob/55562e4073dea0fbfd0b20e0bf69ffe6390c7f97/cctools/ar/archive.c#L334
+ export ZERO_AR_DATE=yes
+ ;;
+esac
####################
# Depends Building #
@@ -135,7 +179,8 @@ make -C depends --jobs="$MAX_JOBS" HOST="$HOST" \
x86_64_linux_RANLIB=x86_64-linux-gnu-ranlib \
x86_64_linux_NM=x86_64-linux-gnu-nm \
x86_64_linux_STRIP=x86_64-linux-gnu-strip \
- qt_config_opts_i686_linux='-platform linux-g++ -xplatform bitcoin-linux-g++'
+ qt_config_opts_i686_linux='-platform linux-g++ -xplatform bitcoin-linux-g++' \
+ FORCE_USE_SYSTEM_CLANG=1
###########################
@@ -169,6 +214,7 @@ HOST_CFLAGS="-O2 -g"
case "$HOST" in
*linux*) HOST_CFLAGS+=" -ffile-prefix-map=${PWD}=." ;;
*mingw*) HOST_CFLAGS+=" -fno-ident" ;;
+ *darwin*) unset HOST_CFLAGS ;;
esac
# CXXFLAGS
@@ -199,8 +245,8 @@ mkdir -p "$DISTSRC"
--disable-maintainer-mode \
--disable-dependency-tracking \
${CONFIGFLAGS} \
- CFLAGS="${HOST_CFLAGS}" \
- CXXFLAGS="${HOST_CXXFLAGS}" \
+ ${HOST_CFLAGS:+CFLAGS="${HOST_CFLAGS}"} \
+ ${HOST_CXXFLAGS:+CXXFLAGS="${HOST_CXXFLAGS}"} \
${HOST_LDFLAGS:+LDFLAGS="${HOST_LDFLAGS}"}
sed -i.old 's/-lstdc++ //g' config.status libtool src/univalue/config.status src/univalue/libtool
@@ -210,14 +256,9 @@ mkdir -p "$DISTSRC"
# Perform basic ELF security checks on a series of executables.
make -C src --jobs=1 check-security ${V:+V=1}
-
- case "$HOST" in
- *linux*|*mingw*)
- # Check that executables only contain allowed gcc, glibc and libstdc++
- # version symbols for Linux distro back-compatibility.
- make -C src --jobs=1 check-symbols ${V:+V=1}
- ;;
- esac
+ # Check that executables only contain allowed gcc, glibc and libstdc++
+ # version symbols for Linux distro back-compatibility.
+ make -C src --jobs=1 check-symbols ${V:+V=1}
# Make the os-specific installers
case "$HOST" in
@@ -232,8 +273,39 @@ mkdir -p "$DISTSRC"
INSTALLPATH="${PWD}/installed/${DISTNAME}"
mkdir -p "${INSTALLPATH}"
# Install built Bitcoin Core to $INSTALLPATH
- make install DESTDIR="${INSTALLPATH}" ${V:+V=1}
+ case "$HOST" in
+ *darwin*)
+ make install-strip DESTDIR="${INSTALLPATH}" ${V:+V=1}
+ ;;
+ *)
+ make install DESTDIR="${INSTALLPATH}" ${V:+V=1}
+ ;;
+ esac
+ case "$HOST" in
+ *darwin*)
+ make osx_volname ${V:+V=1}
+ make deploydir ${V:+V=1}
+ mkdir -p "unsigned-app-${HOST}"
+ cp --target-directory="unsigned-app-${HOST}" \
+ osx_volname \
+ contrib/macdeploy/detached-sig-{apply,create}.sh \
+ "${BASEPREFIX}/${HOST}"/native/bin/dmg
+ for util in codesign_allocate pagestuff; do
+ cp --no-target-directory {"${BASEPREFIX}/${HOST}/native/bin/${HOST}-","unsigned-app-${HOST}/"}"$util"
+ done
+ mv --target-directory="unsigned-app-${HOST}" dist
+ (
+ cd "unsigned-app-${HOST}"
+ find . -print0 \
+ | sort --zero-terminated \
+ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
+ | gzip -9n > "${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz" \
+ || ( rm -f "${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz" && exit 1 )
+ )
+ make deploy ${V:+V=1} OSX_DMG="${OUTDIR}/${DISTNAME}-osx-unsigned.dmg"
+ ;;
+ esac
(
cd installed
@@ -248,13 +320,18 @@ mkdir -p "$DISTSRC"
find . -name "lib*.a" -delete
# Prune pkg-config files
- rm -r "${DISTNAME}/lib/pkgconfig"
+ rm -rf "${DISTNAME}/lib/pkgconfig"
- # Split binaries and libraries from their debug symbols
- {
- find "${DISTNAME}/bin" -type f -executable -print0
- find "${DISTNAME}/lib" -type f -print0
- } | xargs -0 -n1 -P"$MAX_JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg
+ case "$HOST" in
+ *darwin*) ;;
+ *)
+ # Split binaries and libraries from their debug symbols
+ {
+ find "${DISTNAME}/bin" -type f -executable -print0
+ find "${DISTNAME}/lib" -type f -print0
+ } | xargs -0 -n1 -P"$MAX_JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg
+ ;;
+ esac
case "$HOST" in
*mingw*)
@@ -294,6 +371,13 @@ mkdir -p "$DISTSRC"
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz" && exit 1 )
;;
+ *darwin*)
+ find "${DISTNAME}" -print0 \
+ | sort --zero-terminated \
+ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
+ | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST//x86_64-apple-darwin18/osx64}.tar.gz" \
+ || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-apple-darwin18/osx64}.tar.gz" && exit 1 )
+ ;;
esac
)
)
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 5e011ea184..3b89659263 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -3,28 +3,44 @@
(gnu packages autotools)
(gnu packages base)
(gnu packages bash)
+ (gnu packages cdrom)
(gnu packages check)
+ (gnu packages cmake)
(gnu packages commencement)
(gnu packages compression)
(gnu packages cross-base)
(gnu packages file)
(gnu packages gawk)
(gnu packages gcc)
+ (gnu packages gnome)
+ (gnu packages image)
+ (gnu packages imagemagick)
(gnu packages installers)
(gnu packages linux)
+ (gnu packages llvm)
(gnu packages mingw)
(gnu packages perl)
(gnu packages pkg-config)
(gnu packages python)
(gnu packages shells)
(gnu packages version-control)
+ (guix build-system font)
(guix build-system gnu)
(guix build-system trivial)
+ (guix download)
(guix gexp)
+ ((guix licenses) #:prefix license:)
(guix packages)
(guix profiles)
(guix utils))
+(define-syntax-rule (search-our-patches file-name ...)
+ "Return the list of absolute file names corresponding to each
+FILE-NAME found in ./patches relative to the current file."
+ (parameterize
+ ((%patch-path (list (string-append (dirname (current-filename)) "/patches"))))
+ (list (search-patch file-name) ...)))
+
(define (make-ssp-fixed-gcc xgcc)
"Given a XGCC package, return a modified package that uses the SSP function
from glibc instead of from libssp.so. Our `symbol-check' script will complain if
@@ -150,11 +166,33 @@ chain for " target " development."))
(home-page (package-home-page pthreads-xgcc))
(license (package-license pthreads-xgcc)))))
+(define (make-nsis-with-sde-support base-nsis)
+ (package-with-extra-patches base-nsis
+ (search-our-patches "nsis-SConstruct-sde-support.patch")))
+
+(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)))
(packages->manifest
(append
(list ;; The Basics
- bash-minimal
+ bash
which
coreutils
util-linux
@@ -184,15 +222,19 @@ chain for " target " development."))
python-3.7
;; Git
git
- ;; Native gcc 9 toolchain targeting glibc 2.27
- (make-gcc-toolchain gcc-9 glibc-2.27))
+ ;; Native gcc 7 toolchain
+ gcc-toolchain-7)
(let ((target (getenv "HOST")))
(cond ((string-suffix? "-mingw32" target)
;; Windows
- (list zip (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32") nsis-x86_64))
+ (list zip
+ (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32")
+ (make-nsis-with-sde-support nsis-x86_64)))
((string-contains target "riscv64-linux-")
(list (make-bitcoin-cross-toolchain "riscv64-linux-gnu"
#:base-gcc-for-libc gcc-7)))
((string-contains target "-linux-")
(list (make-bitcoin-cross-toolchain target)))
+ ((string-contains target "darwin")
+ (list clang-8 libcap binutils imagemagick libtiff librsvg font-tuffy cmake-3.15.5 xorriso))
(else '())))))
diff --git a/contrib/guix/patches/nsis-SConstruct-sde-support.patch b/contrib/guix/patches/nsis-SConstruct-sde-support.patch
new file mode 100644
index 0000000000..5edf1b7c8e
--- /dev/null
+++ b/contrib/guix/patches/nsis-SConstruct-sde-support.patch
@@ -0,0 +1,15 @@
+diff --git a/SConstruct b/SConstruct
+index e8252c9..41786f2 100755
+--- a/SConstruct
++++ b/SConstruct
+@@ -95,8 +95,8 @@ default_doctype = 'html'
+ if defenv.WhereIs('hhc', os.environ['PATH']):
+ default_doctype = 'chm'
+
+-from time import strftime, gmtime
+-cvs_version = strftime('%d-%b-%Y.cvs', gmtime())
++import time
++cvs_version = time.strftime('%d-%b-%Y.cvs', time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
+
+ opts = Variables()
+
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
index e9130a21de..4037936404 100755
--- a/contrib/install_db4.sh
+++ b/contrib/install_db4.sh
@@ -68,10 +68,155 @@ tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX"
cd "${BDB_PREFIX}/${BDB_VERSION}/"
# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592)
-CLANG_CXX11_PATCH_URL='https://gist.githubusercontent.com/LnL7/5153b251fd525fe15de69b67e63a6075/raw/7778e9364679093a32dec2908656738e16b6bdcb/clang.patch'
-CLANG_CXX11_PATCH_HASH='7a9a47b03fd5fb93a16ef42235fa9512db9b0829cfc3bdf90edd3ec1f44d637c'
-http_get "${CLANG_CXX11_PATCH_URL}" clang.patch "${CLANG_CXX11_PATCH_HASH}"
-patch -p2 < clang.patch
+patch --ignore-whitespace -p1 << 'EOF'
+commit 3311d68f11d1697565401eee6efc85c34f022ea7
+Author: fanquake <fanquake@gmail.com>
+Date: Mon Aug 17 20:03:56 2020 +0800
+
+ Fix C++11 compatibility
+
+diff --git a/dbinc/atomic.h b/dbinc/atomic.h
+index 0034dcc..7c11d4a 100644
+--- a/dbinc/atomic.h
++++ b/dbinc/atomic.h
+@@ -70,7 +70,7 @@ typedef struct {
+ * These have no memory barriers; the caller must include them when necessary.
+ */
+ #define atomic_read(p) ((p)->value)
+-#define atomic_init(p, val) ((p)->value = (val))
++#define atomic_init_db(p, val) ((p)->value = (val))
+
+ #ifdef HAVE_ATOMIC_SUPPORT
+
+@@ -144,7 +144,7 @@ typedef LONG volatile *interlocked_val;
+ #define atomic_inc(env, p) __atomic_inc(p)
+ #define atomic_dec(env, p) __atomic_dec(p)
+ #define atomic_compare_exchange(env, p, o, n) \
+- __atomic_compare_exchange((p), (o), (n))
++ __atomic_compare_exchange_db((p), (o), (n))
+ static inline int __atomic_inc(db_atomic_t *p)
+ {
+ int temp;
+@@ -176,7 +176,7 @@ static inline int __atomic_dec(db_atomic_t *p)
+ * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
+ * which configure could be changed to use.
+ */
+-static inline int __atomic_compare_exchange(
++static inline int __atomic_compare_exchange_db(
+ db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
+ {
+ atomic_value_t was;
+@@ -206,7 +206,7 @@ static inline int __atomic_compare_exchange(
+ #define atomic_dec(env, p) (--(p)->value)
+ #define atomic_compare_exchange(env, p, oldval, newval) \
+ (DB_ASSERT(env, atomic_read(p) == (oldval)), \
+- atomic_init(p, (newval)), 1)
++ atomic_init_db(p, (newval)), 1)
+ #else
+ #define atomic_inc(env, p) __atomic_inc(env, p)
+ #define atomic_dec(env, p) __atomic_dec(env, p)
+diff --git a/mp/mp_fget.c b/mp/mp_fget.c
+index 5fdee5a..0b75f57 100644
+--- a/mp/mp_fget.c
++++ b/mp/mp_fget.c
+@@ -617,7 +617,7 @@ alloc: /* Allocate a new buffer header and data space. */
+
+ /* Initialize enough so we can call __memp_bhfree. */
+ alloc_bhp->flags = 0;
+- atomic_init(&alloc_bhp->ref, 1);
++ atomic_init_db(&alloc_bhp->ref, 1);
+ #ifdef DIAGNOSTIC
+ if ((uintptr_t)alloc_bhp->buf & (sizeof(size_t) - 1)) {
+ __db_errx(env,
+@@ -911,7 +911,7 @@ alloc: /* Allocate a new buffer header and data space. */
+ MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize,
+ PROT_READ);
+
+- atomic_init(&alloc_bhp->ref, 1);
++ atomic_init_db(&alloc_bhp->ref, 1);
+ MUTEX_LOCK(env, alloc_bhp->mtx_buf);
+ alloc_bhp->priority = bhp->priority;
+ alloc_bhp->pgno = bhp->pgno;
+diff --git a/mp/mp_mvcc.c b/mp/mp_mvcc.c
+index 34467d2..f05aa0c 100644
+--- a/mp/mp_mvcc.c
++++ b/mp/mp_mvcc.c
+@@ -276,7 +276,7 @@ __memp_bh_freeze(dbmp, infop, hp, bhp, need_frozenp)
+ #else
+ memcpy(frozen_bhp, bhp, SSZA(BH, buf));
+ #endif
+- atomic_init(&frozen_bhp->ref, 0);
++ atomic_init_db(&frozen_bhp->ref, 0);
+ if (mutex != MUTEX_INVALID)
+ frozen_bhp->mtx_buf = mutex;
+ else if ((ret = __mutex_alloc(env, MTX_MPOOL_BH,
+@@ -428,7 +428,7 @@ __memp_bh_thaw(dbmp, infop, hp, frozen_bhp, alloc_bhp)
+ #endif
+ alloc_bhp->mtx_buf = mutex;
+ MUTEX_LOCK(env, alloc_bhp->mtx_buf);
+- atomic_init(&alloc_bhp->ref, 1);
++ atomic_init_db(&alloc_bhp->ref, 1);
+ F_CLR(alloc_bhp, BH_FROZEN);
+ }
+
+diff --git a/mp/mp_region.c b/mp/mp_region.c
+index e6cece9..ddbe906 100644
+--- a/mp/mp_region.c
++++ b/mp/mp_region.c
+@@ -224,7 +224,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
+ MTX_MPOOL_FILE_BUCKET, 0, &htab[i].mtx_hash)) != 0)
+ return (ret);
+ SH_TAILQ_INIT(&htab[i].hash_bucket);
+- atomic_init(&htab[i].hash_page_dirty, 0);
++ atomic_init_db(&htab[i].hash_page_dirty, 0);
+ }
+
+ /*
+@@ -269,7 +269,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
+ hp->mtx_hash = (mtx_base == MUTEX_INVALID) ? MUTEX_INVALID :
+ mtx_base + i;
+ SH_TAILQ_INIT(&hp->hash_bucket);
+- atomic_init(&hp->hash_page_dirty, 0);
++ atomic_init_db(&hp->hash_page_dirty, 0);
+ #ifdef HAVE_STATISTICS
+ hp->hash_io_wait = 0;
+ hp->hash_frozen = hp->hash_thawed = hp->hash_frozen_freed = 0;
+diff --git a/mutex/mut_method.c b/mutex/mut_method.c
+index 2588763..5c6d516 100644
+--- a/mutex/mut_method.c
++++ b/mutex/mut_method.c
+@@ -426,7 +426,7 @@ atomic_compare_exchange(env, v, oldval, newval)
+ MUTEX_LOCK(env, mtx);
+ ret = atomic_read(v) == oldval;
+ if (ret)
+- atomic_init(v, newval);
++ atomic_init_db(v, newval);
+ MUTEX_UNLOCK(env, mtx);
+
+ return (ret);
+diff --git a/mutex/mut_tas.c b/mutex/mut_tas.c
+index f3922e0..e40fcdf 100644
+--- a/mutex/mut_tas.c
++++ b/mutex/mut_tas.c
+@@ -46,7 +46,7 @@ __db_tas_mutex_init(env, mutex, flags)
+
+ #ifdef HAVE_SHARED_LATCHES
+ if (F_ISSET(mutexp, DB_MUTEX_SHARED))
+- atomic_init(&mutexp->sharecount, 0);
++ atomic_init_db(&mutexp->sharecount, 0);
+ else
+ #endif
+ if (MUTEX_INIT(&mutexp->tas)) {
+@@ -486,7 +486,7 @@ __db_tas_mutex_unlock(env, mutex)
+ F_CLR(mutexp, DB_MUTEX_LOCKED);
+ /* Flush flag update before zeroing count */
+ MEMBAR_EXIT();
+- atomic_init(&mutexp->sharecount, 0);
++ atomic_init_db(&mutexp->sharecount, 0);
+ } else {
+ DB_ASSERT(env, sharecount > 0);
+ MEMBAR_EXIT();
+EOF
# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
# Replace them with modern versions.
diff --git a/depends/README.md b/depends/README.md
index 9bc9b6714b..9e9878c595 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -44,7 +44,7 @@ The paths are automatically configured and no other options are needed unless ta
#### For macOS cross compilation
- sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools libtinfo5
+ sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools libtinfo5 xorriso
#### For Win64 cross compilation
diff --git a/doc/release-process.md b/doc/release-process.md
index 92845bcc82..9fdb19edf1 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -326,6 +326,18 @@ bitcoin.org (see below for bitcoin.org update instructions).
- bitcoincore.org RPC documentation update
+ - Install [golang](https://golang.org/doc/install)
+
+ - Install the new Bitcoin Core release
+
+ - Run bitcoind on regtest
+
+ - Clone the [bitcoincore.org repository](https://github.com/bitcoin-core/bitcoincore.org)
+
+ - Run: `go run generate.go` while being in `contrib/doc-gen` folder, and with bitcoin-cli in PATH
+
+ - Add the generated files to git
+
- Update packaging repo
- Push the flatpak to flathub, e.g. https://github.com/flathub/org.bitcoincore.bitcoin-qt/pull/2
diff --git a/doc/tor.md b/doc/tor.md
index 1ba7137b8e..8a2aef2d07 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -23,14 +23,19 @@ outgoing connections, but more is possible.
-proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy
server will be used to try to reach .onion addresses as well.
+ You need to use -noonion or -onion=0 to explicitly disable
+ outbound access to onion services.
-onion=ip:port Set the proxy server to use for Tor onion services. You do not
- need to set this if it's the same as -proxy. You can use -noonion
+ need to set this if it's the same as -proxy. You can use -onion=0
to explicitly disable access to onion services.
+ Note: Only the -proxy option sets the proxy for DNS requests;
+ with -onion they will not route over Tor, so use -proxy if you
+ have privacy concerns.
-listen When using -proxy, listening is disabled by default. If you want
- to run an onion service (see next section), you'll need to enable
- it explicitly.
+ to manually configure an onion service (see section 3), you'll
+ need to enable it explicitly.
-connect=X When behind a Tor proxy, you can specify .onion addresses instead
-addnode=X of IP addresses or hostnames in these parameters. It requires
@@ -40,19 +45,112 @@ outgoing connections, but more is possible.
-onlynet=onion Make outgoing connections only to .onion addresses. Incoming
connections are not affected by this option. This option can be
specified multiple times to allow multiple network types, e.g.
- ipv4, ipv6, or onion.
+ ipv4, ipv6 or onion. If you use this option with values other
+ than onion you *cannot* disable onion connections; outgoing onion
+ connections will be enabled when you use -proxy or -onion. Use
+ -noonion or -onion=0 if you want to be sure there are no outbound
+ onion connections over the default proxy or your defined -proxy.
In a typical situation, this suffices to run behind a Tor proxy:
./bitcoind -proxy=127.0.0.1:9050
+## 2. Automatically create a Bitcoin Core onion service
-## 2. Manually create a Bitcoin Core onion service
+Bitcoin Core makes use of Tor's control socket API to create and destroy
+ephemeral onion services programmatically. This means that if Tor is running and
+proper authentication has been configured, Bitcoin Core automatically creates an
+onion service to listen on. The goal is to increase the number of available
+onion nodes.
-If you configure your Tor system accordingly, it is possible to make your node also
-reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent
-config file): *Needed for Tor version 0.2.7.0 and older versions of Tor only. For newer
-versions of Tor see [Section 3](#3-automatically-listen-on-tor).*
+This feature is enabled by default if Bitcoin Core is listening (`-listen`) and
+it requires a Tor connection to work. It can be explicitly disabled with
+`-listenonion=0`. If it is not disabled, it can be configured using the
+`-torcontrol` and `-torpassword` settings.
+
+To see verbose Tor information in the bitcoind debug log, pass `-debug=tor`.
+
+### Control Port
+
+You may need to set up the Tor Control Port. On Linux distributions there may be
+some or all of the following settings in `/etc/tor/torrc`, generally commented
+out by default (if not, add them):
+
+```
+ControlPort 9051
+CookieAuthentication 1
+CookieAuthFileGroupReadable 1
+```
+
+Add or uncomment those, save, and restart Tor (usually `systemctl restart tor`
+or `sudo systemctl restart tor` on most systemd-based systems, including recent
+Debian and Ubuntu, or just restart the computer).
+
+On some systems (such as Arch Linux), you may also need to add the following
+line:
+
+```
+DataDirectoryGroupReadable 1
+```
+
+### Authentication
+
+Connecting to Tor's control socket API requires one of two authentication
+methods to be configured: cookie authentication or bitcoind's `-torpassword`
+configuration option.
+
+#### Cookie authentication
+
+For cookie authentication, the user running bitcoind must have read access to
+the `CookieAuthFile` specified in the Tor configuration. In some cases this is
+preconfigured and the creation of an onion service is automatic. Don't forget to
+use the `-debug=tor` bitcoind configuration option to enable Tor debug logging.
+
+If a permissions problem is seen in the debug log, e.g. `tor: Authentication
+cookie /run/tor/control.authcookie could not be opened (check permissions)`, it
+can be resolved by adding both the user running Tor and the user running
+bitcoind to the same Tor group and setting permissions appropriately.
+
+On Debian-derived systems, the Tor group will likely be `debian-tor` and one way
+to verify could be to list the groups and grep for a "tor" group name:
+
+```
+getent group | cut -d: -f1 | grep -i tor
+```
+
+You can also check the group of the cookie file. On most Linux systems, the Tor
+auth cookie will usually be `/run/tor/control.authcookie`:
+
+```
+stat -c '%G' /run/tor/control.authcookie
+```
+
+Once you have determined the `${TORGROUP}` and selected the `${USER}` that will
+run bitcoind, run this as root:
+
+```
+usermod -a -G ${TORGROUP} ${USER}
+```
+
+Then restart the computer (or log out) and log in as the `${USER}` that will run
+bitcoind.
+
+#### `torpassword` authentication
+
+For the `-torpassword=password` option, the password is the clear text form that
+was used when generating the hashed password for the `HashedControlPassword`
+option in the Tor configuration file.
+
+The hashed password can be obtained with the command `tor --hash-password
+password` (refer to the [Tor Dev
+Manual](https://2019.www.torproject.org/docs/tor-manual.html.en) for more
+details).
+
+
+## 3. Manually create a Bitcoin Core onion service
+
+You can also manually configure your node to be reachable from the Tor network.
+Add these lines to your `/etc/tor/torrc` (or equivalent config file):
HiddenServiceDir /var/lib/tor/bitcoin-service/
HiddenServicePort 8333 127.0.0.1:8334
@@ -106,44 +204,10 @@ for normal IPv4/IPv6 communication, use:
./bitcoind -onion=127.0.0.1:9050 -externalip=7zvj7a2imdgkdbg4f2dryd5rgtrn7upivr5eeij4cicjh65pooxeshid.onion -discover
-## 3. Automatically create a Bitcoin Core onion service
-
-Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket
-API, to create and destroy 'ephemeral' onion services programmatically.
-Bitcoin Core has been updated to make use of this.
-
-This means that if Tor is running (and proper authentication has been configured),
-Bitcoin Core automatically creates an onion service to listen on. This will positively
-affect the number of available .onion nodes.
-
-This new feature is enabled by default if Bitcoin Core is listening (`-listen`), and
-requires a Tor connection to work. It can be explicitly disabled with `-listenonion=0`
-and, if not disabled, configured using the `-torcontrol` and `-torpassword` settings.
-To show verbose debugging information, pass `-debug=tor`.
-
-Connecting to Tor's control socket API requires one of two authentication methods to be
-configured. It also requires the control socket to be enabled, e.g. put `ControlPort 9051`
-in `torrc` config file. For cookie authentication the user running bitcoind must have read
-access to the `CookieAuthFile` specified in Tor configuration. In some cases this is
-preconfigured and the creation of an onion service is automatic. If permission problems
-are seen with `-debug=tor` they can be resolved by adding both the user running Tor and
-the user running bitcoind to the same group and setting permissions appropriately. On
-Debian-based systems the user running bitcoind can be added to the debian-tor group,
-which has the appropriate permissions. Before starting bitcoind you will need to re-login
-to allow debian-tor group to be applied. Otherwise you will see the following notice: "tor:
-Authentication cookie /run/tor/control.authcookie could not be opened (check permissions)"
-on debug.log.
-
-An alternative authentication method is the use
-of the `-torpassword=password` option. The `password` is the clear text form that
-was used when generating the hashed password for the `HashedControlPassword` option
-in the tor configuration file. The hashed password can be obtained with the command
-`tor --hash-password password` (read the tor manual for more details).
-
## 4. Privacy recommendations
-- Do not add anything but Bitcoin Core ports to the onion service created in section 2.
+- Do not add anything but Bitcoin Core ports to the onion service created in section 3.
If you run a web service too, create a new onion service for that.
Otherwise it is trivial to link them, which may reduce privacy. Onion
- services created automatically (as in section 3) always have only one port
+ services created automatically (as in section 2) always have only one port
open.
diff --git a/src/Makefile.am b/src/Makefile.am
index 52bd4f1621..2616eb8638 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,6 +2,10 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+# Pattern rule to print variables, e.g. make print-top_srcdir
+print-%:
+ @echo $* = $($*)
+
DIST_SUBDIRS = secp256k1 univalue
AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 3d41d203d3..969f0ca411 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -78,6 +78,7 @@ QT_MOC_CPP = \
qt/moc_transactiondesc.cpp \
qt/moc_transactiondescdialog.cpp \
qt/moc_transactionfilterproxy.cpp \
+ qt/moc_transactionoverviewwidget.cpp \
qt/moc_transactiontablemodel.cpp \
qt/moc_transactionview.cpp \
qt/moc_utilitydialog.cpp \
@@ -151,6 +152,7 @@ BITCOIN_QT_H = \
qt/transactiondesc.h \
qt/transactiondescdialog.h \
qt/transactionfilterproxy.h \
+ qt/transactionoverviewwidget.h \
qt/transactionrecord.h \
qt/transactiontablemodel.h \
qt/transactionview.h \
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index ffa772d8c1..d7b8c1badc 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -10,8 +10,6 @@
#include <random.h>
#include <util/system.h>
-#include <boost/thread/thread.hpp>
-
#include <vector>
static const size_t BATCHES = 101;
@@ -44,12 +42,9 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
void swap(PrevectorJob& x){p.swap(x.p);};
};
CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
- boost::thread_group tg;
// The main thread should be counted to prevent thread oversubscription, and
// to decrease the variance of benchmark results.
- for (auto x = 0; x < GetNumCores() - 1; ++x) {
- tg.create_thread([&]{queue.Thread();});
- }
+ queue.StartWorkerThreads(GetNumCores() - 1);
// create all the data once, then submit copies in the benchmark.
FastRandomContext insecure_rand(true);
@@ -70,8 +65,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
// it is done explicitly here for clarity
control.Wait();
});
- tg.interrupt_all();
- tg.join_all();
+ queue.StopWorkerThreads();
ECC_Stop();
}
BENCHMARK(CCheckQueueSpeedPrevectorJob);
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index 4b45264a3c..45ed9f60dc 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -7,12 +7,15 @@
#include <rpc/blockchain.h>
#include <streams.h>
+#include <test/util/setup_common.h>
#include <validation.h>
#include <univalue.h>
static void BlockToJsonVerbose(benchmark::Bench& bench)
{
+ TestingSetup test_setup{};
+
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
char a = '\0';
stream.write(&a, 1); // Prevent compaction
diff --git a/src/checkqueue.h b/src/checkqueue.h
index e3faa1dec0..4ceeb3600a 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -6,13 +6,12 @@
#define BITCOIN_CHECKQUEUE_H
#include <sync.h>
+#include <tinyformat.h>
+#include <util/threadnames.h>
#include <algorithm>
#include <vector>
-#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/mutex.hpp>
-
template <typename T>
class CCheckQueueControl;
@@ -31,61 +30,64 @@ class CCheckQueue
{
private:
//! Mutex to protect the inner state
- boost::mutex mutex;
+ Mutex m_mutex;
//! Worker threads block on this when out of work
- boost::condition_variable condWorker;
+ std::condition_variable m_worker_cv;
//! Master thread blocks on this when out of work
- boost::condition_variable condMaster;
+ std::condition_variable m_master_cv;
//! The queue of elements to be processed.
//! As the order of booleans doesn't matter, it is used as a LIFO (stack)
- std::vector<T> queue;
+ std::vector<T> queue GUARDED_BY(m_mutex);
//! The number of workers (including the master) that are idle.
- int nIdle;
+ int nIdle GUARDED_BY(m_mutex){0};
//! The total number of workers (including the master).
- int nTotal;
+ int nTotal GUARDED_BY(m_mutex){0};
//! The temporary evaluation result.
- bool fAllOk;
+ bool fAllOk GUARDED_BY(m_mutex){true};
/**
* Number of verifications that haven't completed yet.
* This includes elements that are no longer queued, but still in the
* worker's own batches.
*/
- unsigned int nTodo;
+ unsigned int nTodo GUARDED_BY(m_mutex){0};
//! The maximum number of elements to be processed in one batch
- unsigned int nBatchSize;
+ const unsigned int nBatchSize;
+
+ std::vector<std::thread> m_worker_threads;
+ bool m_request_stop GUARDED_BY(m_mutex){false};
/** Internal function that does bulk of the verification work. */
- bool Loop(bool fMaster = false)
+ bool Loop(bool fMaster)
{
- boost::condition_variable& cond = fMaster ? condMaster : condWorker;
+ std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv;
std::vector<T> vChecks;
vChecks.reserve(nBatchSize);
unsigned int nNow = 0;
bool fOk = true;
do {
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ WAIT_LOCK(m_mutex, lock);
// first do the clean-up of the previous loop run (allowing us to do it in the same critsect)
if (nNow) {
fAllOk &= fOk;
nTodo -= nNow;
if (nTodo == 0 && !fMaster)
// We processed the last element; inform the master it can exit and return the result
- condMaster.notify_one();
+ m_master_cv.notify_one();
} else {
// first iteration
nTotal++;
}
// logically, the do loop starts here
- while (queue.empty()) {
+ while (queue.empty() && !m_request_stop) {
if (fMaster && nTodo == 0) {
nTotal--;
bool fRet = fAllOk;
@@ -98,6 +100,10 @@ private:
cond.wait(lock); // wait
nIdle--;
}
+ if (m_request_stop) {
+ return false;
+ }
+
// Decide how many work units to process now.
// * Do not try to do everything at once, but aim for increasingly smaller batches so
// all workers finish approximately simultaneously.
@@ -106,7 +112,7 @@ private:
nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
vChecks.resize(nNow);
for (unsigned int i = 0; i < nNow; i++) {
- // We want the lock on the mutex to be as short as possible, so swap jobs from the global
+ // We want the lock on the m_mutex to be as short as possible, so swap jobs from the global
// queue to the local batch vector instead of copying.
vChecks[i].swap(queue.back());
queue.pop_back();
@@ -124,40 +130,68 @@ private:
public:
//! Mutex to ensure only one concurrent CCheckQueueControl
- boost::mutex ControlMutex;
+ Mutex m_control_mutex;
//! Create a new check queue
- explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), nBatchSize(nBatchSizeIn) {}
+ explicit CCheckQueue(unsigned int nBatchSizeIn)
+ : nBatchSize(nBatchSizeIn)
+ {
+ }
- //! Worker thread
- void Thread()
+ //! Create a pool of new worker threads.
+ void StartWorkerThreads(const int threads_num)
{
- Loop();
+ {
+ LOCK(m_mutex);
+ nIdle = 0;
+ nTotal = 0;
+ fAllOk = true;
+ }
+ assert(m_worker_threads.empty());
+ for (int n = 0; n < threads_num; ++n) {
+ m_worker_threads.emplace_back([this, n]() {
+ util::ThreadRename(strprintf("scriptch.%i", n));
+ Loop(false /* worker thread */);
+ });
+ }
}
//! Wait until execution finishes, and return whether all evaluations were successful.
bool Wait()
{
- return Loop(true);
+ return Loop(true /* master thread */);
}
//! Add a batch of checks to the queue
void Add(std::vector<T>& vChecks)
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ LOCK(m_mutex);
for (T& check : vChecks) {
queue.push_back(T());
check.swap(queue.back());
}
nTodo += vChecks.size();
if (vChecks.size() == 1)
- condWorker.notify_one();
+ m_worker_cv.notify_one();
else if (vChecks.size() > 1)
- condWorker.notify_all();
+ m_worker_cv.notify_all();
+ }
+
+ //! Stop all of the worker threads.
+ void StopWorkerThreads()
+ {
+ WITH_LOCK(m_mutex, m_request_stop = true);
+ m_worker_cv.notify_all();
+ for (std::thread& t : m_worker_threads) {
+ t.join();
+ }
+ m_worker_threads.clear();
+ WITH_LOCK(m_mutex, m_request_stop = false);
}
~CCheckQueue()
{
+ assert(m_worker_threads.empty());
}
};
@@ -181,7 +215,7 @@ public:
{
// passed queue is supposed to be unused, or nullptr
if (pqueue != nullptr) {
- ENTER_CRITICAL_SECTION(pqueue->ControlMutex);
+ ENTER_CRITICAL_SECTION(pqueue->m_control_mutex);
}
}
@@ -205,7 +239,7 @@ public:
if (!fDone)
Wait();
if (pqueue != nullptr) {
- LEAVE_CRITICAL_SECTION(pqueue->ControlMutex);
+ LEAVE_CRITICAL_SECTION(pqueue->m_control_mutex);
}
}
};
diff --git a/src/fs.cpp b/src/fs.cpp
index 7eb0f5ca9f..4f20ca4d28 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -31,6 +31,12 @@ FILE *fopen(const fs::path& p, const char *mode)
#endif
}
+fs::path AbsPathJoin(const fs::path& base, const fs::path& path)
+{
+ assert(base.is_absolute());
+ return fs::absolute(path, base);
+}
+
#ifndef WIN32
static std::string GetErrorReason()
diff --git a/src/fs.h b/src/fs.h
index dfbecc18e6..d77b90be66 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -21,6 +21,17 @@ namespace fs = boost::filesystem;
namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode);
+ /**
+ * Helper function for joining two paths
+ *
+ * @param[in] base Base path
+ * @param[in] path Path to combine with base
+ * @returns path unchanged if it is an absolute path, otherwise returns base joined with path. Returns base unchanged if path is empty.
+ * @pre Base path must be absolute
+ * @post Returned path will always be absolute
+ */
+ fs::path AbsPathJoin(const fs::path& base, const fs::path& path);
+
class FileLock
{
public:
diff --git a/src/init.cpp b/src/init.cpp
index 09eb76eaee..64bbf8988d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -223,6 +223,7 @@ void Shutdown(NodeContext& node)
if (g_load_block.joinable()) g_load_block.join();
threadGroup.interrupt_all();
threadGroup.join_all();
+ StopScriptCheckWorkerThreads();
// After the threads that potentially access these pointers have been stopped,
// destruct and reset all to nullptr.
@@ -447,7 +448,7 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks. Warning: if it is used with ipv4 or ipv6 but not onion and the -onion or -proxy option is set, then outbound onion connections will still be made; use -noonion or -onion=0 to disable outbound onion connections in this case.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -1334,9 +1335,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
LogPrintf("Script verification uses %d additional threads\n", script_threads);
if (script_threads >= 1) {
g_parallel_script_checks = true;
- for (int i = 0; i < script_threads; ++i) {
- threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
- }
+ StartScriptCheckWorkerThreads(script_threads);
}
assert(!node.scheduler);
diff --git a/src/key_io.cpp b/src/key_io.cpp
index a270ede864..e27673fd16 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -12,6 +12,9 @@
#include <assert.h>
#include <string.h>
+/// Maximum witness length for Bech32 addresses.
+static constexpr std::size_t BECH32_WITNESS_PROG_MAX_LEN = 40;
+
namespace {
class DestinationEncoder
{
@@ -65,10 +68,11 @@ public:
std::string operator()(const CNoDestination& no) const { return {}; }
};
-CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
{
std::vector<unsigned char> data;
uint160 hash;
+ error_str = "";
if (DecodeBase58Check(str, data, 21)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
@@ -85,10 +89,21 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
return ScriptHash(hash);
}
+
+ // Set potential error message.
+ // This message may be changed if the address can also be interpreted as a Bech32 address.
+ error_str = "Invalid prefix for Base58-encoded address";
}
data.clear();
auto bech = bech32::Decode(str);
- if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
+ if (bech.second.size() > 0) {
+ error_str = "";
+
+ if (bech.first != params.Bech32HRP()) {
+ error_str = "Invalid prefix for Bech32 address";
+ return CNoDestination();
+ }
+
// Bech32 decoding
int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
// The rest of the symbols are converted witness program bytes.
@@ -109,11 +124,21 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return scriptid;
}
}
+
+ error_str = "Invalid Bech32 v0 address data size";
+ return CNoDestination();
+ }
+
+ if (version > 16) {
+ error_str = "Invalid Bech32 address witness version";
return CNoDestination();
}
- if (version > 16 || data.size() < 2 || data.size() > 40) {
+
+ if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) {
+ error_str = "Invalid Bech32 address data size";
return CNoDestination();
}
+
WitnessUnknown unk;
unk.version = version;
std::copy(data.begin(), data.end(), unk.program);
@@ -121,6 +146,10 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return unk;
}
}
+
+ // Set error message if address can't be interpreted as Base58 or Bech32.
+ if (error_str.empty()) error_str = "Invalid address format";
+
return CNoDestination();
}
} // namespace
@@ -208,14 +237,21 @@ std::string EncodeDestination(const CTxDestination& dest)
return std::visit(DestinationEncoder(Params()), dest);
}
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
+{
+ return DecodeDestination(str, Params(), error_msg);
+}
+
CTxDestination DecodeDestination(const std::string& str)
{
- return DecodeDestination(str, Params());
+ std::string error_msg;
+ return DecodeDestination(str, error_msg);
}
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
- return IsValidDestination(DecodeDestination(str, params));
+ std::string error_msg;
+ return IsValidDestination(DecodeDestination(str, params, error_msg));
}
bool IsValidDestinationString(const std::string& str)
diff --git a/src/key_io.h b/src/key_io.h
index d80c08f49c..bd81f7847e 100644
--- a/src/key_io.h
+++ b/src/key_io.h
@@ -23,6 +23,7 @@ std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
diff --git a/src/net.cpp b/src/net.cpp
index 4f74bbede4..4759287c36 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -35,6 +35,7 @@
#include <algorithm>
#include <cstdint>
+#include <functional>
#include <unordered_map>
#include <math.h>
@@ -1216,37 +1217,47 @@ void CConnman::NotifyNumConnectionsChanged()
}
}
-void CConnman::InactivityCheck(CNode *pnode) const
+bool CConnman::InactivityCheck(const CNode& node) const
{
- int64_t nTime = GetSystemTimeInSeconds();
- if (nTime - pnode->nTimeConnected > m_peer_connect_timeout)
- {
- if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
- {
- LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d from %d\n", m_peer_connect_timeout, pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId());
- pnode->fDisconnect = true;
- }
- else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
- {
- LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
- pnode->fDisconnect = true;
- }
- else if (nTime - pnode->nLastRecv > TIMEOUT_INTERVAL)
- {
- LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
- pnode->fDisconnect = true;
- }
- else if (pnode->nPingNonceSent && pnode->m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>())
- {
- LogPrintf("ping timeout: %fs\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - pnode->m_ping_start.load()));
- pnode->fDisconnect = true;
- }
- else if (!pnode->fSuccessfullyConnected)
- {
- LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId());
- pnode->fDisconnect = true;
- }
+ // Use non-mockable system time (otherwise these timers will pop when we
+ // use setmocktime in the tests).
+ int64_t now = GetSystemTimeInSeconds();
+
+ if (now <= node.nTimeConnected + m_peer_connect_timeout) {
+ // Only run inactivity checks if the peer has been connected longer
+ // than m_peer_connect_timeout.
+ return false;
}
+
+ if (node.nLastRecv == 0 || node.nLastSend == 0) {
+ LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d from %d\n", m_peer_connect_timeout, node.nLastRecv != 0, node.nLastSend != 0, node.GetId());
+ return true;
+ }
+
+ if (now > node.nLastSend + TIMEOUT_INTERVAL) {
+ LogPrintf("socket sending timeout: %is\n", now - node.nLastSend);
+ return true;
+ }
+
+ if (now > node.nLastRecv + TIMEOUT_INTERVAL) {
+ LogPrintf("socket receive timeout: %is\n", now - node.nLastRecv);
+ return true;
+ }
+
+ if (node.nPingNonceSent && node.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>()) {
+ // We use mockable time for ping timeouts. This means that setmocktime
+ // may cause pings to time out for peers that have been connected for
+ // longer than m_peer_connect_timeout.
+ LogPrintf("ping timeout: %fs\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - node.m_ping_start.load()));
+ return true;
+ }
+
+ if (!node.fSuccessfullyConnected) {
+ LogPrint(BCLog::NET, "version handshake timeout from %d\n", node.GetId());
+ return true;
+ }
+
+ return false;
}
bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
@@ -1522,7 +1533,7 @@ void CConnman::SocketHandler()
if (bytes_sent) RecordBytesSent(bytes_sent);
}
- InactivityCheck(pnode);
+ if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
}
{
LOCK(cs_vNodes);
diff --git a/src/net.h b/src/net.h
index 087135a290..3a1b55d054 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1044,7 +1044,8 @@ private:
void AcceptConnection(const ListenSocket& hListenSocket);
void DisconnectNodes();
void NotifyNumConnectionsChanged();
- void InactivityCheck(CNode *pnode) const;
+ /** Return true if the peer is inactive and should be disconnected. */
+ bool InactivityCheck(const CNode& node) const;
bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
void SocketHandler();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index f2a49e5a76..ccc0a6828c 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -30,6 +30,7 @@
#include <qt/macdockiconhandler.h>
#endif
+#include <functional>
#include <chain.h>
#include <chainparams.h>
#include <interfaces/handler.h>
@@ -845,7 +846,7 @@ void BitcoinGUI::showDebugWindowActivateConsole()
void BitcoinGUI::showHelpMessageClicked()
{
- helpMessageDialog->show();
+ GUIUtil::bringToFront(helpMessageDialog);
}
#ifdef ENABLE_WALLET
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index a2f46c339b..56813b2d19 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -19,6 +19,7 @@
#include <validation.h>
#include <stdint.h>
+#include <functional>
#include <QDebug>
#include <QThread>
diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui
index 0b33c2cb8d..881869a46c 100644
--- a/src/qt/forms/createwalletdialog.ui
+++ b/src/qt/forms/createwalletdialog.ui
@@ -7,140 +7,135 @@
<x>0</x>
<y>0</y>
<width>364</width>
- <height>213</height>
+ <height>249</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Wallet</string>
</property>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>170</y>
- <width>341</width>
- <height>32</height>
- </rect>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- <widget class="QLineEdit" name="wallet_name_line_edit">
- <property name="geometry">
- <rect>
- <x>120</x>
- <y>20</y>
- <width>231</width>
- <height>24</height>
- </rect>
- </property>
- <property name="placeholderText">
- <string>Wallet</string>
- </property>
- </widget>
- <widget class="QLabel" name="label">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>20</y>
- <width>101</width>
- <height>21</height>
- </rect>
- </property>
- <property name="text">
- <string>Wallet Name</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="encrypt_wallet_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>50</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string>
- </property>
- <property name="text">
- <string>Encrypt Wallet</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLabel" name="advanced_options_label">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>90</y>
- <width>220</width>
- <height>21</height>
- </rect>
- </property>
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
- </property>
- <property name="text">
- <string>Advanced options</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="disable_privkeys_checkbox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>115</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string>
- </property>
- <property name="text">
- <string>Disable Private Keys</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="blank_wallet_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>135</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string>
- </property>
- <property name="text">
- <string>Make Blank Wallet</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="descriptor_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>155</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Use descriptors for scriptPubKey management</string>
- </property>
- <property name="text">
- <string>Descriptor Wallet</string>
- </property>
- </widget>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="wallet_name_label">
+ <property name="text">
+ <string>Wallet Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="wallet_name_line_edit">
+ <property name="minimumSize">
+ <size>
+ <width>262</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="placeholderText">
+ <string>Wallet</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="encrypt_wallet_checkbox">
+ <property name="toolTip">
+ <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string>
+ </property>
+ <property name="text">
+ <string>Encrypt Wallet</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_1">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>8</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Advanced Options</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_groupbox">
+ <item>
+ <widget class="QCheckBox" name="disable_privkeys_checkbox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip">
+ <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string>
+ </property>
+ <property name="text">
+ <string>Disable Private Keys</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="blank_wallet_checkbox">
+ <property name="toolTip">
+ <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string>
+ </property>
+ <property name="text">
+ <string>Make Blank Wallet</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="descriptor_checkbox">
+ <property name="toolTip">
+ <string>Use descriptors for scriptPubKey management</string>
+ </property>
+ <property name="text">
+ <string>Descriptor Wallet</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
<tabstops>
<tabstop>wallet_name_line_edit</tabstop>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 4d3f90c484..ee9d4a113c 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -504,7 +504,7 @@
</layout>
</item>
<item>
- <widget class="QListView" name="listTransactions">
+ <widget class="TransactionOverviewWidget" name="listTransactions">
<property name="styleSheet">
<string notr="true">QListView { background: transparent; }</string>
</property>
@@ -517,9 +517,15 @@
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
+ <property name="uniformItemSizes">
+ <bool>true</bool>
+ </property>
</widget>
</item>
</layout>
@@ -544,6 +550,13 @@
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>TransactionOverviewWidget</class>
+ <extends>QListView</extends>
+ <header>qt/transactionoverviewwidget.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index cca4dce624..bc542a0833 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -12,6 +12,7 @@
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/transactionfilterproxy.h>
+#include <qt/transactionoverviewwidget.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
@@ -21,6 +22,9 @@
#include <QPainter>
#include <QStatusTipEvent>
+#include <algorithm>
+#include <map>
+
#define DECORATION_SIZE 54
#define NUM_ITEMS 5
@@ -34,7 +38,7 @@ public:
QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(_platformStyle)
{
-
+ connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged);
}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -67,13 +71,15 @@ public:
painter->setPen(foreground);
QRect boundingRect;
- painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect);
+ painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect);
+ int address_rect_min_width = boundingRect.width();
if (index.data(TransactionTableModel::WatchonlyRole).toBool())
{
QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
iconWatchonly.paint(painter, watchonlyRect);
+ address_rect_min_width += 5 + watchonlyRect.width();
}
if(amount < 0)
@@ -94,23 +100,42 @@ public:
{
amountText = QString("[") + amountText + QString("]");
}
- painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
+
+ QRect amount_bounding_rect;
+ painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText, &amount_bounding_rect);
painter->setPen(option.palette.color(QPalette::Text));
- painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
+ QRect date_bounding_rect;
+ painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date), &date_bounding_rect);
+
+ const int minimum_width = std::max(address_rect_min_width, amount_bounding_rect.width() + date_bounding_rect.width());
+ const auto search = m_minimum_width.find(index.row());
+ if (search == m_minimum_width.end() || search->second != minimum_width) {
+ m_minimum_width[index.row()] = minimum_width;
+ Q_EMIT width_changed(index);
+ }
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
- return QSize(DECORATION_SIZE, DECORATION_SIZE);
+ const auto search = m_minimum_width.find(index.row());
+ const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second;
+ return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE};
}
int unit;
- const PlatformStyle *platformStyle;
+Q_SIGNALS:
+ //! An intermediate signal for emitting from the `paint() const` member function.
+ void width_changed(const QModelIndex& index) const;
+
+private:
+ const PlatformStyle* platformStyle;
+ mutable std::map<int, int> m_minimum_width;
};
+
#include <qt/overviewpage.moc>
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
@@ -126,7 +151,6 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
// use a SingleColorIcon for the "out of sync warning" icon
QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
- icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
ui->labelTransactionsStatus->setIcon(icon);
ui->labelWalletStatus->setIcon(icon);
@@ -136,7 +160,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
- connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked);
+ connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked);
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 5796a6ef56..2292c01d6a 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -18,6 +18,8 @@
#include <util/system.h>
#include <util/translation.h>
+#include <functional>
+
#include <QApplication>
#include <QCloseEvent>
#include <QPainter>
diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h
new file mode 100644
index 0000000000..2bdead7bc4
--- /dev/null
+++ b/src/qt/transactionoverviewwidget.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
+#define BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
+
+#include <qt/transactiontablemodel.h>
+
+#include <QListView>
+#include <QSize>
+#include <QSizePolicy>
+
+QT_BEGIN_NAMESPACE
+class QShowEvent;
+class QWidget;
+QT_END_NAMESPACE
+
+class TransactionOverviewWidget : public QListView
+{
+ Q_OBJECT
+
+public:
+ explicit TransactionOverviewWidget(QWidget* parent = nullptr) : QListView(parent) {}
+
+ QSize sizeHint() const override
+ {
+ return {sizeHintForColumn(TransactionTableModel::ToAddress), QListView::sizeHint().height()};
+ }
+
+protected:
+ void showEvent(QShowEvent* event) override
+ {
+ Q_UNUSED(event);
+ QSizePolicy sp = sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Minimum);
+ setSizePolicy(sp);
+ }
+};
+
+#endif // BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 05b250eea9..e6d483364c 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -19,6 +19,7 @@
#include <uint256.h>
#include <algorithm>
+#include <functional>
#include <QColor>
#include <QDateTime>
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 2edb7eff8a..02b3c62867 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -106,9 +106,24 @@ void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
if (mapWalletViews.count(wallet_model) == 0) return;
+ // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget.
+ WalletView* view_about_to_hide = currentWalletView();
+ if (view_about_to_hide) {
+ QSizePolicy sp = view_about_to_hide->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Ignored);
+ view_about_to_hide->setSizePolicy(sp);
+ }
+
WalletView *walletView = mapWalletViews.value(wallet_model);
- walletStack->setCurrentWidget(walletView);
assert(walletView);
+
+ // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously.
+ QSizePolicy sp = walletView->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Preferred);
+ walletView->setSizePolicy(sp);
+ walletView->updateGeometry();
+
+ walletStack->setCurrentWidget(walletView);
walletView->updateEncryptionStatus();
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index cad472b43b..58427b42cc 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -29,6 +29,7 @@
#include <wallet/wallet.h> // for CRecipient
#include <stdint.h>
+#include <functional>
#include <QDebug>
#include <QMessageBox>
@@ -514,6 +515,13 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
questionString.append("</td><td>");
questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee));
questionString.append("</td></tr></table>");
+
+ // Display warning in the "Confirm fee bump" window if the "Coin Control Features" option is enabled
+ if (getOptionsModel()->getCoinControlFeatures()) {
+ questionString.append("<br><br>");
+ questionString.append(tr("Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy."));
+ }
+
SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
confirmationDialog.exec();
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 3f97f6f3d9..7a336c1ad6 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -2399,10 +2399,10 @@ static RPCHelpMan dumptxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- fs::path path = fs::absolute(request.params[0].get_str(), GetDataDir());
+ const fs::path path = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str());
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption.
- fs::path temppath = fs::absolute(request.params[0].get_str() + ".incomplete", GetDataDir());
+ const fs::path temppath = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str() + ".incomplete");
if (fs::exists(path)) {
throw JSONRPCError(
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index b3102a236d..215e48ca26 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -39,13 +39,14 @@ static RPCHelpMan validateaddress()
RPCResult{
RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
+ {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
{RPCResult::Type::STR, "address", "The bitcoin address validated"},
{RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address"},
{RPCResult::Type::BOOL, "isscript", "If the key is a script"},
{RPCResult::Type::BOOL, "iswitness", "If the address is a witness address"},
{RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
{RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
+ {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
}
},
RPCExamples{
@@ -54,13 +55,14 @@ static RPCHelpMan validateaddress()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
- bool isValid = IsValidDestination(dest);
+ std::string error_msg;
+ CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
+ const bool isValid = IsValidDestination(dest);
+ CHECK_NONFATAL(isValid == error_msg.empty());
UniValue ret(UniValue::VOBJ);
ret.pushKV("isvalid", isValid);
- if (isValid)
- {
+ if (isValid) {
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
@@ -69,7 +71,10 @@ static RPCHelpMan validateaddress()
UniValue detail = DescribeAddress(dest);
ret.pushKVs(detail);
+ } else {
+ ret.pushKV("error", error_msg);
}
+
return ret;
},
};
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 7c361bf26f..b3ee23f139 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -7,6 +7,7 @@
#include <random.h>
#include <assert.h>
+#include <functional>
#include <utility>
CScheduler::CScheduler()
diff --git a/src/sync.cpp b/src/sync.cpp
index acfbe8fe29..a2b62c2286 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -13,8 +13,6 @@
#include <util/strencodings.h>
#include <util/threadnames.h>
-#include <boost/thread/mutex.hpp>
-
#include <map>
#include <mutex>
#include <set>
@@ -224,7 +222,6 @@ template void EnterCritical(const char*, const char*, int, Mutex*, bool);
template void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool);
template void EnterCritical(const char*, const char*, int, std::mutex*, bool);
template void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool);
-template void EnterCritical(const char*, const char*, int, boost::mutex*, bool);
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)
{
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 5dbf07b420..76d6727044 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -148,10 +148,7 @@ typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;
static void Correct_Queue_range(std::vector<size_t> range)
{
auto small_queue = MakeUnique<Correct_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{small_queue->Thread();});
- }
+ small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
// Make vChecks here to save on malloc (this test can be slow...)
std::vector<FakeCheckCheckCompletion> vChecks;
for (const size_t i : range) {
@@ -168,8 +165,7 @@ static void Correct_Queue_range(std::vector<size_t> range)
BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);
}
}
- tg.interrupt_all();
- tg.join_all();
+ small_queue->StopWorkerThreads();
}
/** Test that 0 checks is correct
@@ -212,11 +208,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)
BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
{
auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE);
-
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{fail_queue->Thread();});
- }
+ fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (size_t i = 0; i < 1001; ++i) {
CCheckQueueControl<FailingCheck> control(fail_queue.get());
@@ -237,18 +229,14 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
BOOST_REQUIRE(success);
}
}
- tg.interrupt_all();
- tg.join_all();
+ fail_queue->StopWorkerThreads();
}
// Test that a block validation which fails does not interfere with
// future blocks, ie, the bad state is cleared.
BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
{
auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{fail_queue->Thread();});
- }
+ fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (auto times = 0; times < 10; ++times) {
for (const bool end_fails : {true, false}) {
@@ -263,8 +251,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
BOOST_REQUIRE(r != end_fails);
}
}
- tg.interrupt_all();
- tg.join_all();
+ fail_queue->StopWorkerThreads();
}
// Test that unique checks are actually all called individually, rather than
@@ -273,11 +260,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
{
auto queue = MakeUnique<Unique_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{queue->Thread();});
-
- }
+ queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
size_t COUNT = 100000;
size_t total = COUNT;
@@ -300,8 +283,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
}
BOOST_REQUIRE(r);
}
- tg.interrupt_all();
- tg.join_all();
+ queue->StopWorkerThreads();
}
@@ -313,10 +295,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
{
auto queue = MakeUnique<Memory_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{queue->Thread();});
- }
+ queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (size_t i = 0; i < 1000; ++i) {
size_t total = i;
{
@@ -335,8 +314,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
}
BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U);
}
- tg.interrupt_all();
- tg.join_all();
+ queue->StopWorkerThreads();
}
// Test that a new verification cannot occur until all checks
@@ -344,11 +322,8 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
{
auto queue = MakeUnique<FrozenCleanup_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
bool fails = false;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{queue->Thread();});
- }
+ queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
std::thread t0([&]() {
CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
std::vector<FrozenCleanupCheck> vChecks(1);
@@ -367,7 +342,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
}
// Try to get control of the queue a bunch of times
for (auto x = 0; x < 100 && !fails; ++x) {
- fails = queue->ControlMutex.try_lock();
+ fails = queue->m_control_mutex.try_lock();
}
{
// Unfreeze (we need lock n case of spurious wakeup)
@@ -378,9 +353,8 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
FrozenCleanupCheck::cv.notify_one();
// Wait for control to finish
t0.join();
- tg.interrupt_all();
- tg.join_all();
BOOST_REQUIRE(!fails);
+ queue->StopWorkerThreads();
}
@@ -431,7 +405,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
cv.wait(l, [&](){return has_lock;});
bool fails = false;
for (auto x = 0; x < 100 && !fails; ++x) {
- fails = queue->ControlMutex.try_lock();
+ fails = queue->m_control_mutex.try_lock();
}
has_tried = true;
cv.notify_one();
@@ -445,4 +419,3 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
}
}
BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index d02c3613ba..ec487aa3ff 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -52,6 +52,23 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
file >> input_buffer;
BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
}
+ {
+ // Join an absolute path and a relative path.
+ fs::path p = fsbridge::AbsPathJoin(tmpfolder, "fs_tests_₿_🏃");
+ BOOST_CHECK(p.is_absolute());
+ BOOST_CHECK_EQUAL(tmpfile1, p);
+ }
+ {
+ // Join two absolute paths.
+ fs::path p = fsbridge::AbsPathJoin(tmpfile1, tmpfile2);
+ BOOST_CHECK(p.is_absolute());
+ BOOST_CHECK_EQUAL(tmpfile2, p);
+ }
+ {
+ // Ensure joining with empty paths does not add trailing path components.
+ BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, ""));
+ BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, {}));
+ }
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index e703fa39c1..e0715f3e29 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -26,7 +26,7 @@ int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
void initialize_banman()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(banman, initialize_banman)
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 12ef4b203f..8ece94d771 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -36,9 +36,7 @@ bool operator==(const Coin& a, const Coin& b)
void initialize_coins_view()
{
- static const ECCVerifyHandle ecc_verify_handle;
- ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 7950213bd5..71b4b00116 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -17,7 +17,7 @@
void initialize_connman()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(connman, initialize_connman)
diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
index 1f122082b2..0e1c44cded 100644
--- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
+++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
@@ -45,18 +45,24 @@ FUZZ_TARGET(crypto_chacha20_poly1305_aead)
assert(ok);
},
[&] {
+ if (AdditionOverflow(seqnr_payload, static_cast<uint64_t>(1))) {
+ return;
+ }
seqnr_payload += 1;
aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
aad_pos = 0;
+ if (AdditionOverflow(seqnr_aad, static_cast<uint64_t>(1))) {
+ return;
+ }
seqnr_aad += 1;
}
},
[&] {
- seqnr_payload = fuzzed_data_provider.ConsumeIntegral<int>();
+ seqnr_payload = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
},
[&] {
- seqnr_aad = fuzzed_data_provider.ConsumeIntegral<int>();
+ seqnr_aad = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
},
[&] {
is_encrypt = fuzzed_data_provider.ConsumeBool();
diff --git a/src/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp
index 28fc528ceb..f3b6e6af04 100644
--- a/src/test/fuzz/data_stream.cpp
+++ b/src/test/fuzz/data_stream.cpp
@@ -13,7 +13,7 @@
void initialize_data_stream_addr_man()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
index c428a86631..207ee586bc 100644
--- a/src/test/fuzz/load_external_block_file.cpp
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -15,7 +15,7 @@
void initialize_load_external_block_file()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 31b99600ef..21dca4eb05 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -22,7 +22,7 @@
void initialize_net()
{
- static const BasicTestingSetup basic_testing_setup;
+ static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::MAIN);
}
FUZZ_TARGET_INIT(net, initialize_net)
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 0393491e4b..fff893fb3f 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -16,7 +16,7 @@
void initialize_policy_estimator()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 8fa52143d8..73242870a0 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -12,7 +12,7 @@
void initialize_policy_estimator_io()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 02beb6eb37..c4348495bf 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -43,7 +43,10 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
current_block.nHeight = current_height;
}
if (fuzzed_data_provider.ConsumeBool()) {
- current_block.nTime = fixed_time + current_height * consensus_params.nPowTargetSpacing;
+ const uint32_t seconds = current_height * consensus_params.nPowTargetSpacing;
+ if (!AdditionOverflow(fixed_time, seconds)) {
+ current_block.nTime = fixed_time + seconds;
+ }
}
if (fuzzed_data_provider.ConsumeBool()) {
current_block.nBits = fixed_bits;
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index e9aeef1d32..5d6a33d7c2 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -38,14 +38,8 @@ const TestingSetup* g_setup;
void initialize_process_message()
{
- static TestingSetup setup{
- CBaseChainParams::REGTEST,
- {
- "-nodebuglogfile",
- },
- };
- g_setup = &setup;
-
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index a54a3d5be1..d0d0e19694 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -17,18 +17,14 @@
#include <validation.h>
#include <validationinterface.h>
+namespace {
const TestingSetup* g_setup;
+} // namespace
void initialize_process_messages()
{
- static TestingSetup setup{
- CBaseChainParams::REGTEST,
- {
- "-nodebuglogfile",
- },
- };
- g_setup = &setup;
-
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index d883426c81..7fadf36f98 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -154,13 +154,13 @@ FUZZ_TARGET_INIT(script, initialize_script)
{
WitnessUnknown witness_unknown_1{};
- witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown_1.length = witness_unknown_program_1.size();
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown_1.program);
WitnessUnknown witness_unknown_2{};
- witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_2 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown_2.length = witness_unknown_program_2.size();
std::copy(witness_unknown_program_2.begin(), witness_unknown_program_2.end(), witness_unknown_2.program);
diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp
index 541322d484..83effec064 100644
--- a/src/test/fuzz/signet.cpp
+++ b/src/test/fuzz/signet.cpp
@@ -17,7 +17,7 @@
void initialize_signet()
{
- InitializeFuzzingContext(CBaseChainParams::SIGNET);
+ static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::SIGNET);
}
FUZZ_TARGET_INIT(signet, initialize_signet)
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index b7cf395e76..5b8eacf051 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -27,6 +27,7 @@
#include <txmempool.h>
#include <uint256.h>
#include <util/time.h>
+#include <util/vector.h>
#include <version.h>
#include <algorithm>
@@ -195,7 +196,7 @@ template <typename WeakEnumType, size_t size>
},
[&] {
WitnessUnknown witness_unknown{};
- witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown.length = witness_unknown_program_1.size();
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
@@ -338,9 +339,17 @@ inline void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, cons
}
}
-inline void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
+template <class T = const BasicTestingSetup>
+std::unique_ptr<T> MakeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {})
{
- static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
+ // Prepend default arguments for fuzzing
+ const std::vector<const char*> arguments = Cat(
+ {
+ "-nodebuglogfile",
+ },
+ extra_args);
+
+ return MakeUnique<T>(chain_name, arguments);
}
class FuzzedFileProvider
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 2e5a7549b7..21162356b8 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -9,6 +9,7 @@
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
+#include <functional>
#include <mutex>
BOOST_AUTO_TEST_SUITE(scheduler_tests)
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index 71275f69d9..3e4d1dac9e 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -6,7 +6,6 @@
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
-#include <boost/thread/mutex.hpp>
#include <mutex>
@@ -110,11 +109,6 @@ BOOST_AUTO_TEST_CASE(double_lock_mutex)
TestDoubleLock<Mutex>(true /* should throw */);
}
-BOOST_AUTO_TEST_CASE(double_lock_boost_mutex)
-{
- TestDoubleLock<boost::mutex>(true /* should throw */);
-}
-
BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
{
TestDoubleLock<RecursiveMutex>(false /* should not throw */);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 5b35ed6976..1eb30c68d6 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -24,6 +24,7 @@
#include <util/strencodings.h>
#include <validation.h>
+#include <functional>
#include <map>
#include <string>
@@ -428,12 +429,10 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
// check all inputs concurrently, with the cache
PrecomputedTransactionData txdata(tx);
- boost::thread_group threadGroup;
CCheckQueue<CScriptCheck> scriptcheckqueue(128);
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
- for (int i=0; i<20; i++)
- threadGroup.create_thread(std::bind(&CCheckQueue<CScriptCheck>::Thread, std::ref(scriptcheckqueue)));
+ scriptcheckqueue.StartWorkerThreads(20);
std::vector<Coin> coins;
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
@@ -455,9 +454,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
bool controlCheck = control.Wait();
assert(controlCheck);
-
- threadGroup.interrupt_all();
- threadGroup.join_all();
+ scriptcheckqueue.StopWorkerThreads();
}
SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutableTransaction& input2, const CTransactionRef tx)
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 738f414cd0..8a9694f55b 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -143,9 +143,7 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
// Start script-checking threads. Set g_parallel_script_checks to true so they are used.
constexpr int script_check_threads = 2;
- for (int i = 0; i < script_check_threads; ++i) {
- threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
- }
+ StartScriptCheckWorkerThreads(script_check_threads);
g_parallel_script_checks = true;
}
@@ -154,6 +152,7 @@ ChainTestingSetup::~ChainTestingSetup()
if (m_node.scheduler) m_node.scheduler->stop();
threadGroup.interrupt_all();
threadGroup.join_all();
+ StopScriptCheckWorkerThreads();
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler();
m_node.connman.reset();
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 90ee9422ba..908ad35e1b 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -15,10 +15,11 @@
#include <util/strencodings.h>
#include <util/system.h>
-#include <vector>
#include <deque>
+#include <functional>
#include <set>
#include <stdlib.h>
+#include <vector>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/split.hpp>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 9ae7b921b3..470e665844 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -618,6 +618,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (GetRand(m_check_ratio) >= 1) return;
+ AssertLockHeld(::cs_main);
LOCK(cs);
LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
diff --git a/src/txmempool.h b/src/txmempool.h
index 9a1aa9bc2b..0a9cd81ff5 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -602,7 +602,7 @@ public:
* all inputs are in the mapNextTx array). If sanity-checking is turned off,
* check does nothing.
*/
- void check(const CCoinsViewCache *pcoins) const;
+ void check(const CCoinsViewCache *pcoins) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
// addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 917d37ccc7..d1fb921642 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -398,7 +398,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
}
if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
- *filepath = fs::absolute(temp ? settings + ".tmp" : settings, GetDataDir(/* net_specific= */ true));
+ *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings);
}
return true;
}
@@ -1311,7 +1311,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
if (path.is_absolute()) {
return path;
}
- return fs::absolute(path, GetDataDir(net_specific));
+ return fsbridge::AbsPathJoin(GetDataDir(net_specific), path);
}
void ScheduleBatchPriority()
diff --git a/src/validation.cpp b/src/validation.cpp
index a22c75a686..eeb99f0f0a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1763,9 +1763,14 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationSt
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
-void ThreadScriptCheck(int worker_num) {
- util::ThreadRename(strprintf("scriptch.%i", worker_num));
- scriptcheckqueue.Thread();
+void StartScriptCheckWorkerThreads(int threads_num)
+{
+ scriptcheckqueue.StartWorkerThreads(threads_num);
+}
+
+void StopScriptCheckWorkerThreads()
+{
+ scriptcheckqueue.StopWorkerThreads();
}
VersionBitsCache versionbitscache GUARDED_BY(cs_main);
diff --git a/src/validation.h b/src/validation.h
index 1b4e40cd53..d3fbabe1a2 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -149,8 +149,10 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
bool LoadGenesisBlock(const CChainParams& chainparams);
/** Unload database information */
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman);
-/** Run an instance of the script checking thread */
-void ThreadScriptCheck(int worker_num);
+/** Run instances of script checking worker threads */
+void StartScriptCheckWorkerThreads(int threads_num);
+/** Stop all of the script checking worker threads */
+void StopScriptCheckWorkerThreads();
/**
* Return transaction from the block at block_index.
* If block_index is not provided, fall back to mempool.
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 6ed48593fb..c0d107bf39 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -723,6 +723,23 @@ bool BerkeleyBatch::TxnAbort()
return (ret == 0);
}
+bool BerkeleyDatabaseSanityCheck()
+{
+ int major, minor;
+ DbEnv::version(&major, &minor, nullptr);
+
+ /* If the major version differs, or the minor version of library is *older*
+ * than the header that was compiled against, flag an error.
+ */
+ if (major != DB_VERSION_MAJOR || minor < DB_VERSION_MINOR) {
+ LogPrintf("BerkeleyDB database version conflict: header version is %d.%d, library version is %d.%d\n",
+ DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor);
+ return false;
+ }
+
+ return true;
+}
+
std::string BerkeleyDatabaseVersion()
{
return DbEnv::version(nullptr, nullptr, nullptr);
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index bf1617d67f..a8209587d7 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -223,6 +223,10 @@ public:
std::string BerkeleyDatabaseVersion();
+/** Perform sanity check of runtime BDB version versus linked BDB version.
+ */
+bool BerkeleyDatabaseSanityCheck();
+
//! Return object giving access to Berkeley database at specified path.
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 085dde1026..0d2be64dfb 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -86,6 +86,11 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
bool WalletInit::ParameterInteraction() const
{
+#ifdef USE_BDB
+ if (!BerkeleyDatabaseSanityCheck()) {
+ return InitError(Untranslated("A version conflict was detected between the run-time BerkeleyDB library and the one used during compilation."));
+ }
+#endif
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet);
diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h
index 5cdd7dff80..38ed7e7770 100644
--- a/src/wallet/ismine.h
+++ b/src/wallet/ismine.h
@@ -14,7 +14,27 @@
class CWallet;
class CScript;
-/** IsMine() return codes */
+/**
+ * IsMine() return codes, which depend on ScriptPubKeyMan implementation.
+ * Not every ScriptPubKeyMan covers all types, please refer to
+ * https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.21.0.md#ismine-semantics
+ * for better understanding.
+ *
+ * For LegacyScriptPubKeyMan,
+ * ISMINE_NO: the scriptPubKey is not in the wallet;
+ * ISMINE_WATCH_ONLY: the scriptPubKey has been imported into the wallet;
+ * ISMINE_SPENDABLE: the scriptPubKey corresponds to an address owned by the wallet user (can spend with the private key);
+ * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user;
+ * ISMINE_ALL: all ISMINE flags except for USED;
+ * ISMINE_ALL_USED: all ISMINE flags including USED;
+ * ISMINE_ENUM_ELEMENTS: the number of isminetype enum elements.
+ *
+ * For DescriptorScriptPubKeyMan and future ScriptPubKeyMan,
+ * ISMINE_NO: the scriptPubKey is not in the wallet;
+ * ISMINE_SPENDABLE: the scriptPubKey matches a scriptPubKey in the wallet.
+ * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user.
+ *
+ */
enum isminetype : unsigned int
{
ISMINE_NO = 0,
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 036fd4956f..30832f983b 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -62,7 +62,7 @@ bool VerifyWallets(interfaces::Chain& chain)
std::set<fs::path> wallet_paths;
for (const auto& wallet_file : gArgs.GetArgs("-wallet")) {
- const fs::path path = fs::absolute(wallet_file, GetWalletDir());
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_file);
if (!wallet_paths.insert(path).second) {
chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index e3631d5c6b..ec51ba0453 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3460,10 +3460,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
CWallet* const pwallet = wallet.get();
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
- if (!pwallet->chain().rpcEnableDeprecated("bumpfee")) {
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "Using bumpfee with wallets that have private keys disabled is deprecated. Use psbtbumpfee instead or restart bitcoind with -deprecatedrpc=bumpfee. This functionality will be removed in 0.22");
- }
- want_psbt = true;
+ throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
}
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
@@ -3834,13 +3831,19 @@ RPCHelpMan getaddressinfo()
LOCK(pwallet->cs_wallet);
- UniValue ret(UniValue::VOBJ);
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ std::string error_msg;
+ CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
+
// Make sure the destination is valid
if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ // Set generic error message in case 'DecodeDestination' didn't set it
+ if (error_msg.empty()) error_msg = "Invalid address";
+
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error_msg);
}
+ UniValue ret(UniValue::VOBJ);
+
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index aa7f1c83d8..f035a70a20 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <fs.h>
+#include <univalue.h>
#include <util/check.h>
#include <util/system.h>
@@ -37,6 +38,9 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
{
+ gArgs.LockSettings([&](util::Settings& settings) {
+ settings.forced_settings.erase("walletdir");
+ });
fs::current_path(m_cwd);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 918946f9e7..723552860a 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3780,7 +3780,7 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
// 2. Path to an existing directory.
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
- const fs::path& wallet_path = fs::absolute(name, GetWalletDir());
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), name);
fs::file_type path_type = fs::symlink_status(wallet_path).type();
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index a1bb7343f4..bc90491a2c 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -105,7 +105,7 @@ static void WalletShowInfo(CWallet* wallet_instance)
bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command, const std::string& name)
{
- fs::path path = fs::absolute(name, GetWalletDir());
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), name);
if (args.IsArgSet("-format") && command != "createfromdump") {
tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n");
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index c0207f9dd6..168ba841c8 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -17,6 +17,7 @@
#include <cstdarg>
#include <cstddef>
#include <map>
+#include <optional>
#include <string>
#include <utility>
@@ -227,50 +228,43 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr
return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
}
+// Helper function to send a 'sequence' topic message with the following structure:
+// <32-byte hash> | <1-byte label> | <8-byte LE sequence> (optional)
+static bool SendSequenceMsg(CZMQAbstractPublishNotifier& notifier, uint256 hash, char label, std::optional<uint64_t> sequence = {})
+{
+ unsigned char data[sizeof(hash) + sizeof(label) + sizeof(uint64_t)];
+ for (unsigned int i = 0; i < sizeof(hash); ++i) {
+ data[sizeof(hash) - 1 - i] = hash.begin()[i];
+ }
+ data[sizeof(hash)] = label;
+ if (sequence) WriteLE64(data + sizeof(hash) + sizeof(label), *sequence);
+ return notifier.SendZmqMessage(MSG_SEQUENCE, data, sequence ? sizeof(data) : sizeof(hash) + sizeof(label));
+}
-// TODO: Dedup this code to take label char, log string
bool CZMQPublishSequenceNotifier::NotifyBlockConnect(const CBlockIndex *pindex)
{
uint256 hash = pindex->GetBlockHash();
LogPrint(BCLog::ZMQ, "zmq: Publish sequence block connect %s to %s\n", hash.GetHex(), this->address);
- char data[sizeof(uint256)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(data) - 1] = 'C'; // Block (C)onnect
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Block (C)onnect */ 'C');
}
bool CZMQPublishSequenceNotifier::NotifyBlockDisconnect(const CBlockIndex *pindex)
{
uint256 hash = pindex->GetBlockHash();
LogPrint(BCLog::ZMQ, "zmq: Publish sequence block disconnect %s to %s\n", hash.GetHex(), this->address);
- char data[sizeof(uint256)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(data) - 1] = 'D'; // Block (D)isconnect
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Block (D)isconnect */ 'D');
}
bool CZMQPublishSequenceNotifier::NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence)
{
uint256 hash = transaction.GetHash();
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address);
- unsigned char data[sizeof(uint256)+sizeof(mempool_sequence)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(uint256)] = 'A'; // Mempool (A)cceptance
- WriteLE64(data+sizeof(uint256)+1, mempool_sequence);
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence);
}
bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence)
{
uint256 hash = transaction.GetHash();
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address);
- unsigned char data[sizeof(uint256)+sizeof(mempool_sequence)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(uint256)] = 'R'; // Mempool (R)emoval
- WriteLE64(data+sizeof(uint256)+1, mempool_sequence);
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence);
}
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 3e28dae4b3..2445b6d977 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -7,6 +7,7 @@
import os
from test_framework.test_framework import BitcoinTestFramework
+from test_framework import util
class ConfArgsTest(BitcoinTestFramework):
@@ -42,10 +43,11 @@ class ConfArgsTest(BitcoinTestFramework):
conf.write("wallet=foo\n")
self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Config setting for -wallet only applied on %s network when in [%s] section.' % (self.chain, self.chain))
+ main_conf_file_path = os.path.join(self.options.tmpdir, 'node0', 'bitcoin_main.conf')
+ util.write_config(main_conf_file_path, n=0, chain='', extra_config='includeconf={}\n'.format(inc_conf_file_path))
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
- conf.write('regtest=0\n') # mainnet
conf.write('acceptnonstdtxn=1\n')
- self.nodes[0].assert_start_raises_init_error(expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
+ self.nodes[0].assert_start_raises_init_error(extra_args=["-conf={}".format(main_conf_file_path)], expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('nono\n')
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 9b2414cf2d..946bfa51d4 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -80,34 +80,43 @@ class ZMQTest (BitcoinTestFramework):
self.log.debug("Destroying ZMQ context")
self.ctx.destroy(linger=None)
+ # Restart node with the specified zmq notifications enabled, subscribe to
+ # all of them and return the corresponding ZMQSubscriber objects.
+ def setup_zmq_test(self, services, recv_timeout=60, connect_nodes=False):
+ subscribers = []
+ for topic, address in services:
+ socket = self.ctx.socket(zmq.SUB)
+ socket.set(zmq.RCVTIMEO, recv_timeout*1000)
+ subscribers.append(ZMQSubscriber(socket, topic.encode()))
+
+ self.restart_node(0, ["-zmqpub%s=%s" % (topic, address) for topic, address in services])
+
+ if connect_nodes:
+ self.connect_nodes(0, 1)
+
+ for i, sub in enumerate(subscribers):
+ sub.socket.connect(services[i][1])
+
+ # Relax so that the subscribers are ready before publishing zmq messages
+ sleep(0.2)
+
+ return subscribers
+
def test_basic(self):
# Invalid zmq arguments don't take down the node, see #17185.
self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"])
address = 'tcp://127.0.0.1:28332'
- sockets = []
- subs = []
- services = [b"hashblock", b"hashtx", b"rawblock", b"rawtx"]
- for service in services:
- sockets.append(self.ctx.socket(zmq.SUB))
- sockets[-1].set(zmq.RCVTIMEO, 60000)
- subs.append(ZMQSubscriber(sockets[-1], service))
-
- # Subscribe to all available topics.
+ subs = self.setup_zmq_test(
+ [(topic, address) for topic in ["hashblock", "hashtx", "rawblock", "rawtx"]],
+ connect_nodes=True)
+
hashblock = subs[0]
hashtx = subs[1]
rawblock = subs[2]
rawtx = subs[3]
- self.restart_node(0, ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [hashblock, hashtx, rawblock, rawtx]])
- self.connect_nodes(0, 1)
- for socket in sockets:
- socket.connect(address)
-
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
-
num_blocks = 5
self.log.info("Generate %(n)d blocks (and %(n)d coinbase txes)" % {"n": num_blocks})
genhashes = self.nodes[0].generatetoaddress(num_blocks, ADDRESS_BCRT1_UNSPENDABLE)
@@ -174,25 +183,10 @@ class ZMQTest (BitcoinTestFramework):
address = 'tcp://127.0.0.1:28333'
- services = [b"hashblock", b"hashtx"]
- sockets = []
- subs = []
- for service in services:
- sockets.append(self.ctx.socket(zmq.SUB))
- # 2 second timeout to check end of notifications
- sockets[-1].set(zmq.RCVTIMEO, 2000)
- subs.append(ZMQSubscriber(sockets[-1], service))
-
- # Subscribe to all available topics.
- hashblock = subs[0]
- hashtx = subs[1]
-
# Should only notify the tip if a reorg occurs
- self.restart_node(0, ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [hashblock, hashtx]])
- for socket in sockets:
- socket.connect(address)
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ hashblock, hashtx = self.setup_zmq_test(
+ [(topic, address) for topic in ["hashblock", "hashtx"]],
+ recv_timeout=2) # 2 second timeout to check end of notifications
# Generate 1 block in nodes[0] with 1 mempool tx and receive all notifications
payment_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
@@ -240,15 +234,7 @@ class ZMQTest (BitcoinTestFramework):
<32-byte hash>A<8-byte LE uint> : Transactionhash added mempool
"""
self.log.info("Testing 'sequence' publisher")
- address = 'tcp://127.0.0.1:28333'
- socket = self.ctx.socket(zmq.SUB)
- socket.set(zmq.RCVTIMEO, 60000)
- seq = ZMQSubscriber(socket, b'sequence')
-
- self.restart_node(0, ['-zmqpub%s=%s' % (seq.topic.decode(), address)])
- socket.connect(address)
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")])
# Mempool sequence number starts at 1
seq_num = 1
@@ -399,16 +385,7 @@ class ZMQTest (BitcoinTestFramework):
return
self.log.info("Testing 'mempool sync' usage of sequence notifier")
- address = 'tcp://127.0.0.1:28333'
- socket = self.ctx.socket(zmq.SUB)
- socket.set(zmq.RCVTIMEO, 60000)
- seq = ZMQSubscriber(socket, b'sequence')
-
- self.restart_node(0, ['-zmqpub%s=%s' % (seq.topic.decode(), address)])
- self.connect_nodes(0, 1)
- socket.connect(address)
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")], connect_nodes=True)
# In-memory counter, should always start at 1
next_mempool_seq = self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"]
@@ -508,26 +485,17 @@ class ZMQTest (BitcoinTestFramework):
def test_multiple_interfaces(self):
# Set up two subscribers with different addresses
- subscribers = []
- for i in range(2):
- address = 'tcp://127.0.0.1:%d' % (28334 + i)
- socket = self.ctx.socket(zmq.SUB)
- socket.set(zmq.RCVTIMEO, 60000)
- hashblock = ZMQSubscriber(socket, b"hashblock")
- socket.connect(address)
- subscribers.append({'address': address, 'hashblock': hashblock})
-
- self.restart_node(0, ['-zmqpub%s=%s' % (subscriber['hashblock'].topic.decode(), subscriber['address']) for subscriber in subscribers])
-
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ subscribers = self.setup_zmq_test([
+ ("hashblock", "tcp://127.0.0.1:28334"),
+ ("hashblock", "tcp://127.0.0.1:28335"),
+ ])
# Generate 1 block in nodes[0] and receive all notifications
self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)
# Should receive the same block hash on both subscribers
- assert_equal(self.nodes[0].getbestblockhash(), subscribers[0]['hashblock'].receive().hex())
- assert_equal(self.nodes[0].getbestblockhash(), subscribers[1]['hashblock'].receive().hex())
+ assert_equal(self.nodes[0].getbestblockhash(), subscribers[0].receive().hex())
+ assert_equal(self.nodes[0].getbestblockhash(), subscribers[1].receive().hex())
if __name__ == '__main__':
ZMQTest().main()
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index 209d1182d7..1af79b9f7c 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test deprecation of RPC calls."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_raises_rpc_error, find_vout_for_address
class DeprecatedRpcTest(BitcoinTestFramework):
def set_test_params(self):
@@ -24,37 +23,7 @@ class DeprecatedRpcTest(BitcoinTestFramework):
# assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].rpc.generate, 1)
# self.nodes[1].generate(1)
- if self.is_wallet_compiled():
- self.log.info("Test bumpfee RPC")
- self.nodes[0].generate(101)
- self.nodes[0].createwallet(wallet_name='nopriv', disable_private_keys=True)
- noprivs0 = self.nodes[0].get_wallet_rpc('nopriv')
- w0 = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
- self.nodes[1].createwallet(wallet_name='nopriv', disable_private_keys=True)
- noprivs1 = self.nodes[1].get_wallet_rpc('nopriv')
-
- address = w0.getnewaddress()
- desc = w0.getaddressinfo(address)['desc']
- change_addr = w0.getrawchangeaddress()
- change_desc = w0.getaddressinfo(change_addr)['desc']
- txid = w0.sendtoaddress(address=address, amount=10)
- vout = find_vout_for_address(w0, txid, address)
- self.nodes[0].generate(1)
- rawtx = w0.createrawtransaction([{'txid': txid, 'vout': vout}], {w0.getnewaddress(): 5}, 0, True)
- rawtx = w0.fundrawtransaction(rawtx, {'changeAddress': change_addr})
- signed_tx = w0.signrawtransactionwithwallet(rawtx['hex'])['hex']
-
- noprivs0.importmulti([{'desc': desc, 'timestamp': 0}, {'desc': change_desc, 'timestamp': 0, 'internal': True}])
- noprivs1.importmulti([{'desc': desc, 'timestamp': 0}, {'desc': change_desc, 'timestamp': 0, 'internal': True}])
-
- txid = w0.sendrawtransaction(signed_tx)
- self.sync_all()
-
- assert_raises_rpc_error(-32, 'Using bumpfee with wallets that have private keys disabled is deprecated. Use psbtbumpfee instead or restart bitcoind with -deprecatedrpc=bumpfee. This functionality will be removed in 0.22', noprivs0.bumpfee, txid)
- bumped_psbt = noprivs1.bumpfee(txid)
- assert 'psbt' in bumped_psbt
- else:
- self.log.info("No tested deprecated RPC methods")
+ self.log.info("No tested deprecated RPC methods")
if __name__ == '__main__':
DeprecatedRpcTest().main()
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
new file mode 100755
index 0000000000..469d6bdb05
--- /dev/null
+++ b/test/functional/rpc_invalid_address_message.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test error messages for 'getaddressinfo' and 'validateaddress' RPC commands."""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+BECH32_VALID = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
+BECH32_INVALID_SIZE = 'bcrt1sqqpl9r5c'
+BECH32_INVALID_PREFIX = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
+
+BASE58_VALID = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn'
+BASE58_INVALID_PREFIX = '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem'
+
+INVALID_ADDRESS = 'asfah14i8fajz0123f'
+
+class InvalidAddressErrorMessageTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def test_validateaddress(self):
+ node = self.nodes[0]
+
+ # Bech32
+ info = node.validateaddress(BECH32_INVALID_SIZE)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid Bech32 address data size')
+
+ info = node.validateaddress(BECH32_INVALID_PREFIX)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid prefix for Bech32 address')
+
+ info = node.validateaddress(BECH32_VALID)
+ assert info['isvalid']
+ assert 'error' not in info
+
+ # Base58
+ info = node.validateaddress(BASE58_INVALID_PREFIX)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid prefix for Base58-encoded address')
+
+ info = node.validateaddress(BASE58_VALID)
+ assert info['isvalid']
+ assert 'error' not in info
+
+ # Invalid address format
+ info = node.validateaddress(INVALID_ADDRESS)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid address format')
+
+ def test_getaddressinfo(self):
+ node = self.nodes[0]
+
+ assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
+
+ assert_raises_rpc_error(-5, "Invalid prefix for Bech32 address", node.getaddressinfo, BECH32_INVALID_PREFIX)
+
+ assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX)
+
+ assert_raises_rpc_error(-5, "Invalid address format", node.getaddressinfo, INVALID_ADDRESS)
+
+ def run_test(self):
+ self.test_validateaddress()
+ self.test_getaddressinfo()
+
+
+if __name__ == '__main__':
+ InvalidAddressErrorMessageTest().main()
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index b3eb2d61a7..123c48852c 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -342,16 +342,25 @@ def initialize_datadir(dirname, n, chain):
datadir = get_datadir_path(dirname, n)
if not os.path.isdir(datadir):
os.makedirs(datadir)
- # Translate chain name to config name
+ write_config(os.path.join(datadir, "bitcoin.conf"), n=n, chain=chain)
+ os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
+ os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
+ return datadir
+
+
+def write_config(config_path, *, n, chain, extra_config=""):
+ # Translate chain subdirectory name to config name
if chain == 'testnet3':
chain_name_conf_arg = 'testnet'
chain_name_conf_section = 'test'
else:
chain_name_conf_arg = chain
chain_name_conf_section = chain
- with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
- f.write("{}=1\n".format(chain_name_conf_arg))
- f.write("[{}]\n".format(chain_name_conf_section))
+ with open(config_path, 'w', encoding='utf8') as f:
+ if chain_name_conf_arg:
+ f.write("{}=1\n".format(chain_name_conf_arg))
+ if chain_name_conf_section:
+ f.write("[{}]\n".format(chain_name_conf_section))
f.write("port=" + str(p2p_port(n)) + "\n")
f.write("rpcport=" + str(rpc_port(n)) + "\n")
f.write("fallbackfee=0.0002\n")
@@ -364,9 +373,7 @@ def initialize_datadir(dirname, n, chain):
f.write("upnp=0\n")
f.write("natpmp=0\n")
f.write("shrinkdebugfile=0\n")
- os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
- os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
- return datadir
+ f.write(extra_config)
def get_datadir_path(dirname, n):
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 9bbf862568..898d4bfe17 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -134,6 +134,7 @@ BASE_SCRIPTS = [
'wallet_keypool_topup.py --descriptors',
'feature_fee_estimation.py',
'interface_zmq.py',
+ 'rpc_invalid_address_message.py',
'interface_bitcoin_cli.py',
'mempool_resurrect.py',
'wallet_txn_doublespend.py --mineblock',
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 6bcb03e8ed..4a589f0393 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -586,7 +586,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
- assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
+ assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index c8c1f2e374..5fc8438e8f 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -425,6 +425,9 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
original_txid = watcher.sendrawtransaction(psbt_final["hex"])
assert_equal(len(watcher.decodepsbt(psbt)["tx"]["vin"]), 1)
+ # bumpfee can't be used on watchonly wallets
+ assert_raises_rpc_error(-4, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.", watcher.bumpfee, original_txid)
+
# Bump fee, obnoxiously high to add additional watchonly input
bumped_psbt = watcher.psbtbumpfee(original_txid, {"fee_rate": HIGH})
assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1)
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 3c743603bb..ab766b4a45 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -14,6 +14,14 @@ import subprocess
import sys
+def get_fuzz_env(*, target):
+ return {
+ 'FUZZ': target,
+ 'ASAN_OPTIONS': # symbolizer disabled due to https://github.com/google/sanitizers/issues/1364#issuecomment-761072085
+ 'symbolize=0:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1',
+ }
+
+
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -129,9 +137,7 @@ def main():
os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz'),
'-help=1',
],
- env={
- 'FUZZ': test_list_selection[0]
- },
+ env=get_fuzz_env(target=test_list_selection[0]),
timeout=20,
check=True,
stderr=subprocess.PIPE,
@@ -186,9 +192,7 @@ def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets):
' '.join(command),
subprocess.run(
command,
- env={
- 'FUZZ': t
- },
+ env=get_fuzz_env(target=t),
check=True,
stderr=subprocess.PIPE,
universal_newlines=True,
@@ -227,9 +231,7 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir):
output = 'Run {} with args {}\n'.format(t, " ".join(args))
output += subprocess.run(
args,
- env={
- 'FUZZ': t
- },
+ env=get_fuzz_env(target=t),
check=True,
stderr=subprocess.PIPE,
universal_newlines=True,
@@ -257,7 +259,12 @@ def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind):
def job(t, args):
output = 'Run {} with args {}'.format(t, args)
- result = subprocess.run(args, env={'FUZZ': t}, stderr=subprocess.PIPE, universal_newlines=True)
+ result = subprocess.run(
+ args,
+ env=get_fuzz_env(target=t),
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
output += result.stderr
return output, result
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index dc032665e4..262e9d4c79 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -68,7 +68,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/signals2/signal.hpp
boost/test/unit_test.hpp
boost/thread/condition_variable.hpp
- boost/thread/mutex.hpp
boost/thread/shared_mutex.hpp
boost/thread/thread.hpp
)
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index c800fd20db..37fcf7804a 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -33,7 +33,7 @@ if [ -z "${COMMIT_RANGE}" ]; then
fi
showdiff() {
- if ! git diff -U0 "${COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then
+ if ! git diff -U0 "${COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)contrib/guix/patches/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then
echo "Failed to get a diff"
exit 1
fi
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 9a52cd4b57..18f1de0926 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -1,3 +1,7 @@
+# -fsanitize=undefined suppressions
+# =================================
+# No suppressions at the moment. Hooray!
+
# -fsanitize=integer suppressions
# ===============================
# Unsigned integer overflow occurs when the result of an unsigned integer
@@ -6,7 +10,8 @@
# contains files in which we expect unsigned integer overflows to occur. The
# list is used to suppress -fsanitize=integer warnings when running our CI UBSan
# job.
-unsigned-integer-overflow:*/include/c++/*/bits/basic_string.tcc
+unsigned-integer-overflow:*/include/c++/
+unsigned-integer-overflow:addrman.cpp
unsigned-integer-overflow:arith_uint256.h
unsigned-integer-overflow:basic_string.h
unsigned-integer-overflow:bench/bench.h
@@ -15,34 +20,41 @@ unsigned-integer-overflow:bloom.cpp
unsigned-integer-overflow:chain.cpp
unsigned-integer-overflow:chain.h
unsigned-integer-overflow:coded_stream.h
+unsigned-integer-overflow:coins.cpp
+unsigned-integer-overflow:compressor.cpp
unsigned-integer-overflow:core_write.cpp
-unsigned-integer-overflow:crypto/*
+unsigned-integer-overflow:crypto/
+# unsigned-integer-overflow in FuzzedDataProvider's ConsumeIntegralInRange
+unsigned-integer-overflow:FuzzedDataProvider.h
unsigned-integer-overflow:hash.cpp
-unsigned-integer-overflow:leveldb/db/log_reader.cc
-unsigned-integer-overflow:leveldb/util/bloom.cc
-unsigned-integer-overflow:leveldb/util/crc32c.h
-unsigned-integer-overflow:leveldb/util/hash.cc
+unsigned-integer-overflow:leveldb/
unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
+unsigned-integer-overflow:pubkey.h
unsigned-integer-overflow:script/interpreter.cpp
unsigned-integer-overflow:stl_bvector.h
unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:util/strencodings.cpp
unsigned-integer-overflow:validation.cpp
-
-implicit-integer-sign-change:*/include/c++/*/bits/*.h
+implicit-integer-sign-change:*/include/boost/
+implicit-integer-sign-change:*/include/c++/
implicit-integer-sign-change:*/new_allocator.h
-implicit-integer-sign-change:/usr/include/boost/date_time/format_date_parser.hpp
+implicit-integer-sign-change:addrman.h
implicit-integer-sign-change:arith_uint256.cpp
implicit-integer-sign-change:bech32.cpp
implicit-integer-sign-change:bloom.cpp
-implicit-integer-sign-change:chain.*
+implicit-integer-sign-change:chain.cpp
+implicit-integer-sign-change:chain.h
implicit-integer-sign-change:coins.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h
-implicit-integer-sign-change:crypto/*
+implicit-integer-sign-change:crc32c/
+implicit-integer-sign-change:crypto/
+# implicit-integer-sign-change in FuzzedDataProvider's ConsumeIntegralInRange
+implicit-integer-sign-change:FuzzedDataProvider.h
implicit-integer-sign-change:key.cpp
implicit-integer-sign-change:noui.cpp
+implicit-integer-sign-change:policy/fees.cpp
implicit-integer-sign-change:prevector.h
implicit-integer-sign-change:protocol.cpp
implicit-integer-sign-change:script/bitcoinconsensus.cpp
@@ -53,24 +65,37 @@ implicit-integer-sign-change:test/coins_tests.cpp
implicit-integer-sign-change:test/pow_tests.cpp
implicit-integer-sign-change:test/prevector_tests.cpp
implicit-integer-sign-change:test/sighash_tests.cpp
+implicit-integer-sign-change:test/skiplist_tests.cpp
implicit-integer-sign-change:test/streams_tests.cpp
implicit-integer-sign-change:test/transaction_tests.cpp
implicit-integer-sign-change:txmempool.cpp
-implicit-integer-sign-change:util/strencodings.*
+implicit-integer-sign-change:util/strencodings.cpp
+implicit-integer-sign-change:util/strencodings.h
implicit-integer-sign-change:validation.cpp
implicit-integer-sign-change:zmq/zmqpublishnotifier.cpp
implicit-signed-integer-truncation,implicit-integer-sign-change:chain.h
implicit-signed-integer-truncation,implicit-integer-sign-change:test/skiplist_tests.cpp
+implicit-signed-integer-truncation:addrman.cpp
+implicit-signed-integer-truncation:addrman.h
implicit-signed-integer-truncation:chain.h
-implicit-signed-integer-truncation:crypto/*
+implicit-signed-integer-truncation:crypto/
implicit-signed-integer-truncation:cuckoocache.h
-implicit-signed-integer-truncation:leveldb/*
+implicit-signed-integer-truncation:leveldb/
+implicit-signed-integer-truncation:net.cpp
+implicit-signed-integer-truncation:net_processing.cpp
implicit-signed-integer-truncation:streams.h
implicit-signed-integer-truncation:test/arith_uint256_tests.cpp
implicit-signed-integer-truncation:test/skiplist_tests.cpp
implicit-signed-integer-truncation:torcontrol.cpp
-implicit-unsigned-integer-truncation:crypto/*
-implicit-unsigned-integer-truncation:leveldb/*
+implicit-unsigned-integer-truncation:crypto/
+implicit-unsigned-integer-truncation:leveldb/
# std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9
implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage
-implicit-integer-sign-change:crc32c/*
+shift-base:*/include/c++/
+shift-base:arith_uint256.cpp
+shift-base:crypto/
+shift-base:hash.cpp
+shift-base:leveldb/
+shift-base:net_processing.cpp
+shift-base:streams.h
+shift-base:util/bip32.cpp