aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_msan.sh2
-rwxr-xr-xci/test/00_setup_env_native_msan.sh2
-rwxr-xr-xci/test/00_setup_env_win64.sh2
-rw-r--r--configure.ac55
-rwxr-xr-xcontrib/guix/guix-build2
-rw-r--r--contrib/guix/manifest.scm6
-rw-r--r--contrib/tracing/README.md31
-rwxr-xr-xcontrib/tracing/log_utxocache_flush.py21
-rwxr-xr-xcontrib/tracing/log_utxos.bt2
-rw-r--r--depends/Makefile2
-rw-r--r--depends/builders/netbsd.mk2
-rw-r--r--depends/hosts/freebsd.mk10
-rw-r--r--depends/hosts/netbsd.mk31
-rw-r--r--depends/packages/bdb.mk1
-rw-r--r--depends/packages/libevent.mk1
-rw-r--r--depends/packages/libmultiprocess.mk2
-rw-r--r--depends/packages/native_clang.mk7
-rw-r--r--depends/packages/sqlite.mk1
-rw-r--r--depends/packages/zeromq.mk1
-rw-r--r--doc/managing-wallets.md6
-rw-r--r--doc/release-process.md2
-rw-r--r--doc/tracing.md33
-rw-r--r--src/Makefile.am26
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/bitcoin-cli.cpp20
-rw-r--r--src/bitcoin-wallet.cpp2
-rw-r--r--src/crypto/sha256.cpp74
-rw-r--r--src/crypto/sha256_arm_shani.cpp899
-rw-r--r--src/crypto/sha256_x86_shani.cpp (renamed from src/crypto/sha256_shani.cpp)6
-rw-r--r--src/fs.h22
-rw-r--r--src/index/base.cpp5
-rw-r--r--src/index/base.h4
-rw-r--r--src/index/coinstatsindex.cpp10
-rw-r--r--src/init.cpp2
-rw-r--r--src/node/blockstorage.cpp2
-rw-r--r--src/primitives/transaction.h2
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/bitcoin.cpp6
-rw-r--r--src/qt/bitcoingui.cpp126
-rw-r--r--src/qt/bitcoingui.h10
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/transactionview.cpp4
-rw-r--r--src/qt/walletframe.cpp2
-rw-r--r--src/qt/walletview.cpp12
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/mining.cpp36
-rw-r--r--src/script/descriptor.cpp12
-rw-r--r--src/streams.h101
-rw-r--r--src/test/dbwrapper_tests.cpp4
-rw-r--r--src/test/descriptor_tests.cpp75
-rw-r--r--src/test/fs_tests.cpp60
-rw-r--r--src/test/fuzz/script.cpp8
-rw-r--r--src/test/fuzz/script_format.cpp30
-rw-r--r--src/util/overflow.h1
-rw-r--r--src/util/syscall_sandbox.cpp7
-rw-r--r--src/util/system.cpp11
-rw-r--r--src/validation.cpp75
-rw-r--r--src/validation.h16
-rw-r--r--src/wallet/test/wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp3
-rwxr-xr-xtest/functional/feature_dirsymlinks.py39
-rwxr-xr-xtest/functional/feature_init.py6
-rwxr-xr-xtest/functional/rpc_help.py2
-rw-r--r--test/functional/test_framework/address.py12
-rw-r--r--test/functional/test_framework/netutil.py1
-rwxr-xr-xtest/functional/test_runner.py1
-rw-r--r--test/sanitizer_suppressions/tsan4
70 files changed, 1643 insertions, 334 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 5624c97d56..31bdb66e98 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -176,10 +176,10 @@ task:
QEMU_USER_CMD: "" # Disable qemu and run the test natively
task:
- name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [focal]'
+ name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [jammy]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:focal
+ image: ubuntu:jammy
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_win64.sh"
diff --git a/ci/test/00_setup_env_native_fuzz_with_msan.sh b/ci/test/00_setup_env_native_fuzz_with_msan.sh
index 07332690e8..619acc4677 100755
--- a/ci/test/00_setup_env_native_fuzz_with_msan.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_msan.sh
@@ -14,7 +14,7 @@ export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
export CONTAINER_NAME="ci_native_msan"
export PACKAGES="clang-9 llvm-9 cmake"
-export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' boost_cxxflags='-std=c++17 -fvisibility=hidden -fPIC ${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'"
+export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --with-asm=no --prefix=${DEPENDS_DIR}/x86_64-pc-linux-gnu/ CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export USE_MEMORY_SANITIZER="true"
diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh
index 557e9b1419..b8418106c6 100755
--- a/ci/test/00_setup_env_native_msan.sh
+++ b/ci/test/00_setup_env_native_msan.sh
@@ -15,7 +15,7 @@ export BDB_PREFIX="${BASE_ROOT_DIR}/db4"
export CONTAINER_NAME="ci_native_msan"
export PACKAGES="clang-9 llvm-9 cmake"
-export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' boost_cxxflags='-std=c++17 -fvisibility=hidden -fPIC ${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'"
+export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' libevent_cflags='${MSAN_FLAGS}' sqlite_cflags='${MSAN_FLAGS}' zeromq_cxxflags='-std=c++17 ${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
export BITCOIN_CONFIG="--enable-wallet --with-sanitizers=memory --with-asm=no --prefix=${DEPENDS_DIR}/x86_64-pc-linux-gnu/ CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}' BDB_LIBS='-L${BDB_PREFIX}/lib -ldb_cxx-4.8' BDB_CFLAGS='-I${BDB_PREFIX}/include'"
export USE_MEMORY_SANITIZER="true"
diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh
index 6619852423..25aa682eb0 100755
--- a/ci/test/00_setup_env_win64.sh
+++ b/ci/test/00_setup_env_win64.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_win64
-export DOCKER_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to win64
+export DOCKER_NAME_TAG=ubuntu:22.04 # Check that Jammy can cross-compile to win64
export HOST=x86_64-w64-mingw32
export DPKG_ADD_ARCH="i386"
export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 wine32 file"
diff --git a/configure.ac b/configure.ac
index 11a01f310c..222fa94946 100644
--- a/configure.ac
+++ b/configure.ac
@@ -469,7 +469,7 @@ AX_CHECK_COMPILE_FLAG([-fno-extended-identifiers], [CXXFLAGS="$CXXFLAGS -fno-ext
enable_sse42=no
enable_sse41=no
enable_avx2=no
-enable_shani=no
+enable_x86_shani=no
if test "$use_asm" = "yes"; then
@@ -481,7 +481,7 @@ dnl x86
AX_CHECK_COMPILE_FLAG([-msse4.2], [SSE42_CXXFLAGS="-msse4.2"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-msse4.1], [SSE41_CXXFLAGS="-msse4.1"], [], [$CXXFLAG_WERROR])
AX_CHECK_COMPILE_FLAG([-mavx -mavx2], [AVX2_CXXFLAGS="-mavx -mavx2"], [], [$CXXFLAG_WERROR])
-AX_CHECK_COMPILE_FLAG([-msse4 -msha], [SHANI_CXXFLAGS="-msse4 -msha"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-msse4 -msha], [X86_SHANI_CXXFLAGS="-msse4 -msha"], [], [$CXXFLAG_WERROR])
enable_clmul=
AX_CHECK_COMPILE_FLAG([-mpclmul], [enable_clmul=yes], [], [$CXXFLAG_WERROR], [AC_LANG_PROGRAM([
@@ -554,8 +554,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
CXXFLAGS="$TEMP_CXXFLAGS"
TEMP_CXXFLAGS="$CXXFLAGS"
-CXXFLAGS="$CXXFLAGS $SHANI_CXXFLAGS"
-AC_MSG_CHECKING([for SHA-NI intrinsics])
+CXXFLAGS="$CXXFLAGS $X86_SHANI_CXXFLAGS"
+AC_MSG_CHECKING([for x86 SHA-NI intrinsics])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>
#include <immintrin.h>
@@ -565,17 +565,18 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
__m128i k = _mm_set1_epi32(2);
return _mm_extract_epi32(_mm_sha256rnds2_epu32(i, i, k), 0);
]])],
- [ AC_MSG_RESULT([yes]); enable_shani=yes; AC_DEFINE([ENABLE_SHANI], [1], [Define this symbol to build code that uses SHA-NI intrinsics]) ],
+ [ AC_MSG_RESULT([yes]); enable_x86_shani=yes; AC_DEFINE([ENABLE_X86_SHANI], [1], [Define this symbol to build code that uses x86 SHA-NI intrinsics]) ],
[ AC_MSG_RESULT([no])]
)
CXXFLAGS="$TEMP_CXXFLAGS"
# ARM
AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_CRC_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-march=armv8-a+crc+crypto], [ARM_SHANI_CXXFLAGS="-march=armv8-a+crc+crypto"], [], [$CXXFLAG_WERROR])
TEMP_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $ARM_CRC_CXXFLAGS"
-AC_MSG_CHECKING([for AArch64 CRC32 intrinsics])
+AC_MSG_CHECKING([for ARMv8 CRC32 intrinsics])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <arm_acle.h>
#include <arm_neon.h>
@@ -592,6 +593,24 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
)
CXXFLAGS="$TEMP_CXXFLAGS"
+TEMP_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS="$CXXFLAGS $ARM_SHANI_CXXFLAGS"
+AC_MSG_CHECKING([for ARMv8 SHA-NI intrinsics])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <arm_acle.h>
+ #include <arm_neon.h>
+ ]],[[
+ uint32x4_t a, b, c;
+ vsha256h2q_u32(a, b, c);
+ vsha256hq_u32(a, b, c);
+ vsha256su0q_u32(a, b);
+ vsha256su1q_u32(a, b, c);
+ ]])],
+ [ AC_MSG_RESULT([yes]); enable_arm_shani=yes; AC_DEFINE([ENABLE_ARM_SHANI], [1], [Define this symbol to build code that uses ARMv8 SHA-NI intrinsics]) ],
+ [ AC_MSG_RESULT([no])]
+)
+CXXFLAGS="$TEMP_CXXFLAGS"
+
fi
CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO"
@@ -1418,8 +1437,20 @@ if test "$use_external_signer" != "no"; then
use_external_signer="no";
;;
*)
- use_external_signer="yes"
- AC_DEFINE([ENABLE_EXTERNAL_SIGNER], [1], [Define if external signer support is enabled])
+ AC_MSG_CHECKING([whether Boost.Process can be used])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <boost/process.hpp>]])],
+ [have_boost_process="yes"],
+ [have_boost_process="no"])
+ AC_MSG_RESULT([$have_boost_process])
+ if test "$have_boost_process" == "yes"; then
+ use_external_signer="yes"
+ AC_DEFINE([ENABLE_EXTERNAL_SIGNER], [1], [Define if external signer support is enabled])
+ else
+ if test "$use_external_signer" = "yes"; then
+ AC_MSG_ERROR([External signing is not supported for this Boost version])
+ fi
+ use_external_signer="no";
+ fi
;;
esac
fi
@@ -1774,8 +1805,9 @@ AM_CONDITIONAL([HARDEN], [test "$use_hardening" = "yes"])
AM_CONDITIONAL([ENABLE_SSE42], [test "$enable_sse42" = "yes"])
AM_CONDITIONAL([ENABLE_SSE41], [test "$enable_sse41" = "yes"])
AM_CONDITIONAL([ENABLE_AVX2], [test "$enable_avx2" = "yes"])
-AM_CONDITIONAL([ENABLE_SHANI], [test "$enable_shani" = "yes"])
+AM_CONDITIONAL([ENABLE_X86_SHANI], [test "$enable_x86_shani" = "yes"])
AM_CONDITIONAL([ENABLE_ARM_CRC], [test "$enable_arm_crc" = "yes"])
+AM_CONDITIONAL([ENABLE_ARM_SHANI], [test "$enable_arm_shani" = "yes"])
AM_CONDITIONAL([USE_ASM], [test "$use_asm" = "yes"])
AM_CONDITIONAL([WORDS_BIGENDIAN], [test "$ac_cv_c_bigendian" = "yes"])
AM_CONDITIONAL([USE_NATPMP], [test "$use_natpmp" = "yes"])
@@ -1832,8 +1864,9 @@ AC_SUBST(SSE42_CXXFLAGS)
AC_SUBST(SSE41_CXXFLAGS)
AC_SUBST(CLMUL_CXXFLAGS)
AC_SUBST(AVX2_CXXFLAGS)
-AC_SUBST(SHANI_CXXFLAGS)
+AC_SUBST(X86_SHANI_CXXFLAGS)
AC_SUBST(ARM_CRC_CXXFLAGS)
+AC_SUBST(ARM_SHANI_CXXFLAGS)
AC_SUBST(LIBTOOL_APP_LDFLAGS)
AC_SUBST(USE_SQLITE)
AC_SUBST(USE_BDB)
@@ -1924,8 +1957,8 @@ if test $enable_fuzz = "no"; then
echo " with test = $use_tests"
else
echo " with test = not building test_bitcoin because fuzzing is enabled"
- echo " with fuzz = $enable_fuzz"
fi
+echo " with fuzz binary = $enable_fuzz_binary"
echo " with bench = $use_bench"
echo " with upnp = $use_upnp"
echo " with natpmp = $use_natpmp"
diff --git a/contrib/guix/guix-build b/contrib/guix/guix-build
index bfffbda742..2d44ad0365 100755
--- a/contrib/guix/guix-build
+++ b/contrib/guix/guix-build
@@ -239,7 +239,7 @@ SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git -c log.showSignature=false log --f
time-machine() {
# shellcheck disable=SC2086
guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \
- --commit=1ef7a03a148cf5f83ab1820444f6bd50d8e732d1 \
+ --commit=ae03f401381e956c4c41b4cf495cbde964fa43d0 \
--cores="$JOBS" \
--keep-failed \
--fallback \
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 22b922dc9b..d296eb9543 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -162,13 +162,17 @@ desirable for building Bitcoin Core release binaries."
(define (make-gcc-with-pthreads gcc)
(package-with-extra-configure-variable gcc "--enable-threads" "posix"))
+;; Required to support std::filesystem for mingw-w64 target.
+(define (make-gcc-without-newlib gcc)
+ (package-with-extra-configure-variable gcc "--with-newlib" "no"))
+
(define (make-mingw-pthreads-cross-toolchain target)
"Create a cross-compilation toolchain package for TARGET"
(let* ((xbinutils (cross-binutils target))
(pthreads-xlibc mingw-w64-x86_64-winpthreads)
(pthreads-xgcc (make-gcc-with-pthreads
(cross-gcc target
- #:xgcc (make-ssp-fixed-gcc base-gcc)
+ #:xgcc (make-gcc-without-newlib (make-ssp-fixed-gcc base-gcc))
#:xbinutils xbinutils
#:libc pthreads-xlibc))))
;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and
diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md
index b71ce2f34b..a409a23ef8 100644
--- a/contrib/tracing/README.md
+++ b/contrib/tracing/README.md
@@ -237,7 +237,7 @@ Histogram of block connection times in milliseconds (ms).
### log_utxocache_flush.py
-A BCC Python script to log the cache and index flushes. Based on the
+A BCC Python script to log the UTXO cache flushes. Based on the
`utxocache:flush` tracepoint.
```bash
@@ -246,23 +246,10 @@ $ python3 contrib/tracing/log_utxocache_flush.py ./src/bitcoind
```
Logging utxocache flushes. Ctrl-C to end...
-Duration (µs) Mode Coins Count Memory Usage Prune Full Flush
-0 PERIODIC 28484 3929.87 kB False False
-1 PERIODIC 28485 3930.00 kB False False
-0 PERIODIC 28489 3930.51 kB False False
-1 PERIODIC 28490 3930.64 kB False False
-0 PERIODIC 28491 3930.77 kB False False
-0 PERIODIC 28491 3930.77 kB False False
-0 PERIODIC 28496 3931.41 kB False False
-1 PERIODIC 28496 3931.41 kB False False
-0 PERIODIC 28497 3931.54 kB False False
-1 PERIODIC 28497 3931.54 kB False False
-1 PERIODIC 28499 3931.79 kB False False
-.
-.
-.
-53788 ALWAYS 30076 4136.27 kB False False
-7463 ALWAYS 0 245.84 kB False False
+Duration (µs) Mode Coins Count Memory Usage Prune
+730451 IF_NEEDED 22990 3323.54 kB True
+637657 ALWAYS 122320 17124.80 kB False
+81349 ALWAYS 0 1383.49 kB False
```
### log_utxos.bt
@@ -275,7 +262,13 @@ uncached from the UTXO set. Based on the `utxocache:add`, `utxocache:spend` and
$ bpftrace contrib/tracing/log_utxos.bt
```
-It should produce an output similar to the following.
+This should produce an output similar to the following. If you see bpftrace
+warnings like `Lost 24 events`, the eBPF perf ring-buffer is filled faster
+than it is being read. You can increase the ring-buffer size by setting the
+ENV variable `BPFTRACE_PERF_RB_PAGES` (default 64) at a cost of higher
+memory usage. See the [bpftrace reference guide] for more information.
+
+[bpftrace reference guide]: https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md#98-bpftrace_perf_rb_pages
```bash
Attaching 4 probes...
diff --git a/contrib/tracing/log_utxocache_flush.py b/contrib/tracing/log_utxocache_flush.py
index 7f26504e7b..8c073bea0d 100755
--- a/contrib/tracing/log_utxocache_flush.py
+++ b/contrib/tracing/log_utxocache_flush.py
@@ -16,14 +16,14 @@ from bcc import BPF, USDT
# a sandboxed Linux kernel VM.
program = """
# include <uapi/linux/ptrace.h>
+
struct data_t
{
u64 duration;
u32 mode;
u64 coins_count;
u64 coins_mem_usage;
- bool is_flush_prune;
- bool is_full_flush;
+ bool is_flush_for_prune;
};
// BPF perf buffer to push the data to user space.
@@ -35,8 +35,7 @@ int trace_flush(struct pt_regs *ctx) {
bpf_usdt_readarg(2, ctx, &data.mode);
bpf_usdt_readarg(3, ctx, &data.coins_count);
bpf_usdt_readarg(4, ctx, &data.coins_mem_usage);
- bpf_usdt_readarg(5, ctx, &data.is_flush_prune);
- bpf_usdt_readarg(5, ctx, &data.is_full_flush);
+ bpf_usdt_readarg(5, ctx, &data.is_flush_for_prune);
flush.perf_submit(ctx, &data, sizeof(data));
return 0;
}
@@ -57,19 +56,17 @@ class Data(ctypes.Structure):
("mode", ctypes.c_uint32),
("coins_count", ctypes.c_uint64),
("coins_mem_usage", ctypes.c_uint64),
- ("is_flush_prune", ctypes.c_bool),
- ("is_full_flush", ctypes.c_bool)
+ ("is_flush_for_prune", ctypes.c_bool)
]
def print_event(event):
- print("%-15d %-10s %-15d %-15s %-8s %-8s" % (
+ print("%-15d %-10s %-15d %-15s %-8s" % (
event.duration,
FLUSH_MODES[event.mode],
event.coins_count,
"%.2f kB" % (event.coins_mem_usage/1000),
- event.is_flush_prune,
- event.is_full_flush
+ event.is_flush_for_prune
))
@@ -90,9 +87,9 @@ def main(bitcoind_path):
b["flush"].open_perf_buffer(handle_flush)
print("Logging utxocache flushes. Ctrl-C to end...")
- print("%-15s %-10s %-15s %-15s %-8s %-8s" % ("Duration (µs)", "Mode",
- "Coins Count", "Memory Usage",
- "Prune", "Full Flush"))
+ print("%-15s %-10s %-15s %-15s %-8s" % ("Duration (µs)", "Mode",
+ "Coins Count", "Memory Usage",
+ "Flush for Prune"))
while True:
try:
diff --git a/contrib/tracing/log_utxos.bt b/contrib/tracing/log_utxos.bt
index 0d47f3d62b..54d5010f82 100755
--- a/contrib/tracing/log_utxos.bt
+++ b/contrib/tracing/log_utxos.bt
@@ -7,7 +7,7 @@
bpftrace contrib/tracing/log_utxos.bt
This script requires a 'bitcoind' binary compiled with eBPF support and the
- 'utxochache' tracepoints. By default, it's assumed that 'bitcoind' is
+ 'utxocache' tracepoints. By default, it's assumed that 'bitcoind' is
located in './src/bitcoind'. This can be modified in the script below.
NOTE: requires bpftrace v0.12.0 or above.
diff --git a/depends/Makefile b/depends/Makefile
index 573115d447..723509c81d 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -77,6 +77,7 @@ full_build_os:=$(subst $(build_arch)-$(build_vendor)-,,$(build))
build_os:=$(findstring linux,$(full_build_os))
build_os+=$(findstring darwin,$(full_build_os))
build_os+=$(findstring freebsd,$(full_build_os))
+build_os+=$(findstring netbsd,$(full_build_os))
build_os+=$(findstring openbsd,$(full_build_os))
build_os:=$(strip $(build_os))
ifeq ($(build_os),)
@@ -89,6 +90,7 @@ full_host_os:=$(subst $(host_arch)-$(host_vendor)-,,$(canonical_host))
host_os:=$(findstring linux,$(full_host_os))
host_os+=$(findstring darwin,$(full_host_os))
host_os+=$(findstring freebsd,$(full_host_os))
+host_os+=$(findstring netbsd,$(full_host_os))
host_os+=$(findstring openbsd,$(full_host_os))
host_os+=$(findstring mingw32,$(full_host_os))
diff --git a/depends/builders/netbsd.mk b/depends/builders/netbsd.mk
new file mode 100644
index 0000000000..b7cf1f7514
--- /dev/null
+++ b/depends/builders/netbsd.mk
@@ -0,0 +1,2 @@
+build_netbsd_SHA256SUM = shasum -a 256
+build_netbsd_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o
diff --git a/depends/hosts/freebsd.mk b/depends/hosts/freebsd.mk
index 307f844331..0a62347b57 100644
--- a/depends/hosts/freebsd.mk
+++ b/depends/hosts/freebsd.mk
@@ -1,11 +1,11 @@
freebsd_CFLAGS=-pipe
-freebsd_CFLAGS_CXXFLAGS=$(freebsd_CFLAGS)
+freebsd_CXXFLAGS=$(freebsd_CFLAGS)
-freebsd_CFLAGS_release_CFLAGS=-O2
-freebsd_CFLAGS_release_CXXFLAGS=$(freebsd_release_CFLAGS)
+freebsd_release_CFLAGS=-O2
+freebsd_release_CXXFLAGS=$(freebsd_release_CFLAGS)
-freebsd_CFLAGS_debug_CFLAGS=-O1
-freebsd_CFLAGS_debug_CXXFLAGS=$(freebsd_debug_CFLAGS)
+freebsd_debug_CFLAGS=-O1
+freebsd_debug_CXXFLAGS=$(freebsd_debug_CFLAGS)
ifeq (86,$(findstring 86,$(build_arch)))
i686_freebsd_CC=clang -m32
diff --git a/depends/hosts/netbsd.mk b/depends/hosts/netbsd.mk
new file mode 100644
index 0000000000..b3e4545a64
--- /dev/null
+++ b/depends/hosts/netbsd.mk
@@ -0,0 +1,31 @@
+netbsd_CFLAGS=-pipe
+netbsd_CXXFLAGS=$(netbsd_CFLAGS)
+
+netbsd_release_CFLAGS=-O2
+netbsd_release_CXXFLAGS=$(netbsd_release_CFLAGS)
+
+netbsd_debug_CFLAGS=-O1
+netbsd_debug_CXXFLAGS=$(netbsd_debug_CFLAGS)
+
+ifeq (86,$(findstring 86,$(build_arch)))
+i686_netbsd_CC=gcc -m32
+i686_netbsd_CXX=g++ -m32
+i686_netbsd_AR=ar
+i686_netbsd_RANLIB=ranlib
+i686_netbsd_NM=nm
+i686_netbsd_STRIP=strip
+
+x86_64_netbsd_CC=gcc -m64
+x86_64_netbsd_CXX=g++ -m64
+x86_64_netbsd_AR=ar
+x86_64_netbsd_RANLIB=ranlib
+x86_64_netbsd_NM=nm
+x86_64_netbsd_STRIP=strip
+else
+i686_netbsd_CC=$(default_host_CC) -m32
+i686_netbsd_CXX=$(default_host_CXX) -m32
+x86_64_netbsd_CC=$(default_host_CC) -m64
+x86_64_netbsd_CXX=$(default_host_CXX) -m64
+endif
+
+netbsd_cmake_system=NetBSD
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 95004f3a22..dc536fd399 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -11,6 +11,7 @@ $(package)_config_opts=--disable-shared --enable-cxx --disable-replication --ena
$(package)_config_opts_mingw32=--enable-mingw
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
+$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
$(package)_cflags+=-Wno-error=implicit-function-declaration
diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk
index 78850e583e..748ed510c1 100644
--- a/depends/packages/libevent.mk
+++ b/depends/packages/libevent.mk
@@ -13,6 +13,7 @@ define $(package)_set_vars
$(package)_config_opts_release=--disable-debug-mode
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
+ $(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
$(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601
diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk
index 3e5cf5f160..40ab3c68ea 100644
--- a/depends/packages/libmultiprocess.mk
+++ b/depends/packages/libmultiprocess.mk
@@ -3,7 +3,7 @@ $(package)_version=$(native_$(package)_version)
$(package)_download_path=$(native_$(package)_download_path)
$(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
-$(package)_dependencies=native_$(package) boost capnp
+$(package)_dependencies=native_$(package) capnp
define $(package)_config_cmds
$($(package)_cmake)
diff --git a/depends/packages/native_clang.mk b/depends/packages/native_clang.mk
index 23c8139262..245269a9d3 100644
--- a/depends/packages/native_clang.mk
+++ b/depends/packages/native_clang.mk
@@ -16,15 +16,10 @@ endef
define $(package)_stage_cmds
mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include && \
mkdir -p $($(package)_staging_prefix_dir)/bin && \
- mkdir -p $($(package)_staging_prefix_dir)/include && \
cp bin/clang $($(package)_staging_prefix_dir)/bin/ && \
cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ && \
cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \
cp bin/llvm-config $($(package)_staging_prefix_dir)/bin/ && \
cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \
- cp -rf lib/clang/$($(package)_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include/
-endef
-
-define $(package)_postprocess_cmds
- rmdir include
+ cp -r lib/clang/$($(package)_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include/
endef
diff --git a/depends/packages/sqlite.mk b/depends/packages/sqlite.mk
index 94bc6dda79..126781ceeb 100644
--- a/depends/packages/sqlite.mk
+++ b/depends/packages/sqlite.mk
@@ -8,6 +8,7 @@ define $(package)_set_vars
$(package)_config_opts=--disable-shared --disable-readline --disable-dynamic-extensions --enable-option-checking
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
+$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
endef
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index 2d8286ea36..c74ae15b31 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -13,6 +13,7 @@ define $(package)_set_vars
$(package)_config_opts += --disable-Werror --disable-drafts --enable-option-checking
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
+ $(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
$(package)_cxxflags+=-std=c++17
diff --git a/doc/managing-wallets.md b/doc/managing-wallets.md
index aab6d131bd..6c1e13c503 100644
--- a/doc/managing-wallets.md
+++ b/doc/managing-wallets.md
@@ -12,11 +12,9 @@ In the GUI, the `Create a new wallet` button is displayed on the main screen whe
The following command, for example, creates a descriptor wallet. More information about this command may be found by running `bitcoin-cli help createwallet`.
```
-$ bitcoin-cli -named createwallet wallet_name="wallet-01" descriptors=true
+$ bitcoin-cli createwallet "wallet-01"
```
-The `descriptors` parameter can be omitted if the intention is to create a legacy wallet. For now, the default type is the legacy wallet, but that is expected to change in a future release.
-
By default, wallets are created in the `wallets` folder of the data directory, which varies by operating system, as shown below. The user can change the default by using the `-datadir` or `-walletdir` initialization parameters.
| Operating System | Default wallet directory |
@@ -54,7 +52,7 @@ Only the wallet's private key is encrypted. All other wallet information, such a
The wallet's private key can also be encrypted in the `createwallet` command via the `passphrase` argument:
```
-$ bitcoin-cli -named createwallet wallet_name="wallet-01" descriptors=true passphrase="passphrase"
+$ bitcoin-cli -named createwallet wallet_name="wallet-01" passphrase="passphrase"
```
Note that if the passphrase is lost, all the coins in the wallet will also be lost forever.
diff --git a/doc/release-process.md b/doc/release-process.md
index 742d349c17..c5dba46238 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -118,7 +118,7 @@ details.
### Build and attest to build outputs:
Follow the relevant Guix README.md sections:
-- [Performing a build](/contrib/guix/README.md#performing-a-build)
+- [Building](/contrib/guix/README.md#building)
- [Attesting to build outputs](/contrib/guix/README.md#attesting-to-build-outputs)
### Verify other builders' signatures to your own. (Optional)
diff --git a/doc/tracing.md b/doc/tracing.md
index 5b9ba09c2f..6ec6a6c218 100644
--- a/doc/tracing.md
+++ b/doc/tracing.md
@@ -110,23 +110,31 @@ Arguments passed:
### Context `utxocache`
+The following tracepoints cover the in-memory UTXO cache. UTXOs are, for example,
+added to and removed (spent) from the cache when we connect a new block.
+**Note**: Bitcoin Core uses temporary clones of the _main_ UTXO cache
+(`chainstate.CoinsTip()`). For example, the RPCs `generateblock` and
+`getblocktemplate` call `TestBlockValidity()`, which applies the UTXO set
+changes to a temporary cache. Similarly, mempool consistency checks, which are
+frequent on regtest, also apply the the UTXO set changes to a temporary cache.
+Changes to the _main_ UTXO cache and to temporary caches trigger the tracepoints.
+We can't tell if a temporary cache or the _main_ cache was changed.
+
#### Tracepoint `utxocache:flush`
-Is called *after* the caches and indexes are flushed depending on the mode
-`CChainState::FlushStateToDisk` is called with.
+Is called *after* the in-memory UTXO cache is flushed.
Arguments passed:
-1. Duration in microseconds as `int64`
+1. Time it took to flush the cache microseconds as `int64`
2. Flush state mode as `uint32`. It's an enumerator class with values `0`
(`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`ALWAYS`)
-3. Number of coins flushed as `uint64`
-4. Memory usage in bytes as `uint64`
-5. If the flush was pruned as `bool`
-6. If it was full flush as `bool`
+3. Cache size (number of coins) before the flush as `uint64`
+4. Cache memory usage in bytes as `uint64`
+5. If pruning caused the flush as `bool`
#### Tracepoint `utxocache:add`
-It is called when a new coin is added to the UTXO cache.
+Is called when a coin is added to a UTXO cache. This can be a temporary UTXO cache too.
Arguments passed:
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
@@ -137,7 +145,7 @@ Arguments passed:
#### Tracepoint `utxocache:spent`
-It is called when a coin is spent from the UTXO cache.
+Is called when a coin is spent from a UTXO cache. This can be a temporary UTXO cache too.
Arguments passed:
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
@@ -148,14 +156,17 @@ Arguments passed:
#### Tracepoint `utxocache:uncache`
-It is called when the UTXO with the given outpoint is removed from the cache.
+Is called when a coin is purposefully unloaded from a UTXO cache. This
+happens, for example, when we load an UTXO into a cache when trying to accept
+a transaction that turns out to be invalid. The loaded UTXO is uncached to avoid
+filling our UTXO cache up with irrelevant UTXOs.
Arguments passed:
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
2. Output index as `uint32`
3. Block height the coin was uncached, as `uint32`
4. Value of the coin as `int64`
-. If the coin is a coinbase as `bool`
+5. If the coin is a coinbase as `bool`
## Adding tracepoints to Bitcoin Core
diff --git a/src/Makefile.am b/src/Makefile.am
index efc32da55d..417a611181 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,9 +46,13 @@ if ENABLE_AVX2
LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a
LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2)
endif
-if ENABLE_SHANI
-LIBBITCOIN_CRYPTO_SHANI = crypto/libbitcoin_crypto_shani.a
-LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SHANI)
+if ENABLE_X86_SHANI
+LIBBITCOIN_CRYPTO_X86_SHANI = crypto/libbitcoin_crypto_x86_shani.a
+LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_X86_SHANI)
+endif
+if ENABLE_ARM_SHANI
+LIBBITCOIN_CRYPTO_ARM_SHANI = crypto/libbitcoin_crypto_arm_shani.a
+LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_ARM_SHANI)
endif
$(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(wildcard secp256k1/include/*)
@@ -498,11 +502,17 @@ crypto_libbitcoin_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS)
crypto_libbitcoin_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2
crypto_libbitcoin_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp
-crypto_libbitcoin_crypto_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-crypto_libbitcoin_crypto_shani_a_CPPFLAGS = $(AM_CPPFLAGS)
-crypto_libbitcoin_crypto_shani_a_CXXFLAGS += $(SHANI_CXXFLAGS)
-crypto_libbitcoin_crypto_shani_a_CPPFLAGS += -DENABLE_SHANI
-crypto_libbitcoin_crypto_shani_a_SOURCES = crypto/sha256_shani.cpp
+crypto_libbitcoin_crypto_x86_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+crypto_libbitcoin_crypto_x86_shani_a_CPPFLAGS = $(AM_CPPFLAGS)
+crypto_libbitcoin_crypto_x86_shani_a_CXXFLAGS += $(X86_SHANI_CXXFLAGS)
+crypto_libbitcoin_crypto_x86_shani_a_CPPFLAGS += -DENABLE_X86_SHANI
+crypto_libbitcoin_crypto_x86_shani_a_SOURCES = crypto/sha256_x86_shani.cpp
+
+crypto_libbitcoin_crypto_arm_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+crypto_libbitcoin_crypto_arm_shani_a_CPPFLAGS = $(AM_CPPFLAGS)
+crypto_libbitcoin_crypto_arm_shani_a_CXXFLAGS += $(ARM_SHANI_CXXFLAGS)
+crypto_libbitcoin_crypto_arm_shani_a_CPPFLAGS += -DENABLE_ARM_SHANI
+crypto_libbitcoin_crypto_arm_shani_a_SOURCES = crypto/sha256_arm_shani.cpp
# consensus: shared between all executables that validate any consensus rules.
libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 1763dcb562..e2e08468a7 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -294,6 +294,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/script_bitcoin_consensus.cpp \
test/fuzz/script_descriptor_cache.cpp \
test/fuzz/script_flags.cpp \
+ test/fuzz/script_format.cpp \
test/fuzz/script_interpreter.cpp \
test/fuzz/script_ops.cpp \
test/fuzz/script_sigcache.cpp \
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 6557360a71..8062152bb9 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -69,7 +69,12 @@ static void SetupCliArgs(ArgsManager& argsman)
argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-generate",
+ strprintf("Generate blocks, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer "
+ "arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to "
+ "RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000",
+ DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES),
+ ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -606,8 +611,9 @@ public:
"Suggestion: use with the Linux watch(1) command for a live dashboard; see example below.\n\n"
"Arguments:\n"
+ strprintf("1. level (integer 0-%d, optional) Specify the info level of the peers dashboard (default 0):\n", MAX_DETAIL_LEVEL) +
- " 0 - Connection counts and local addresses\n"
- " 1 - Like 0 but with a peers listing (without address or version columns)\n"
+ " 0 - Peer counts for each reachable network as well as for block relay peers\n"
+ " and manual peers, and the list of local addresses and ports\n"
+ " 1 - Like 0 but preceded by a peers listing (without address and version columns)\n"
" 2 - Like 1 but with an address column\n"
" 3 - Like 1 but with a version column\n"
" 4 - Like 1 but with both address and version columns\n"
@@ -645,13 +651,13 @@ public:
" id Peer index, in increasing order of peer connections since node startup\n"
" address IP address and port of the peer\n"
" version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n"
- "* The connection counts table displays the number of peers by direction, network, and the totals\n"
- " for each, as well as two special outbound columns for block relay peers and manual peers.\n\n"
+ "* The peer counts table displays the number of peers for each reachable network as well as\n"
+ " the number of block relay peers and manual peers.\n\n"
"* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n"
"Examples:\n\n"
- "Connection counts and local addresses only\n"
+ "Peer counts table of reachable networks and list of local addresses\n"
"> bitcoin-cli -netinfo\n\n"
- "Compact peers listing\n"
+ "The same, preceded by a peers listing without address and version columns\n"
"> bitcoin-cli -netinfo 1\n\n"
"Full dashboard\n"
+ strprintf("> bitcoin-cli -netinfo %d\n\n", MAX_DETAIL_LEVEL) +
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 65c37f182f..ff5485e2da 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -63,7 +63,7 @@ static bool WalletAppInit(ArgsManager& args, int argc, char* argv[])
strUsage += "\n"
"bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n"
"By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n"
- "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n"
+ "To change the target wallet, use the -datadir, -wallet and -regtest/-signet/-testnet arguments.\n\n"
"Usage:\n"
" bitcoin-wallet [options] <command>\n";
strUsage += "\n" + args.GetHelpMessage();
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index e35d526d35..cde543e68c 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -10,6 +10,16 @@
#include <compat/cpuid.h>
+#if defined(__linux__) && defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+#if defined(MAC_OSX) && defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
#if defined(USE_ASM)
namespace sha256_sse4
@@ -29,16 +39,26 @@ namespace sha256d64_avx2
void Transform_8way(unsigned char* out, const unsigned char* in);
}
-namespace sha256d64_shani
+namespace sha256d64_x86_shani
{
void Transform_2way(unsigned char* out, const unsigned char* in);
}
-namespace sha256_shani
+namespace sha256_x86_shani
{
void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);
}
+namespace sha256_arm_shani
+{
+void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);
+}
+
+namespace sha256d64_arm_shani
+{
+void Transform_2way(unsigned char* out, const unsigned char* in);
+}
+
// Internal implementation code.
namespace
{
@@ -567,7 +587,7 @@ std::string SHA256AutoDetect()
bool have_xsave = false;
bool have_avx = false;
bool have_avx2 = false;
- bool have_shani = false;
+ bool have_x86_shani = false;
bool enabled_avx = false;
(void)AVXEnabled;
@@ -575,7 +595,7 @@ std::string SHA256AutoDetect()
(void)have_avx;
(void)have_xsave;
(void)have_avx2;
- (void)have_shani;
+ (void)have_x86_shani;
(void)enabled_avx;
uint32_t eax, ebx, ecx, edx;
@@ -589,15 +609,15 @@ std::string SHA256AutoDetect()
if (have_sse4) {
GetCPUID(7, 0, eax, ebx, ecx, edx);
have_avx2 = (ebx >> 5) & 1;
- have_shani = (ebx >> 29) & 1;
+ have_x86_shani = (ebx >> 29) & 1;
}
-#if defined(ENABLE_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
- if (have_shani) {
- Transform = sha256_shani::Transform;
- TransformD64 = TransformD64Wrapper<sha256_shani::Transform>;
- TransformD64_2way = sha256d64_shani::Transform_2way;
- ret = "shani(1way,2way)";
+#if defined(ENABLE_X86_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
+ if (have_x86_shani) {
+ Transform = sha256_x86_shani::Transform;
+ TransformD64 = TransformD64Wrapper<sha256_x86_shani::Transform>;
+ TransformD64_2way = sha256d64_x86_shani::Transform_2way;
+ ret = "x86_shani(1way,2way)";
have_sse4 = false; // Disable SSE4/AVX2;
have_avx2 = false;
}
@@ -623,6 +643,38 @@ std::string SHA256AutoDetect()
#endif
#endif
+#if defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL)
+ bool have_arm_shani = false;
+
+#if defined(__linux__)
+#if defined(__arm__) // 32-bit
+ if (getauxval(AT_HWCAP2) & HWCAP2_SHA2) {
+ have_arm_shani = true;
+ }
+#endif
+#if defined(__aarch64__) // 64-bit
+ if (getauxval(AT_HWCAP) & HWCAP_SHA2) {
+ have_arm_shani = true;
+ }
+#endif
+#endif
+
+#if defined(MAC_OSX)
+ int val = 0;
+ size_t len = sizeof(val);
+ if (sysctlbyname("hw.optional.arm.FEAT_SHA256", &val, &len, nullptr, 0) == 0) {
+ have_arm_shani = val != 0;
+ }
+#endif
+
+ if (have_arm_shani) {
+ Transform = sha256_arm_shani::Transform;
+ TransformD64 = TransformD64Wrapper<sha256_arm_shani::Transform>;
+ TransformD64_2way = sha256d64_arm_shani::Transform_2way;
+ ret = "arm_shani(1way,2way)";
+ }
+#endif
+
assert(SelfTest());
return ret;
}
diff --git a/src/crypto/sha256_arm_shani.cpp b/src/crypto/sha256_arm_shani.cpp
new file mode 100644
index 0000000000..2ea1d9c2ac
--- /dev/null
+++ b/src/crypto/sha256_arm_shani.cpp
@@ -0,0 +1,899 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+// Based on https://github.com/noloader/SHA-Intrinsics/blob/master/sha256-arm.c,
+// Written and placed in public domain by Jeffrey Walton.
+// Based on code from ARM, and by Johannes Schneiders, Skip Hovsmith and
+// Barry O'Rourke for the mbedTLS project.
+// Variant specialized for 64-byte inputs added by Pieter Wuille.
+
+#ifdef ENABLE_ARM_SHANI
+
+#include <array>
+#include <cstdint>
+#include <cstddef>
+#include <arm_acle.h>
+#include <arm_neon.h>
+
+namespace {
+alignas(uint32x4_t) static constexpr std::array<uint32_t, 64> K =
+{
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+}
+
+namespace sha256_arm_shani {
+void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
+{
+ uint32x4_t STATE0, STATE1, ABEF_SAVE, CDGH_SAVE;
+ uint32x4_t MSG0, MSG1, MSG2, MSG3;
+ uint32x4_t TMP0, TMP2;
+
+ // Load state
+ STATE0 = vld1q_u32(&s[0]);
+ STATE1 = vld1q_u32(&s[4]);
+
+ while (blocks--)
+ {
+ // Save state
+ ABEF_SAVE = STATE0;
+ CDGH_SAVE = STATE1;
+
+ // Load and convert input chunk to Big Endian
+ MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 0)));
+ MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 16)));
+ MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 32)));
+ MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 48)));
+ chunk += 64;
+
+ // Original implementation preloaded message and constant addition which was 1-3% slower.
+ // Now included as first step in quad round code saving one Q Neon register
+ // "TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0]));"
+
+ // Rounds 1-4
+ TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0]));
+ TMP2 = STATE0;
+ MSG0 = vsha256su0q_u32(MSG0, MSG1);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3);
+
+ // Rounds 5-8
+ TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[4]));
+ TMP2 = STATE0;
+ MSG1 = vsha256su0q_u32(MSG1, MSG2);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0);
+
+ // Rounds 9-12
+ TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[8]));
+ TMP2 = STATE0;
+ MSG2 = vsha256su0q_u32(MSG2, MSG3);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1);
+
+ // Rounds 13-16
+ TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[12]));
+ TMP2 = STATE0;
+ MSG3 = vsha256su0q_u32(MSG3, MSG0);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2);
+
+ // Rounds 17-20
+ TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[16]));
+ TMP2 = STATE0;
+ MSG0 = vsha256su0q_u32(MSG0, MSG1);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3);
+
+ // Rounds 21-24
+ TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[20]));
+ TMP2 = STATE0;
+ MSG1 = vsha256su0q_u32(MSG1, MSG2);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0);
+
+ // Rounds 25-28
+ TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[24]));
+ TMP2 = STATE0;
+ MSG2 = vsha256su0q_u32(MSG2, MSG3);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1);
+
+ // Rounds 29-32
+ TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[28]));
+ TMP2 = STATE0;
+ MSG3 = vsha256su0q_u32(MSG3, MSG0);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2);
+
+ // Rounds 33-36
+ TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[32]));
+ TMP2 = STATE0;
+ MSG0 = vsha256su0q_u32(MSG0, MSG1);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3);
+
+ // Rounds 37-40
+ TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[36]));
+ TMP2 = STATE0;
+ MSG1 = vsha256su0q_u32(MSG1, MSG2);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0);
+
+ // Rounds 41-44
+ TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[40]));
+ TMP2 = STATE0;
+ MSG2 = vsha256su0q_u32(MSG2, MSG3);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1);
+
+ // Rounds 45-48
+ TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[44]));
+ TMP2 = STATE0;
+ MSG3 = vsha256su0q_u32(MSG3, MSG0);
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+ MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2);
+
+ // Rounds 49-52
+ TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[48]));
+ TMP2 = STATE0;
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+
+ // Rounds 53-56
+ TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[52]));
+ TMP2 = STATE0;
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+
+ // Rounds 57-60
+ TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[56]));
+ TMP2 = STATE0;
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+
+ // Rounds 61-64
+ TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[60]));
+ TMP2 = STATE0;
+ STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);
+ STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);
+
+ // Update state
+ STATE0 = vaddq_u32(STATE0, ABEF_SAVE);
+ STATE1 = vaddq_u32(STATE1, CDGH_SAVE);
+ }
+
+ // Save final state
+ vst1q_u32(&s[0], STATE0);
+ vst1q_u32(&s[4], STATE1);
+}
+}
+
+namespace sha256d64_arm_shani {
+void Transform_2way(unsigned char* output, const unsigned char* input)
+{
+ /* Initial state. */
+ alignas(uint32x4_t) static constexpr std::array<uint32_t, 8> INIT = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+ };
+
+ /* Precomputed message schedule for the 2nd transform. */
+ alignas(uint32x4_t) static constexpr std::array<uint32_t, 64> MIDS = {
+ 0xc28a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf374,
+ 0x649b69c1, 0xf0fe4786, 0x0fe1edc6, 0x240cf254,
+ 0x4fe9346f, 0x6cc984be, 0x61b9411e, 0x16f988fa,
+ 0xf2c65152, 0xa88e5a6d, 0xb019fc65, 0xb9d99ec7,
+ 0x9a1231c3, 0xe70eeaa0, 0xfdb1232b, 0xc7353eb0,
+ 0x3069bad5, 0xcb976d5f, 0x5a0f118f, 0xdc1eeefd,
+ 0x0a35b689, 0xde0b7a04, 0x58f4ca9d, 0xe15d5b16,
+ 0x007f3e86, 0x37088980, 0xa507ea32, 0x6fab9537,
+ 0x17406110, 0x0d8cd6f1, 0xcdaa3b6d, 0xc0bbbe37,
+ 0x83613bda, 0xdb48a363, 0x0b02e931, 0x6fd15ca7,
+ 0x521afaca, 0x31338431, 0x6ed41a95, 0x6d437890,
+ 0xc39c91f2, 0x9eccabbd, 0xb5c9a0e6, 0x532fb63c,
+ 0xd2c741c6, 0x07237ea3, 0xa4954b68, 0x4c191d76
+ };
+
+ /* A few precomputed message schedule values for the 3rd transform. */
+ alignas(uint32x4_t) static constexpr std::array<uint32_t, 12> FINS = {
+ 0x5807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x80000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf274
+ };
+
+ /* Padding processed in the 3rd transform (byteswapped). */
+ alignas(uint32x4_t) static constexpr std::array<uint32_t, 8> FINAL = {0x80000000, 0, 0, 0, 0, 0, 0, 0x100};
+
+ uint32x4_t STATE0A, STATE0B, STATE1A, STATE1B, ABEF_SAVEA, ABEF_SAVEB, CDGH_SAVEA, CDGH_SAVEB;
+ uint32x4_t MSG0A, MSG0B, MSG1A, MSG1B, MSG2A, MSG2B, MSG3A, MSG3B;
+ uint32x4_t TMP0A, TMP0B, TMP2A, TMP2B, TMP;
+
+ // Transform 1: Load state
+ STATE0A = vld1q_u32(&INIT[0]);
+ STATE0B = STATE0A;
+ STATE1A = vld1q_u32(&INIT[4]);
+ STATE1B = STATE1A;
+
+ // Transform 1: Load and convert input chunk to Big Endian
+ MSG0A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 0)));
+ MSG1A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 16)));
+ MSG2A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 32)));
+ MSG3A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 48)));
+ MSG0B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 64)));
+ MSG1B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 80)));
+ MSG2B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 96)));
+ MSG3B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 112)));
+
+ // Transform 1: Rounds 1-4
+ TMP = vld1q_u32(&K[0]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG0A = vsha256su0q_u32(MSG0A, MSG1A);
+ MSG0B = vsha256su0q_u32(MSG0B, MSG1B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);
+ MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);
+
+ // Transform 1: Rounds 5-8
+ TMP = vld1q_u32(&K[4]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG1A = vsha256su0q_u32(MSG1A, MSG2A);
+ MSG1B = vsha256su0q_u32(MSG1B, MSG2B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);
+ MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);
+
+ // Transform 1: Rounds 9-12
+ TMP = vld1q_u32(&K[8]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG2A = vsha256su0q_u32(MSG2A, MSG3A);
+ MSG2B = vsha256su0q_u32(MSG2B, MSG3B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);
+ MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);
+
+ // Transform 1: Rounds 13-16
+ TMP = vld1q_u32(&K[12]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG3A = vsha256su0q_u32(MSG3A, MSG0A);
+ MSG3B = vsha256su0q_u32(MSG3B, MSG0B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);
+ MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);
+
+ // Transform 1: Rounds 17-20
+ TMP = vld1q_u32(&K[16]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG0A = vsha256su0q_u32(MSG0A, MSG1A);
+ MSG0B = vsha256su0q_u32(MSG0B, MSG1B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);
+ MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);
+
+ // Transform 1: Rounds 21-24
+ TMP = vld1q_u32(&K[20]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG1A = vsha256su0q_u32(MSG1A, MSG2A);
+ MSG1B = vsha256su0q_u32(MSG1B, MSG2B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);
+ MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);
+
+ // Transform 1: Rounds 25-28
+ TMP = vld1q_u32(&K[24]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG2A = vsha256su0q_u32(MSG2A, MSG3A);
+ MSG2B = vsha256su0q_u32(MSG2B, MSG3B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);
+ MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);
+
+ // Transform 1: Rounds 29-32
+ TMP = vld1q_u32(&K[28]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG3A = vsha256su0q_u32(MSG3A, MSG0A);
+ MSG3B = vsha256su0q_u32(MSG3B, MSG0B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);
+ MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);
+
+ // Transform 1: Rounds 33-36
+ TMP = vld1q_u32(&K[32]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG0A = vsha256su0q_u32(MSG0A, MSG1A);
+ MSG0B = vsha256su0q_u32(MSG0B, MSG1B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);
+ MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);
+
+ // Transform 1: Rounds 37-40
+ TMP = vld1q_u32(&K[36]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG1A = vsha256su0q_u32(MSG1A, MSG2A);
+ MSG1B = vsha256su0q_u32(MSG1B, MSG2B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);
+ MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);
+
+ // Transform 1: Rounds 41-44
+ TMP = vld1q_u32(&K[40]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG2A = vsha256su0q_u32(MSG2A, MSG3A);
+ MSG2B = vsha256su0q_u32(MSG2B, MSG3B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);
+ MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);
+
+ // Transform 1: Rounds 45-48
+ TMP = vld1q_u32(&K[44]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG3A = vsha256su0q_u32(MSG3A, MSG0A);
+ MSG3B = vsha256su0q_u32(MSG3B, MSG0B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);
+ MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);
+
+ // Transform 1: Rounds 49-52
+ TMP = vld1q_u32(&K[48]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 1: Rounds 53-56
+ TMP = vld1q_u32(&K[52]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 1: Rounds 57-60
+ TMP = vld1q_u32(&K[56]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 1: Rounds 61-64
+ TMP = vld1q_u32(&K[60]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 1: Update state
+ TMP = vld1q_u32(&INIT[0]);
+ STATE0A = vaddq_u32(STATE0A, TMP);
+ STATE0B = vaddq_u32(STATE0B, TMP);
+ TMP = vld1q_u32(&INIT[4]);
+ STATE1A = vaddq_u32(STATE1A, TMP);
+ STATE1B = vaddq_u32(STATE1B, TMP);
+
+ // Transform 2: Save state
+ ABEF_SAVEA = STATE0A;
+ ABEF_SAVEB = STATE0B;
+ CDGH_SAVEA = STATE1A;
+ CDGH_SAVEB = STATE1B;
+
+ // Transform 2: Rounds 1-4
+ TMP = vld1q_u32(&MIDS[0]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 5-8
+ TMP = vld1q_u32(&MIDS[4]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 9-12
+ TMP = vld1q_u32(&MIDS[8]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 13-16
+ TMP = vld1q_u32(&MIDS[12]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 17-20
+ TMP = vld1q_u32(&MIDS[16]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 21-24
+ TMP = vld1q_u32(&MIDS[20]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 25-28
+ TMP = vld1q_u32(&MIDS[24]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 29-32
+ TMP = vld1q_u32(&MIDS[28]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 33-36
+ TMP = vld1q_u32(&MIDS[32]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 37-40
+ TMP = vld1q_u32(&MIDS[36]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 41-44
+ TMP = vld1q_u32(&MIDS[40]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 45-48
+ TMP = vld1q_u32(&MIDS[44]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 49-52
+ TMP = vld1q_u32(&MIDS[48]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 53-56
+ TMP = vld1q_u32(&MIDS[52]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 57-60
+ TMP = vld1q_u32(&MIDS[56]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Rounds 61-64
+ TMP = vld1q_u32(&MIDS[60]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+
+ // Transform 2: Update state
+ STATE0A = vaddq_u32(STATE0A, ABEF_SAVEA);
+ STATE0B = vaddq_u32(STATE0B, ABEF_SAVEB);
+ STATE1A = vaddq_u32(STATE1A, CDGH_SAVEA);
+ STATE1B = vaddq_u32(STATE1B, CDGH_SAVEB);
+
+ // Transform 3: Pad previous output
+ MSG0A = STATE0A;
+ MSG0B = STATE0B;
+ MSG1A = STATE1A;
+ MSG1B = STATE1B;
+ MSG2A = vld1q_u32(&FINAL[0]);
+ MSG2B = MSG2A;
+ MSG3A = vld1q_u32(&FINAL[4]);
+ MSG3B = MSG3A;
+
+ // Transform 3: Load state
+ STATE0A = vld1q_u32(&INIT[0]);
+ STATE0B = STATE0A;
+ STATE1A = vld1q_u32(&INIT[4]);
+ STATE1B = STATE1A;
+
+ // Transform 3: Rounds 1-4
+ TMP = vld1q_u32(&K[0]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG0A = vsha256su0q_u32(MSG0A, MSG1A);
+ MSG0B = vsha256su0q_u32(MSG0B, MSG1B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);
+ MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);
+
+ // Transform 3: Rounds 5-8
+ TMP = vld1q_u32(&K[4]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG1A = vsha256su0q_u32(MSG1A, MSG2A);
+ MSG1B = vsha256su0q_u32(MSG1B, MSG2B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);
+ MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);
+
+ // Transform 3: Rounds 9-12
+ TMP = vld1q_u32(&FINS[0]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG2A = vld1q_u32(&FINS[4]);
+ MSG2B = MSG2A;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+ MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);
+ MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);
+
+ // Transform 3: Rounds 13-16
+ TMP = vld1q_u32(&FINS[8]);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG3A = vsha256su0q_u32(MSG3A, MSG0A);
+ MSG3B = vsha256su0q_u32(MSG3B, MSG0B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);
+ MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);
+ MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);
+
+ // Transform 3: Rounds 17-20
+ TMP = vld1q_u32(&K[16]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG0A = vsha256su0q_u32(MSG0A, MSG1A);
+ MSG0B = vsha256su0q_u32(MSG0B, MSG1B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);
+ MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);
+
+ // Transform 3: Rounds 21-24
+ TMP = vld1q_u32(&K[20]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG1A = vsha256su0q_u32(MSG1A, MSG2A);
+ MSG1B = vsha256su0q_u32(MSG1B, MSG2B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);
+ MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);
+
+ // Transform 3: Rounds 25-28
+ TMP = vld1q_u32(&K[24]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG2A = vsha256su0q_u32(MSG2A, MSG3A);
+ MSG2B = vsha256su0q_u32(MSG2B, MSG3B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);
+ MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);
+
+ // Transform 3: Rounds 29-32
+ TMP = vld1q_u32(&K[28]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG3A = vsha256su0q_u32(MSG3A, MSG0A);
+ MSG3B = vsha256su0q_u32(MSG3B, MSG0B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);
+ MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);
+
+ // Transform 3: Rounds 33-36
+ TMP = vld1q_u32(&K[32]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG0A = vsha256su0q_u32(MSG0A, MSG1A);
+ MSG0B = vsha256su0q_u32(MSG0B, MSG1B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);
+ MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);
+
+ // Transform 3: Rounds 37-40
+ TMP = vld1q_u32(&K[36]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG1A = vsha256su0q_u32(MSG1A, MSG2A);
+ MSG1B = vsha256su0q_u32(MSG1B, MSG2B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);
+ MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);
+
+ // Transform 3: Rounds 41-44
+ TMP = vld1q_u32(&K[40]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG2A = vsha256su0q_u32(MSG2A, MSG3A);
+ MSG2B = vsha256su0q_u32(MSG2B, MSG3B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);
+ MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);
+
+ // Transform 3: Rounds 45-48
+ TMP = vld1q_u32(&K[44]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ MSG3A = vsha256su0q_u32(MSG3A, MSG0A);
+ MSG3B = vsha256su0q_u32(MSG3B, MSG0B);
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+ MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);
+ MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);
+
+ // Transform 3: Rounds 49-52
+ TMP = vld1q_u32(&K[48]);
+ TMP0A = vaddq_u32(MSG0A, TMP);
+ TMP0B = vaddq_u32(MSG0B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 3: Rounds 53-56
+ TMP = vld1q_u32(&K[52]);
+ TMP0A = vaddq_u32(MSG1A, TMP);
+ TMP0B = vaddq_u32(MSG1B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 3: Rounds 57-60
+ TMP = vld1q_u32(&K[56]);
+ TMP0A = vaddq_u32(MSG2A, TMP);
+ TMP0B = vaddq_u32(MSG2B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 3: Rounds 61-64
+ TMP = vld1q_u32(&K[60]);
+ TMP0A = vaddq_u32(MSG3A, TMP);
+ TMP0B = vaddq_u32(MSG3B, TMP);
+ TMP2A = STATE0A;
+ TMP2B = STATE0B;
+ STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);
+ STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);
+ STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);
+ STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);
+
+ // Transform 3: Update state
+ TMP = vld1q_u32(&INIT[0]);
+ STATE0A = vaddq_u32(STATE0A, TMP);
+ STATE0B = vaddq_u32(STATE0B, TMP);
+ TMP = vld1q_u32(&INIT[4]);
+ STATE1A = vaddq_u32(STATE1A, TMP);
+ STATE1B = vaddq_u32(STATE1B, TMP);
+
+ // Store result
+ vst1q_u8(output, vrev32q_u8(vreinterpretq_u8_u32(STATE0A)));
+ vst1q_u8(output + 16, vrev32q_u8(vreinterpretq_u8_u32(STATE1A)));
+ vst1q_u8(output + 32, vrev32q_u8(vreinterpretq_u8_u32(STATE0B)));
+ vst1q_u8(output + 48, vrev32q_u8(vreinterpretq_u8_u32(STATE1B)));
+}
+}
+
+#endif
diff --git a/src/crypto/sha256_shani.cpp b/src/crypto/sha256_x86_shani.cpp
index 4f4d5b5837..a82802199f 100644
--- a/src/crypto/sha256_shani.cpp
+++ b/src/crypto/sha256_x86_shani.cpp
@@ -6,7 +6,7 @@
// Written and placed in public domain by Jeffrey Walton.
// Based on code from Intel, and by Sean Gulley for the miTLS project.
-#ifdef ENABLE_SHANI
+#ifdef ENABLE_X86_SHANI
#include <stdint.h>
#include <immintrin.h>
@@ -74,7 +74,7 @@ void inline __attribute__((always_inline)) Save(unsigned char* out, __m128i s)
}
}
-namespace sha256_shani {
+namespace sha256_x86_shani {
void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
{
__m128i m0, m1, m2, m3, s0, s1, so0, so1;
@@ -139,7 +139,7 @@ void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
}
}
-namespace sha256d64_shani {
+namespace sha256d64_x86_shani {
void Transform_2way(unsigned char* out, const unsigned char* in)
{
diff --git a/src/fs.h b/src/fs.h
index d2299db168..00b786453c 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -140,6 +140,28 @@ static inline path PathFromString(const std::string& string)
return std::filesystem::path(string);
#endif
}
+
+/**
+ * Create directory (and if necessary its parents), unless the leaf directory
+ * already exists or is a symlink to an existing directory.
+ * This is a temporary workaround for an issue in libstdc++ that has been fixed
+ * upstream [PR101510].
+ */
+static inline bool create_directories(const std::filesystem::path& p)
+{
+ if (std::filesystem::is_symlink(p) && std::filesystem::is_directory(p)) {
+ return false;
+ }
+ return std::filesystem::create_directories(p);
+}
+
+/**
+ * This variant is not used. Delete it to prevent it from accidentally working
+ * around the workaround. If it is needed, add a workaround in the same pattern
+ * as above.
+ */
+bool create_directories(const std::filesystem::path& p, std::error_code& ec) = delete;
+
} // namespace fs
/** Bridge operations to C stdio */
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 2e3d500cd1..8fe30f8960 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -211,6 +211,11 @@ bool BaseIndex::Commit()
bool BaseIndex::CommitInternal(CDBBatch& batch)
{
LOCK(cs_main);
+ // Don't commit anything if we haven't indexed any block yet
+ // (this could happen if init is interrupted).
+ if (m_best_block_index == nullptr) {
+ return false;
+ }
GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
return true;
}
diff --git a/src/index/base.h b/src/index/base.h
index 66149686f0..c4a8215bc4 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -40,10 +40,10 @@ protected:
DB(const fs::path& path, size_t n_cache_size,
bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false);
- /// Read block locator of the chain that the txindex is in sync with.
+ /// Read block locator of the chain that the index is in sync with.
bool ReadBestBlock(CBlockLocator& locator) const;
- /// Write block locator of the chain that the txindex is in sync with.
+ /// Write block locator of the chain that the index is in sync with.
void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator);
};
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index ef247dc119..a1c8a5937c 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -360,7 +360,15 @@ bool CoinStatsIndex::Init()
if (pindex) {
DBVal entry;
if (!LookUpOne(*m_db, pindex, entry)) {
- return false;
+ return error("%s: Cannot read current %s state; index may be corrupted",
+ __func__, GetName());
+ }
+
+ uint256 out;
+ m_muhash.Finalize(out);
+ if (entry.muhash != out) {
+ return error("%s: Cannot read current %s state; index may be corrupted",
+ __func__, GetName());
}
m_transaction_output_count = entry.transaction_output_count;
diff --git a/src/init.cpp b/src/init.cpp
index 6aef1f8149..64ed868333 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -395,7 +395,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#if HAVE_SYSTEM
- argsman.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-alertnotify=<cmd>", "Execute command when an alert is raised (%s in cmd is replaced by message)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#endif
argsman.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s, signet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(), signetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 7691c9a5ce..8a99130fd0 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -295,7 +295,7 @@ bool BlockManager::LoadBlockIndex(
// them from the background chainstate's setBlockIndexCandidates set. This
// does mean that some blocks which are not technically assumed-valid
// (later blocks on a fork beginning before the first assumed-valid block)
- // might not get added to the the background chainstate, but this is ok,
+ // might not get added to the background chainstate, but this is ok,
// because they will still be attached to the active chainstate if they
// actually contain more work.
//
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 1fcbc45c72..fb98fb6868 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -201,7 +201,7 @@ struct CMutableTransaction;
* - std::vector<CTxIn> vin
* - std::vector<CTxOut> vout
* - if (flags & 1):
- * - CTxWitness wit;
+ * - CScriptWitness scriptWitness; (deserialized into CTxIn)
* - uint32_t nLockTime
*/
template<typename Stream, typename TxType>
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index a180b03c08..d59a4345f3 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -189,7 +189,7 @@ void AddressBookPage::onEditAction()
dlg->setModel(model);
QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
dlg->loadRow(origIndex.row());
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
void AddressBookPage::on_newAddress_clicked()
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 6a2781079c..eb31287c56 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -268,7 +268,11 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
connect(window, &BitcoinGUI::quitRequested, this, &BitcoinApplication::requestShutdown);
pollShutdownTimer = new QTimer(window);
- connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown);
+ connect(pollShutdownTimer, &QTimer::timeout, [this]{
+ if (!QApplication::activeModalWidget()) {
+ window->detectShutdown();
+ }
+ });
}
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 0baacfe58c..7c22880dd1 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -261,10 +261,6 @@ void BitcoinGUI::createActions()
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
- sendCoinsMenuAction = new QAction(sendCoinsAction->text(), this);
- sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
- sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
-
receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
@@ -272,10 +268,6 @@ void BitcoinGUI::createActions()
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
- receiveCoinsMenuAction = new QAction(receiveCoinsAction->text(), this);
- receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
- receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
-
historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
historyAction->setStatusTip(tr("Browse transaction history"));
historyAction->setToolTip(historyAction->statusTip());
@@ -290,12 +282,8 @@ void BitcoinGUI::createActions()
connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage);
connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
- connect(sendCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
- connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
- connect(receiveCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
- connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
#endif // ENABLE_WALLET
@@ -315,8 +303,6 @@ void BitcoinGUI::createActions()
optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME));
optionsAction->setMenuRole(QAction::PreferencesRole);
optionsAction->setEnabled(false);
- toggleHideAction = new QAction(tr("&Show / Hide"), this);
- toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
encryptWalletAction = new QAction(tr("&Encrypt Wallet…"), this);
encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
@@ -376,7 +362,6 @@ void BitcoinGUI::createActions()
connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt);
connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked);
- connect(toggleHideAction, &QAction::triggered, this, &BitcoinGUI::toggleHidden);
connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked);
connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow);
// prevents an open debug window from becoming stuck/unusable on client shutdown
@@ -627,8 +612,6 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
trayIcon->setVisible(optionsModel->getShowTrayIcon());
}
} else {
- // Disable possibility to show main window via action
- toggleHideAction->setEnabled(false);
if(trayIconMenu)
{
// Disable context menu on tray icon
@@ -752,9 +735,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
{
overviewAction->setEnabled(enabled);
sendCoinsAction->setEnabled(enabled);
- sendCoinsMenuAction->setEnabled(enabled);
receiveCoinsAction->setEnabled(enabled);
- receiveCoinsMenuAction->setEnabled(enabled);
historyAction->setEnabled(enabled);
encryptWalletAction->setEnabled(enabled);
backupWalletAction->setEnabled(enabled);
@@ -784,57 +765,82 @@ void BitcoinGUI::createTrayIcon()
void BitcoinGUI::createTrayIconMenu()
{
#ifndef Q_OS_MAC
- // return if trayIcon is unset (only on non-macOSes)
- if (!trayIcon)
- return;
-
- trayIcon->setContextMenu(trayIconMenu.get());
- connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated);
-#else
- // Note: On macOS, the Dock icon is used to provide the tray's functionality.
- MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
- connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated);
- trayIconMenu->setAsDockMenu();
-#endif
+ if (!trayIcon) return;
+#endif // Q_OS_MAC
- // Configuration of the tray icon (or Dock icon) menu
+ // Configuration of the tray icon (or Dock icon) menu.
+ QAction* show_hide_action{nullptr};
#ifndef Q_OS_MAC
// Note: On macOS, the Dock icon's menu already has Show / Hide action.
- trayIconMenu->addAction(toggleHideAction);
+ show_hide_action = trayIconMenu->addAction(QString(), this, &BitcoinGUI::toggleHidden);
trayIconMenu->addSeparator();
-#endif
+#endif // Q_OS_MAC
+
+ QAction* send_action{nullptr};
+ QAction* receive_action{nullptr};
+ QAction* sign_action{nullptr};
+ QAction* verify_action{nullptr};
if (enableWallet) {
- trayIconMenu->addAction(sendCoinsMenuAction);
- trayIconMenu->addAction(receiveCoinsMenuAction);
+ send_action = trayIconMenu->addAction(sendCoinsAction->text(), sendCoinsAction, &QAction::trigger);
+ receive_action = trayIconMenu->addAction(receiveCoinsAction->text(), receiveCoinsAction, &QAction::trigger);
trayIconMenu->addSeparator();
- trayIconMenu->addAction(signMessageAction);
- trayIconMenu->addAction(verifyMessageAction);
+ sign_action = trayIconMenu->addAction(signMessageAction->text(), signMessageAction, &QAction::trigger);
+ verify_action = trayIconMenu->addAction(verifyMessageAction->text(), verifyMessageAction, &QAction::trigger);
trayIconMenu->addSeparator();
}
- trayIconMenu->addAction(optionsAction);
- trayIconMenu->addAction(openRPCConsoleAction);
-#ifndef Q_OS_MAC // This is built-in on macOS
+ QAction* options_action = trayIconMenu->addAction(optionsAction->text(), optionsAction, &QAction::trigger);
+ options_action->setMenuRole(QAction::PreferencesRole);
+ QAction* node_window_action = trayIconMenu->addAction(openRPCConsoleAction->text(), openRPCConsoleAction, &QAction::trigger);
+ QAction* quit_action{nullptr};
+#ifndef Q_OS_MAC
+ // Note: On macOS, the Dock icon's menu already has Quit action.
trayIconMenu->addSeparator();
- trayIconMenu->addAction(quitAction);
-#endif
-}
+ quit_action = trayIconMenu->addAction(quitAction->text(), quitAction, &QAction::trigger);
-#ifndef Q_OS_MAC
-void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
-{
- if(reason == QSystemTrayIcon::Trigger)
- {
- // Click on system tray icon triggers show/hide of the main window
- toggleHidden();
- }
-}
+ trayIcon->setContextMenu(trayIconMenu.get());
+ connect(trayIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
+ if (reason == QSystemTrayIcon::Trigger) {
+ // Click on system tray icon triggers show/hide of the main window
+ toggleHidden();
+ }
+ });
#else
-void BitcoinGUI::macosDockIconActivated()
-{
- show();
- activateWindow();
+ // Note: On macOS, the Dock icon is used to provide the tray's functionality.
+ MacDockIconHandler* dockIconHandler = MacDockIconHandler::instance();
+ connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, [this] {
+ show();
+ activateWindow();
+ });
+ trayIconMenu->setAsDockMenu();
+#endif // Q_OS_MAC
+
+ connect(
+ // Using QSystemTrayIcon::Context is not reliable.
+ // See https://bugreports.qt.io/browse/QTBUG-91697
+ trayIconMenu.get(), &QMenu::aboutToShow,
+ [this, show_hide_action, send_action, receive_action, sign_action, verify_action, options_action, node_window_action, quit_action] {
+ if (show_hide_action) show_hide_action->setText(
+ (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this)) ?
+ tr("&Hide") :
+ tr("S&how"));
+ if (QApplication::activeModalWidget()) {
+ for (QAction* a : trayIconMenu.get()->actions()) {
+ a->setEnabled(false);
+ }
+ } else {
+ if (show_hide_action) show_hide_action->setEnabled(true);
+ if (enableWallet) {
+ send_action->setEnabled(sendCoinsAction->isEnabled());
+ receive_action->setEnabled(receiveCoinsAction->isEnabled());
+ sign_action->setEnabled(signMessageAction->isEnabled());
+ verify_action->setEnabled(verifyMessageAction->isEnabled());
+ }
+ options_action->setEnabled(optionsAction->isEnabled());
+ node_window_action->setEnabled(openRPCConsoleAction->isEnabled());
+ if (quit_action) quit_action->setEnabled(true);
+ }
+ });
}
-#endif
void BitcoinGUI::optionsClicked()
{
@@ -847,7 +853,7 @@ void BitcoinGUI::aboutClicked()
return;
auto dlg = new HelpMessageDialog(this, /* about */ true);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
void BitcoinGUI::showDebugWindow()
@@ -992,7 +998,7 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
connect(dlg, &OptionsDialog::quitOnReset, this, &BitcoinGUI::quitRequested);
dlg->setCurrentTab(tab);
dlg->setModel(clientModel->getOptionsModel());
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 658ab5a210..0ae5f7331e 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -137,7 +137,6 @@ private:
QAction* historyAction = nullptr;
QAction* quitAction = nullptr;
QAction* sendCoinsAction = nullptr;
- QAction* sendCoinsMenuAction = nullptr;
QAction* usedSendingAddressesAction = nullptr;
QAction* usedReceivingAddressesAction = nullptr;
QAction* signMessageAction = nullptr;
@@ -146,9 +145,7 @@ private:
QAction* m_load_psbt_clipboard_action = nullptr;
QAction* aboutAction = nullptr;
QAction* receiveCoinsAction = nullptr;
- QAction* receiveCoinsMenuAction = nullptr;
QAction* optionsAction = nullptr;
- QAction* toggleHideAction = nullptr;
QAction* encryptWalletAction = nullptr;
QAction* backupWalletAction = nullptr;
QAction* changePassphraseAction = nullptr;
@@ -302,13 +299,6 @@ public Q_SLOTS:
void showDebugWindowActivateConsole();
/** Show help message dialog */
void showHelpMessageClicked();
-#ifndef Q_OS_MAC
- /** Handle tray icon clicked */
- void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
-#else
- /** Handle macOS Dock icon clicked */
- void macosDockIconActivated();
-#endif
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
void showNormalIfMinimized() { showNormalIfMinimized(false); }
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index dc73bcd911..9565fa508f 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -984,7 +984,7 @@ void PrintSlotException(
PrintExceptionContinue(exception, description.c_str());
}
-void ShowModalDialogAndDeleteOnClose(QDialog* dialog)
+void ShowModalDialogAsynchronously(QDialog* dialog)
{
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setWindowModality(Qt::ApplicationModal);
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 9b25b77325..0224b18b4e 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -426,7 +426,7 @@ namespace GUIUtil
/**
* Shows a QDialog instance asynchronously, and deletes it on close.
*/
- void ShowModalDialogAndDeleteOnClose(QDialog* dialog);
+ void ShowModalDialogAsynchronously(QDialog* dialog);
inline bool IsEscapeOrBack(int key)
{
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index e37168830e..579ef0c3fd 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -930,7 +930,7 @@ void SendCoinsDialog::coinControlButtonClicked()
{
auto dlg = new CoinControlDialog(*m_coin_control, model, platformStyle);
connect(dlg, &QDialog::finished, this, &SendCoinsDialog::coinControlUpdateLabels);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
// Coin Control: checkbox custom change address
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 1ab1333b72..778ef04b77 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -511,7 +511,7 @@ void TransactionView::editLabel()
: EditAddressDialog::EditSendingAddress, this);
dlg->setModel(addressBook);
dlg->loadRow(idx);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
else
{
@@ -520,7 +520,7 @@ void TransactionView::editLabel()
this);
dlg->setModel(addressBook);
dlg->setAddress(address);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
}
}
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 08190f0b9f..91ce420a33 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -226,7 +226,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
auto dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel);
dlg->openWithPSBT(psbtx);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
void WalletFrame::encryptWallet()
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 7954a66995..e7ec54721a 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -208,7 +208,7 @@ void WalletView::encryptWallet()
auto dlg = new AskPassphraseDialog(AskPassphraseDialog::Encrypt, this);
dlg->setModel(walletModel);
connect(dlg, &QDialog::finished, this, &WalletView::encryptionStatusChanged);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
void WalletView::backupWallet()
@@ -235,16 +235,18 @@ void WalletView::changePassphrase()
{
auto dlg = new AskPassphraseDialog(AskPassphraseDialog::ChangePass, this);
dlg->setModel(walletModel);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ GUIUtil::ShowModalDialogAsynchronously(dlg);
}
void WalletView::unlockWallet()
{
// Unlock wallet when requested by wallet model
if (walletModel->getEncryptionStatus() == WalletModel::Locked) {
- auto dlg = new AskPassphraseDialog(AskPassphraseDialog::Unlock, this);
- dlg->setModel(walletModel);
- GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
+ AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
+ dlg.setModel(walletModel);
+ // A modal dialog must be synchronous here as expected
+ // in the WalletModel::requestUnlock() function.
+ dlg.exec();
}
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f18b800e23..9817c80cbd 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1417,7 +1417,7 @@ static RPCHelpMan verifychain()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int());
+ const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()};
const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()};
ChainstateManager& chainman = EnsureAnyChainman(request.context);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 0554367672..1d1ae92c58 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -217,9 +217,9 @@ static RPCHelpMan generatetodescriptor()
{
return RPCHelpMan{
"generatetodescriptor",
- "\nMine blocks immediately to a specified descriptor (before the RPC call returns)\n",
+ "Mine to a specified descriptor and return the block hashes.",
{
- {"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
+ {"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor to send the newly generated bitcoin to."},
{"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
},
@@ -261,18 +261,18 @@ static RPCHelpMan generate()
static RPCHelpMan generatetoaddress()
{
return RPCHelpMan{"generatetoaddress",
- "\nMine blocks immediately to a specified address (before the RPC call returns)\n",
- {
- {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
- {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
- },
- RPCResult{
- RPCResult::Type::ARR, "", "hashes of blocks generated",
- {
- {RPCResult::Type::STR_HEX, "", "blockhash"},
- }},
- RPCExamples{
+ "Mine to a specified address and return the block hashes.",
+ {
+ {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
+ {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
+ },
+ RPCResult{
+ RPCResult::Type::ARR, "", "hashes of blocks generated",
+ {
+ {RPCResult::Type::STR_HEX, "", "blockhash"},
+ }},
+ RPCExamples{
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
+ "If you are using the " PACKAGE_NAME " wallet, you can get a new address to send the newly generated bitcoin to with:\n"
@@ -302,7 +302,7 @@ static RPCHelpMan generatetoaddress()
static RPCHelpMan generateblock()
{
return RPCHelpMan{"generateblock",
- "\nMine a block with a set of ordered transactions immediately to a specified address or descriptor (before the RPC call returns)\n",
+ "Mine a set of ordered transactions to a specified address or descriptor and return the block hash.",
{
{"output", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated bitcoin to."},
{"transactions", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings which are either txids or raw transactions.\n"
@@ -1278,9 +1278,9 @@ static const CRPCCommand commands[] =
{ "mining", &submitheader, },
- { "generating", &generatetoaddress, },
- { "generating", &generatetodescriptor, },
- { "generating", &generateblock, },
+ { "hidden", &generatetoaddress, },
+ { "hidden", &generatetodescriptor, },
+ { "hidden", &generateblock, },
{ "util", &estimatesmartfee, },
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 84040bf847..798c4b3ea0 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -259,7 +259,15 @@ public:
bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
{
CKey key;
- if (!arg.GetKey(m_pubkey.GetID(), key)) return false;
+ if (m_xonly) {
+ for (const auto& keyid : XOnlyPubKey(m_pubkey).GetKeyIDs()) {
+ arg.GetKey(keyid, key);
+ if (key.IsValid()) break;
+ }
+ } else {
+ arg.GetKey(m_pubkey.GetID(), key);
+ }
+ if (!key.IsValid()) return false;
ret = EncodeSecret(key);
return true;
}
@@ -1253,7 +1261,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
{
if (ctx == ParseScriptContext::P2TR && script.size() == 34 && script[0] == 32 && script[33] == OP_CHECKSIG) {
XOnlyPubKey key{Span{script}.subspan(1, 32)};
- return std::make_unique<PKDescriptor>(InferXOnlyPubkey(key, ctx, provider));
+ return std::make_unique<PKDescriptor>(InferXOnlyPubkey(key, ctx, provider), true);
}
std::vector<std::vector<unsigned char>> data;
diff --git a/src/streams.h b/src/streams.h
index cf8b4eb96f..96b7696f72 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -9,6 +9,7 @@
#include <serialize.h>
#include <span.h>
#include <support/allocators/zeroafterfree.h>
+#include <util/overflow.h>
#include <algorithm>
#include <assert.h>
@@ -186,7 +187,7 @@ class CDataStream
protected:
using vector_type = SerializeData;
vector_type vch;
- unsigned int nReadPos{0};
+ vector_type::size_type m_read_pos{0};
int nType;
int nVersion;
@@ -229,37 +230,37 @@ public:
//
// Vector subset
//
- const_iterator begin() const { return vch.begin() + nReadPos; }
- iterator begin() { return vch.begin() + nReadPos; }
+ const_iterator begin() const { return vch.begin() + m_read_pos; }
+ iterator begin() { return vch.begin() + m_read_pos; }
const_iterator end() const { return vch.end(); }
iterator end() { return vch.end(); }
- size_type size() const { return vch.size() - nReadPos; }
- bool empty() const { return vch.size() == nReadPos; }
- void resize(size_type n, value_type c = value_type{}) { vch.resize(n + nReadPos, c); }
- void reserve(size_type n) { vch.reserve(n + nReadPos); }
- const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
- reference operator[](size_type pos) { return vch[pos + nReadPos]; }
- void clear() { vch.clear(); nReadPos = 0; }
- value_type* data() { return vch.data() + nReadPos; }
- const value_type* data() const { return vch.data() + nReadPos; }
+ size_type size() const { return vch.size() - m_read_pos; }
+ bool empty() const { return vch.size() == m_read_pos; }
+ void resize(size_type n, value_type c = value_type{}) { vch.resize(n + m_read_pos, c); }
+ void reserve(size_type n) { vch.reserve(n + m_read_pos); }
+ const_reference operator[](size_type pos) const { return vch[pos + m_read_pos]; }
+ reference operator[](size_type pos) { return vch[pos + m_read_pos]; }
+ void clear() { vch.clear(); m_read_pos = 0; }
+ value_type* data() { return vch.data() + m_read_pos; }
+ const value_type* data() const { return vch.data() + m_read_pos; }
inline void Compact()
{
- vch.erase(vch.begin(), vch.begin() + nReadPos);
- nReadPos = 0;
+ vch.erase(vch.begin(), vch.begin() + m_read_pos);
+ m_read_pos = 0;
}
bool Rewind(std::optional<size_type> n = std::nullopt)
{
// Total rewind if no size is passed
if (!n) {
- nReadPos = 0;
+ m_read_pos = 0;
return true;
}
// Rewind by n characters if the buffer hasn't been compacted yet
- if (*n > nReadPos)
+ if (*n > m_read_pos)
return false;
- nReadPos -= *n;
+ m_read_pos -= *n;
return true;
}
@@ -281,36 +282,32 @@ public:
if (dst.size() == 0) return;
// Read from the beginning of the buffer
- unsigned int nReadPosNext = nReadPos + dst.size();
- if (nReadPosNext > vch.size()) {
+ auto next_read_pos{CheckedAdd(m_read_pos, dst.size())};
+ if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
throw std::ios_base::failure("CDataStream::read(): end of data");
}
- memcpy(dst.data(), &vch[nReadPos], dst.size());
- if (nReadPosNext == vch.size())
- {
- nReadPos = 0;
+ memcpy(dst.data(), &vch[m_read_pos], dst.size());
+ if (next_read_pos.value() == vch.size()) {
+ m_read_pos = 0;
vch.clear();
return;
}
- nReadPos = nReadPosNext;
+ m_read_pos = next_read_pos.value();
}
- void ignore(int nSize)
+ void ignore(size_t num_ignore)
{
// Ignore from the beginning of the buffer
- if (nSize < 0) {
- throw std::ios_base::failure("CDataStream::ignore(): nSize negative");
+ auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)};
+ if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
+ throw std::ios_base::failure("CDataStream::ignore(): end of data");
}
- unsigned int nReadPosNext = nReadPos + nSize;
- if (nReadPosNext >= vch.size())
- {
- if (nReadPosNext > vch.size())
- throw std::ios_base::failure("CDataStream::ignore(): end of data");
- nReadPos = 0;
+ if (next_read_pos.value() == vch.size()) {
+ m_read_pos = 0;
vch.clear();
return;
}
- nReadPos = nReadPosNext;
+ m_read_pos = next_read_pos.value();
}
void write(Span<const value_type> src)
@@ -594,7 +591,7 @@ private:
FILE *src; //!< source file
uint64_t nSrcPos; //!< how many bytes have been read from source
- uint64_t nReadPos; //!< how many bytes have been read from this
+ uint64_t m_read_pos; //!< how many bytes have been read from this
uint64_t nReadLimit; //!< up to which position we're allowed to read
uint64_t nRewind; //!< how many bytes we guarantee to rewind
std::vector<std::byte> vchBuf; //!< the buffer
@@ -604,7 +601,7 @@ protected:
bool Fill() {
unsigned int pos = nSrcPos % vchBuf.size();
unsigned int readNow = vchBuf.size() - pos;
- unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
+ unsigned int nAvail = vchBuf.size() - (nSrcPos - m_read_pos) - nRewind;
if (nAvail < readNow)
readNow = nAvail;
if (readNow == 0)
@@ -619,7 +616,7 @@ protected:
public:
CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn)
- : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
+ : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), m_read_pos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})
{
if (nRewindIn >= nBufSize)
throw std::ios_base::failure("Rewind limit must be less than buffer size");
@@ -648,33 +645,33 @@ public:
//! check whether we're at the end of the source file
bool eof() const {
- return nReadPos == nSrcPos && feof(src);
+ return m_read_pos == nSrcPos && feof(src);
}
//! read a number of bytes
void read(Span<std::byte> dst)
{
- if (dst.size() + nReadPos > nReadLimit) {
+ if (dst.size() + m_read_pos > nReadLimit) {
throw std::ios_base::failure("Read attempted past buffer limit");
}
while (dst.size() > 0) {
- if (nReadPos == nSrcPos)
+ if (m_read_pos == nSrcPos)
Fill();
- unsigned int pos = nReadPos % vchBuf.size();
+ unsigned int pos = m_read_pos % vchBuf.size();
size_t nNow = dst.size();
if (nNow + pos > vchBuf.size())
nNow = vchBuf.size() - pos;
- if (nNow + nReadPos > nSrcPos)
- nNow = nSrcPos - nReadPos;
+ if (nNow + m_read_pos > nSrcPos)
+ nNow = nSrcPos - m_read_pos;
memcpy(dst.data(), &vchBuf[pos], nNow);
- nReadPos += nNow;
+ m_read_pos += nNow;
dst = dst.subspan(nNow);
}
}
//! return the current reading position
uint64_t GetPos() const {
- return nReadPos;
+ return m_read_pos;
}
//! rewind to a given reading position
@@ -682,22 +679,22 @@ public:
size_t bufsize = vchBuf.size();
if (nPos + bufsize < nSrcPos) {
// rewinding too far, rewind as far as possible
- nReadPos = nSrcPos - bufsize;
+ m_read_pos = nSrcPos - bufsize;
return false;
}
if (nPos > nSrcPos) {
// can't go this far forward, go as far as possible
- nReadPos = nSrcPos;
+ m_read_pos = nSrcPos;
return false;
}
- nReadPos = nPos;
+ m_read_pos = nPos;
return true;
}
//! prevent reading beyond a certain position
//! no argument removes the limit
bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
- if (nPos < nReadPos)
+ if (nPos < m_read_pos)
return false;
nReadLimit = nPos;
return true;
@@ -714,12 +711,12 @@ public:
void FindByte(uint8_t ch)
{
while (true) {
- if (nReadPos == nSrcPos)
+ if (m_read_pos == nSrcPos)
Fill();
- if (vchBuf[nReadPos % vchBuf.size()] == std::byte{ch}) {
+ if (vchBuf[m_read_pos % vchBuf.size()] == std::byte{ch}) {
break;
}
- nReadPos++;
+ m_read_pos++;
}
}
};
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 2f95cc27a3..fc89fe1450 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
// We're going to share this fs::path between two wrappers
fs::path ph = m_args.GetDataDirBase() / "existing_data_no_obfuscate";
- create_directories(ph);
+ fs::create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
@@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
// We're going to share this fs::path between two wrappers
fs::path ph = m_args.GetDataDirBase() / "existing_data_reindex";
- create_directories(ph);
+ fs::create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(ph, (1 << 10), false, false, false);
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index 5a3e382c3f..55a9a78159 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -43,6 +43,8 @@ constexpr int UNSOLVABLE = 4; // This descriptor is not expected to be solvable
constexpr int SIGNABLE = 8; // We can sign with this descriptor (this is not true when actual BIP32 derivation is used, as that's not integrated in our signing code)
constexpr int DERIVE_HARDENED = 16; // The final derivation is hardened, i.e. ends with *' or *h
constexpr int MIXED_PUBKEYS = 32;
+constexpr int XONLY_KEYS = 64; // X-only pubkeys are in use (and thus inferring/caching may swap parity of pubkeys/keyids)
+constexpr int MISSING_PRIVKEYS = 128; // Not all private keys are available, so ToPrivateString will fail.
/** Compare two descriptors. If only one of them has a checksum, the checksum is ignored. */
bool EqualDescriptor(std::string a, std::string b)
@@ -88,6 +90,42 @@ static size_t CountXpubs(const std::string& desc)
const std::set<std::vector<uint32_t>> ONLY_EMPTY{{}};
+std::set<CPubKey> GetKeyData(const FlatSigningProvider& provider, int flags) {
+ std::set<CPubKey> ret;
+ for (const auto& [_, pubkey] : provider.pubkeys) {
+ if (flags & XONLY_KEYS) {
+ unsigned char bytes[33];
+ BOOST_CHECK_EQUAL(pubkey.size(), 33);
+ std::copy(pubkey.begin(), pubkey.end(), bytes);
+ bytes[0] = 0x02;
+ CPubKey norm_pubkey{bytes};
+ ret.insert(norm_pubkey);
+ } else {
+ ret.insert(pubkey);
+ }
+ }
+ return ret;
+}
+
+std::set<std::pair<CPubKey, KeyOriginInfo>> GetKeyOriginData(const FlatSigningProvider& provider, int flags) {
+ std::set<std::pair<CPubKey, KeyOriginInfo>> ret;
+ for (const auto& [_, data] : provider.origins) {
+ if (flags & XONLY_KEYS) {
+ unsigned char bytes[33];
+ BOOST_CHECK_EQUAL(data.first.size(), 33);
+ std::copy(data.first.begin(), data.first.end(), bytes);
+ bytes[0] = 0x02;
+ CPubKey norm_pubkey{bytes};
+ KeyOriginInfo norm_origin = data.second;
+ std::fill(std::begin(norm_origin.fingerprint), std::end(norm_origin.fingerprint), 0); // fingerprints don't necessarily match.
+ ret.emplace(norm_pubkey, norm_origin);
+ } else {
+ ret.insert(data);
+ }
+ }
+ return ret;
+}
+
void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY,
bool replace_apostrophe_with_h_in_prv=false, bool replace_apostrophe_with_h_in_pub=false)
{
@@ -127,13 +165,15 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
BOOST_CHECK(EqualDescriptor(pub, pub2));
// Check that both can be serialized with private key back to the private version, but not without private key.
- std::string prv1;
- BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1));
- BOOST_CHECK(EqualDescriptor(prv, prv1));
- BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1));
- BOOST_CHECK(parse_pub->ToPrivateString(keys_priv, prv1));
- BOOST_CHECK(EqualDescriptor(prv, prv1));
- BOOST_CHECK(!parse_pub->ToPrivateString(keys_pub, prv1));
+ if (!(flags & MISSING_PRIVKEYS)) {
+ std::string prv1;
+ BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1));
+ BOOST_CHECK(EqualDescriptor(prv, prv1));
+ BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1));
+ BOOST_CHECK(parse_pub->ToPrivateString(keys_priv, prv1));
+ BOOST_CHECK(EqualDescriptor(prv, prv1));
+ BOOST_CHECK(!parse_pub->ToPrivateString(keys_pub, prv1));
+ }
// Check that private can produce the normalized descriptors
std::string norm1;
@@ -177,9 +217,9 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
// Try to expand again using cached data, and compare.
BOOST_CHECK(parse_pub->ExpandFromCache(i, desc_cache, spks_cached, script_provider_cached));
BOOST_CHECK(spks == spks_cached);
- BOOST_CHECK(script_provider.pubkeys == script_provider_cached.pubkeys);
+ BOOST_CHECK(GetKeyData(script_provider, flags) == GetKeyData(script_provider_cached, flags));
BOOST_CHECK(script_provider.scripts == script_provider_cached.scripts);
- BOOST_CHECK(script_provider.origins == script_provider_cached.origins);
+ BOOST_CHECK(GetKeyOriginData(script_provider, flags) == GetKeyOriginData(script_provider_cached, flags));
// Check whether keys are in the cache
const auto& der_xpub_cache = desc_cache.GetCachedDerivedExtPubKeys();
@@ -255,9 +295,9 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
// Try again but use the cache from expanding i. That cache won't have the pubkeys for i + 1, but will have the parent xpub for derivation.
BOOST_CHECK(parse_pub->ExpandFromCache(i + 1, desc_cache, spk1_from_cache, script_provider_cached1));
BOOST_CHECK(spks1 == spk1_from_cache);
- BOOST_CHECK(script_provider1.pubkeys == script_provider_cached1.pubkeys);
+ BOOST_CHECK(GetKeyData(script_provider1, flags) == GetKeyData(script_provider_cached1, flags));
BOOST_CHECK(script_provider1.scripts == script_provider_cached1.scripts);
- BOOST_CHECK(script_provider1.origins == script_provider_cached1.origins);
+ BOOST_CHECK(GetKeyOriginData(script_provider1, flags) == GetKeyOriginData(script_provider_cached1, flags));
}
// For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it.
@@ -269,7 +309,12 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
CMutableTransaction spend;
spend.vin.resize(1);
spend.vout.resize(1);
- BOOST_CHECK_MESSAGE(SignSignature(Merge(keys_priv, script_provider), spks[n], spend, 0, 1, SIGHASH_ALL), prv);
+ std::vector<CTxOut> utxos(1);
+ PrecomputedTransactionData txdata;
+ txdata.Init(spend, std::move(utxos), /* force */ true);
+ MutableTransactionSignatureCreator creator(&spend, 0, CAmount{0}, &txdata, SIGHASH_DEFAULT);
+ SignatureData sigdata;
+ BOOST_CHECK_MESSAGE(ProduceSignature(Merge(keys_priv, script_provider), creator, spks[n], sigdata), prv);
}
/* Infer a descriptor from the generated script, and verify its solvability and that it roundtrips. */
@@ -281,7 +326,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
BOOST_CHECK_EQUAL(spks_inferred.size(), 1U);
BOOST_CHECK(spks_inferred[0] == spks[n]);
BOOST_CHECK_EQUAL(IsSolvable(provider_inferred, spks_inferred[0]), !(flags & UNSOLVABLE));
- BOOST_CHECK(provider_inferred.origins == script_provider.origins);
+ BOOST_CHECK(GetKeyOriginData(provider_inferred, flags) == GetKeyOriginData(script_provider, flags));
}
// Test whether the observed key path is present in the 'paths' variable (which contains expected, unobserved paths),
@@ -335,6 +380,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, {{1,0x80000002UL,3,0x80000004UL}});
Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32);
Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT);
+ Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE | XONLY_KEYS, {{"512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11"}}, OutputType::BECH32M);
CheckUnparsable("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY2))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5))", "Pubkey '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5' is invalid"); // Invalid pubkey
CheckUnparsable("pkh(deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh(deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "Key origin start '[ character expected but not found, got 'd' instead"); // Missing start bracket in key origin
CheckUnparsable("pkh([deadbeef]/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef]/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "Multiple ']' characters found for a single pubkey"); // Multiple end brackets in key origin
@@ -354,6 +400,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check("wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"0020338e023079b91c58571b20e602d7805fb808c22473cbc391a41b1bd3a192e75b"}}, OutputType::BECH32);
Check("sh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a91472d0c5a3bfad8c3e7bd5303a72b94240e80b6f1787"}}, OutputType::P2SH_SEGWIT);
Check("sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a914b61b92e2ca21bac1e72a3ab859a742982bea960a87"}}, OutputType::P2SH_SEGWIT);
+ Check("tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", XONLY_KEYS | SIGNABLE | MISSING_PRIVKEYS, {{"51201497ae16f30dacb88523ed9301bff17773b609e8a90518a3f96ea328a47d1500"}}, OutputType::BECH32M);
// Versions with BIP32 derivations
Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt);
@@ -362,6 +409,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, {{0}, {1}});
+ Check("tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", "tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", XONLY_KEYS | RANGE, {{"512078bc707124daa551b65af74de2ec128b7525e10f374dc67b64e00ce0ab8b3e12"}, {"512001f0a02a17808c20134b78faab80ef93ffba82261ccef0a2314f5d62b6438f11"}, {"512021024954fcec88237a9386fce80ef2ced5f1e91b422b26c59ccfc174c8d1ad25"}}, OutputType::BECH32M, {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}});
// Mixed xpubs and const pubkeys
Check("wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))","wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", MIXED_PUBKEYS, {{"0020cb155486048b23a6da976d4c6fe071a2dbc8a7b57aaf225b8955f2e2a27b5f00"}},OutputType::BECH32,{{0},{}});
// Mixed range xpubs and const pubkeys
@@ -380,6 +428,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, std::nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}});
Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xprv9vHkqa6XAPwKqSKSEJMcAB3yoCZhaSVsGZbSkFY5L3Lfjjk8sjZucbsbvEw5o3QrSA69nPfZDCgFnNnLhQ2ohpZuwummndnPasDw2Qr6dC2/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", "sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}}, OutputType::P2SH_SEGWIT);
+ Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754"}}, OutputType::BECH32M);
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript
CheckUnparsable("wsh(multi(2,[aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa][aaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multiple ']' characters found for a single pubkey"); // Double key origin descriptor
CheckUnparsable("wsh(multi(2,[aaaagaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaagaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Fingerprint 'aaagaaaa' is not hex"); // Non hex fingerprint
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 1256395849..313064b294 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -118,4 +118,62 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
}
}
-BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
+BOOST_AUTO_TEST_CASE(rename)
+{
+ const fs::path tmpfolder{m_args.GetDataDirBase()};
+
+ const fs::path path1{GetUniquePath(tmpfolder)};
+ const fs::path path2{GetUniquePath(tmpfolder)};
+
+ const std::string path1_contents{"1111"};
+ const std::string path2_contents{"2222"};
+
+ {
+ std::ofstream file{path1};
+ file << path1_contents;
+ }
+
+ {
+ std::ofstream file{path2};
+ file << path2_contents;
+ }
+
+ // Rename path1 -> path2.
+ BOOST_CHECK(RenameOver(path1, path2));
+
+ BOOST_CHECK(!fs::exists(path1));
+
+ {
+ std::ifstream file{path2};
+ std::string contents;
+ file >> contents;
+ BOOST_CHECK_EQUAL(contents, path1_contents);
+ }
+ fs::remove(path2);
+}
+
+#ifndef WIN32
+BOOST_AUTO_TEST_CASE(create_directories)
+{
+ // Test fs::create_directories workaround.
+ const fs::path tmpfolder{m_args.GetDataDirBase()};
+
+ const fs::path dir{GetUniquePath(tmpfolder)};
+ fs::create_directory(dir);
+ BOOST_CHECK(fs::exists(dir));
+ BOOST_CHECK(fs::is_directory(dir));
+ BOOST_CHECK(!fs::create_directories(dir));
+
+ const fs::path symlink{GetUniquePath(tmpfolder)};
+ fs::create_directory_symlink(dir, symlink);
+ BOOST_CHECK(fs::exists(symlink));
+ BOOST_CHECK(fs::is_symlink(symlink));
+ BOOST_CHECK(fs::is_directory(symlink));
+ BOOST_CHECK(!fs::create_directories(symlink));
+
+ fs::remove(symlink);
+ fs::remove(dir);
+}
+#endif // WIN32
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 14a59912db..fdcd0da37d 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -167,12 +167,4 @@ FUZZ_TARGET_INIT(script, initialize_script)
Assert(dest == GetScriptForDestination(tx_destination_2));
}
}
-
- (void)FormatScript(script);
- (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool());
-
- UniValue o1(UniValue::VOBJ);
- ScriptPubKeyToUniv(script, o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool());
- UniValue o3(UniValue::VOBJ);
- ScriptToUniv(script, o3);
}
diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp
new file mode 100644
index 0000000000..2fa893f812
--- /dev/null
+++ b/src/test/fuzz/script_format.cpp
@@ -0,0 +1,30 @@
+// Copyright (c) 2019-2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <chainparams.h>
+#include <core_io.h>
+#include <script/script.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <univalue.h>
+
+void initialize_script_format()
+{
+ SelectParams(CBaseChainParams::REGTEST);
+}
+
+FUZZ_TARGET_INIT(script_format, initialize_script_format)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const CScript script{ConsumeScript(fuzzed_data_provider)};
+
+ (void)FormatScript(script);
+ (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool());
+
+ UniValue o1(UniValue::VOBJ);
+ ScriptPubKeyToUniv(script, o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool());
+ UniValue o3(UniValue::VOBJ);
+ ScriptToUniv(script, o3);
+}
diff --git a/src/util/overflow.h b/src/util/overflow.h
index 5982af8d04..c70a8b663e 100644
--- a/src/util/overflow.h
+++ b/src/util/overflow.h
@@ -6,6 +6,7 @@
#define BITCOIN_UTIL_OVERFLOW_H
#include <limits>
+#include <optional>
#include <type_traits>
template <class T>
diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp
index 4157be9d9f..f2a9cf664d 100644
--- a/src/util/syscall_sandbox.cpp
+++ b/src/util/syscall_sandbox.cpp
@@ -68,6 +68,10 @@ bool g_syscall_sandbox_log_violation_before_terminating{false};
#define __NR_copy_file_range 326
#endif
+#ifndef __NR_rseq
+#define __NR_rseq 334
+#endif
+
// This list of syscalls in LINUX_SYSCALLS is only used to map syscall numbers to syscall names in
// order to be able to print user friendly error messages which include the syscall name in addition
// to the syscall number.
@@ -327,6 +331,7 @@ const std::map<uint32_t, std::string> LINUX_SYSCALLS{
{__NR_request_key, "request_key"},
{__NR_restart_syscall, "restart_syscall"},
{__NR_rmdir, "rmdir"},
+ {__NR_rseq, "rseq"},
{__NR_rt_sigaction, "rt_sigaction"},
{__NR_rt_sigpending, "rt_sigpending"},
{__NR_rt_sigprocmask, "rt_sigprocmask"},
@@ -600,6 +605,7 @@ public:
allowed_syscalls.insert(__NR_statfs); // get filesystem statistics
allowed_syscalls.insert(__NR_statx); // get file status (extended)
allowed_syscalls.insert(__NR_unlink); // delete a name and possibly the file it refers to
+ allowed_syscalls.insert(__NR_unlinkat); // delete relative to a directory file descriptor
}
void AllowFutex()
@@ -722,6 +728,7 @@ public:
allowed_syscalls.insert(__NR_fork); // create a child process
allowed_syscalls.insert(__NR_tgkill); // send a signal to a thread
allowed_syscalls.insert(__NR_wait4); // wait for process to change state, BSD style
+ allowed_syscalls.insert(__NR_rseq); // register restartable sequence for thread
}
void AllowScheduling()
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 5cef2be07a..69811a751b 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1062,9 +1062,20 @@ void ArgsManager::LogArgs() const
bool RenameOver(fs::path src, fs::path dest)
{
+#ifdef __MINGW64__
+ // This is a workaround for a bug in libstdc++ which
+ // implements std::filesystem::rename with _wrename function.
+ // This bug has been fixed in upstream:
+ // - GCC 10.3: 8dd1c1085587c9f8a21bb5e588dfe1e8cdbba79e
+ // - GCC 11.1: 1dfd95f0a0ca1d9e6cbc00e6cbfd1fa20a98f312
+ // For more details see the commits mentioned above.
+ return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
+ MOVEFILE_REPLACE_EXISTING) != 0;
+#else
std::error_code error;
fs::rename(src, dest, error);
return !error;
+#endif
}
/**
diff --git a/src/validation.cpp b/src/validation.cpp
index e20e2fe523..2813b62462 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -286,8 +286,10 @@ bool CheckSequenceLocks(CBlockIndex* tip,
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams);
static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age)
- EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
{
+ AssertLockHeld(::cs_main);
+ AssertLockHeld(pool.cs);
int expired = pool.Expire(GetTime<std::chrono::seconds>() - age);
if (expired != 0) {
LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired);
@@ -628,8 +630,10 @@ private:
EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Compare a package's feerate against minimum allowed.
- bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs)
+ bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs)
{
+ AssertLockHeld(::cs_main);
+ AssertLockHeld(m_pool.cs);
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
@@ -663,6 +667,8 @@ private:
bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(m_pool.cs);
const CTransactionRef& ptx = ws.m_ptx;
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
@@ -963,6 +969,8 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx;
TxValidationState& state = ws.m_state;
@@ -989,6 +997,8 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
TxValidationState& state = ws.m_state;
@@ -1021,6 +1031,8 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
TxValidationState& state = ws.m_state;
@@ -1342,8 +1354,9 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx,
int64_t accept_time, bool bypass_limits, bool test_accept)
- EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
+ AssertLockHeld(::cs_main);
const CChainParams& chainparams{active_chainstate.m_params};
assert(active_chainstate.GetMempool() != nullptr);
CTxMemPool& pool{*active_chainstate.GetMempool()};
@@ -1421,6 +1434,7 @@ CoinsViews::CoinsViews(
void CoinsViews::InitCache()
{
+ AssertLockHeld(::cs_main);
m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview);
}
@@ -1451,6 +1465,7 @@ void CChainState::InitCoinsDB(
void CChainState::InitCoinsCache(size_t cache_size_bytes)
{
+ AssertLockHeld(::cs_main);
assert(m_coins_views != nullptr);
m_coinstip_cache_size_bytes = cache_size_bytes;
m_coins_views->InitCache();
@@ -1524,6 +1539,7 @@ void CChainState::CheckForkWarningConditions()
// Called both upon regular invalid block discovery *and* InvalidateBlock
void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
{
+ AssertLockHeld(cs_main);
if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
m_chainman.m_best_invalid = pindexNew;
}
@@ -1546,6 +1562,7 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
// which does its own setBlockIndexCandidates management.
void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state)
{
+ AssertLockHeld(cs_main);
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID;
m_chainman.m_failed_blocks.insert(pindex);
@@ -1906,7 +1923,10 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
{
AssertLockHeld(cs_main);
assert(pindex);
- assert(*pindex->phashBlock == block.GetHash());
+
+ uint256 block_hash{block.GetHash()};
+ assert(*pindex->phashBlock == block_hash);
+
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
@@ -1940,7 +1960,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
- if (block.GetHash() == m_params.GetConsensus().hashGenesisBlock) {
+ if (block_hash == m_params.GetConsensus().hashGenesisBlock) {
if (!fJustCheck)
view.SetBestBlock(pindex->GetBlockHash());
return true;
@@ -2197,12 +2217,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
TRACE6(validation, block_connected,
- block.GetHash().data(),
+ block_hash.data(),
pindex->nHeight,
block.vtx.size(),
nInputs,
nSigOpsCost,
- GetTimeMicros() - nTimeStart // in microseconds (µs)
+ nTime5 - nTimeStart // in microseconds (µs)
);
return true;
@@ -2210,6 +2230,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
CoinsCacheSizeState CChainState::GetCoinsCacheSizeState()
{
+ AssertLockHeld(::cs_main);
return this->GetCoinsCacheSizeState(
m_coinstip_cache_size_bytes,
gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
@@ -2219,6 +2240,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState(
size_t max_coins_cache_size_bytes,
size_t max_mempool_size_bytes)
{
+ AssertLockHeld(::cs_main);
const int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0;
int64_t cacheSize = CoinsTip().DynamicMemoryUsage();
int64_t nTotalSpace =
@@ -2351,14 +2373,13 @@ bool CChainState::FlushStateToDisk(
return AbortNode(state, "Failed to write to coin database");
nLastFlush = nNow;
full_flush_completed = true;
+ TRACE5(utxocache, flush,
+ (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
+ (u_int32_t)mode,
+ (u_int64_t)coins_count,
+ (u_int64_t)coins_mem_usage,
+ (bool)fFlushForPrune);
}
- TRACE6(utxocache, flush,
- (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
- (u_int32_t)mode,
- (u_int64_t)coins_count,
- (u_int64_t)coins_mem_usage,
- (bool)fFlushForPrune,
- (bool)fDoFullFlush);
}
if (full_flush_completed) {
// Update best block in wallet (so we can detect restored wallets).
@@ -2427,6 +2448,7 @@ static void UpdateTipLog(
void CChainState::UpdateTip(const CBlockIndex* pindexNew)
{
+ AssertLockHeld(::cs_main);
const auto& coins_tip = this->CoinsTip();
// The remainder of the function isn't relevant if we are not acting on
@@ -2650,7 +2672,9 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
* Return the tip of the chain with the most work in it, that isn't
* known to be invalid (it's however far from certain to be valid).
*/
-CBlockIndex* CChainState::FindMostWorkChain() {
+CBlockIndex* CChainState::FindMostWorkChain()
+{
+ AssertLockHeld(::cs_main);
do {
CBlockIndex *pindexNew = nullptr;
@@ -2854,7 +2878,7 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr
// far from a guarantee. Things in the P2P/RPC will often end up calling
// us in the middle of ProcessNewBlock - do not assume pblock is set
// sanely for performance or correctness!
- AssertLockNotHeld(cs_main);
+ AssertLockNotHeld(::cs_main);
// ABC maintains a fair degree of expensive-to-calculate internal state
// because this function periodically releases cs_main so that it does not lock up other threads for too long
@@ -2950,6 +2974,8 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr
bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
{
+ AssertLockNotHeld(m_chainstate_mutex);
+ AssertLockNotHeld(::cs_main);
{
LOCK(cs_main);
if (pindex->nChainWork < m_chain.Tip()->nChainWork) {
@@ -2980,6 +3006,7 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex
bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex)
{
AssertLockNotHeld(m_chainstate_mutex);
+ AssertLockNotHeld(::cs_main);
// Genesis block can't be invalidated
assert(pindex);
@@ -3158,6 +3185,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos)
{
+ AssertLockHeld(cs_main);
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
pindexNew->nFile = pos.nFile;
@@ -3330,8 +3358,9 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
* in ConnectBlock().
* Note that -reindex-chainstate skips the validation that happens here!
*/
-static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
+ AssertLockHeld(::cs_main);
assert(pindexPrev != nullptr);
const int nHeight = pindexPrev->nHeight + 1;
@@ -3702,6 +3731,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept)
{
+ AssertLockHeld(cs_main);
CChainState& active_chainstate = ActiveChainstate();
if (!active_chainstate.GetMempool()) {
TxValidationState state;
@@ -3915,6 +3945,7 @@ bool CVerifyDB::VerifyDB(
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs)
{
+ AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock
CBlock block;
if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) {
@@ -4018,7 +4049,9 @@ bool CChainState::NeedsRedownload() const
return false;
}
-void CChainState::UnloadBlockIndex() {
+void CChainState::UnloadBlockIndex()
+{
+ AssertLockHeld(::cs_main);
nBlockSequenceId = 1;
setBlockIndexCandidates.clear();
}
@@ -4090,6 +4123,7 @@ bool CChainState::LoadGenesisBlock()
void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp)
{
+ AssertLockNotHeld(m_chainstate_mutex);
// Map of disk positions for blocks with unknown parent (only used for reindex)
static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent;
int64_t nStart = GetTimeMillis();
@@ -4430,6 +4464,7 @@ void CChainState::CheckBlockIndex()
std::string CChainState::ToString()
{
+ AssertLockHeld(::cs_main);
CBlockIndex* tip = m_chain.Tip();
return strprintf("Chainstate [%s] @ height %d (%s)",
m_from_snapshot_blockhash ? "snapshot" : "ibd",
@@ -4438,6 +4473,7 @@ std::string CChainState::ToString()
bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
{
+ AssertLockHeld(::cs_main);
if (coinstip_size == m_coinstip_cache_size_bytes &&
coinsdb_size == m_coinsdb_cache_size_bytes) {
// Cache sizes are unchanged, no need to continue.
@@ -4662,6 +4698,7 @@ std::vector<CChainState*> ChainstateManager::GetAll()
CChainState& ChainstateManager::InitializeChainstate(
CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash)
{
+ AssertLockHeld(::cs_main);
bool is_snapshot = snapshot_blockhash.has_value();
std::unique_ptr<CChainState>& to_modify =
is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate;
@@ -4999,6 +5036,7 @@ bool ChainstateManager::IsSnapshotActive() const
void ChainstateManager::Unload()
{
+ AssertLockHeld(::cs_main);
for (CChainState* chainstate : this->GetAll()) {
chainstate->m_chain.SetTip(nullptr);
chainstate->UnloadBlockIndex();
@@ -5020,6 +5058,7 @@ void ChainstateManager::Reset()
void ChainstateManager::MaybeRebalanceCaches()
{
+ AssertLockHeld(::cs_main);
if (m_ibd_chainstate && !m_snapshot_chainstate) {
LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n");
// Allocate everything to the IBD chainstate.
diff --git a/src/validation.h b/src/validation.h
index fdfd29d1f8..7766d77a88 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -90,7 +90,7 @@ static const int DEFAULT_STOPATHEIGHT = 0;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
-static const unsigned int DEFAULT_CHECKLEVEL = 3;
+static constexpr int DEFAULT_CHECKLEVEL{3};
// Require that user allocate at least 550 MiB for block & undo files (blk???.dat and rev???.dat)
// At 1MB per block, 288 blocks = 288MB.
// Add 15% for Undo data = 331MB
@@ -529,7 +529,9 @@ public:
//! @returns whether or not the CoinsViews object has been fully initialized and we can
//! safely flush this object to disk.
- bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
+ bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+ {
+ AssertLockHeld(::cs_main);
return m_coins_views && m_coins_views->m_cacheview;
}
@@ -557,15 +559,17 @@ public:
std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates;
//! @returns A reference to the in-memory cache of the UTXO set.
- CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
+ AssertLockHeld(::cs_main);
assert(m_coins_views->m_cacheview);
return *m_coins_views->m_cacheview.get();
}
//! @returns A reference to the on-disk UTXO set database.
- CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
+ AssertLockHeld(::cs_main);
return m_coins_views->m_dbview;
}
@@ -577,8 +581,9 @@ public:
//! @returns A reference to a wrapped view of the in-memory UTXO set that
//! handles disk read errors gracefully.
- CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
+ AssertLockHeld(::cs_main);
return m_coins_views->m_catcherview;
}
@@ -924,6 +929,7 @@ public:
node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
+ AssertLockHeld(::cs_main);
return m_blockman.m_block_index;
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 8ef0d46c4f..7693c9c0e8 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -426,7 +426,7 @@ BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
// Test some watch-only LegacyScriptPubKeyMan methods by the procedure of loading (LoadWatchOnly),
// checking (HaveWatchOnly), getting (GetWatchPubKey) and removing (RemoveWatchOnly) a
-// given PubKey, resp. its corresponding P2PK Script. Results of the the impact on
+// given PubKey, resp. its corresponding P2PK Script. Results of the impact on
// the address -> PubKey map is dependent on whether the PubKey is a point on the curve
static void TestWatchOnlyPubKey(LegacyScriptPubKeyMan* spk_man, const CPubKey& add_pubkey)
{
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 7e694d1987..6549a2146b 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1027,7 +1027,8 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
if (!fill_wtx(wtx, ins.second)) {
return false;
}
- // If wallet doesn't have a chain (e.g wallet-tool), don't bother to update txn.
+ // If wallet doesn't have a chain (e.g when using bitcoin-wallet tool),
+ // don't bother to update txn.
if (HaveChain()) {
bool active;
auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {
diff --git a/test/functional/feature_dirsymlinks.py b/test/functional/feature_dirsymlinks.py
new file mode 100755
index 0000000000..85c8e27600
--- /dev/null
+++ b/test/functional/feature_dirsymlinks.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test successful startup with symlinked directories.
+"""
+
+import os
+import sys
+
+from test_framework.test_framework import BitcoinTestFramework, SkipTest
+
+
+def rename_and_link(*, from_name, to_name):
+ os.rename(from_name, to_name)
+ os.symlink(to_name, from_name)
+ assert os.path.islink(from_name) and os.path.isdir(from_name)
+
+class SymlinkTest(BitcoinTestFramework):
+ def skip_test_if_missing_module(self):
+ if sys.platform == 'win32':
+ raise SkipTest("Symlinks test skipped on Windows")
+
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ self.stop_node(0)
+
+ rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "blocks"),
+ to_name=os.path.join(self.nodes[0].datadir, self.chain, "newblocks"))
+ rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "chainstate"),
+ to_name=os.path.join(self.nodes[0].datadir, self.chain, "newchainstate"))
+
+ self.start_node(0)
+
+
+if __name__ == '__main__':
+ SymlinkTest().main()
diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py
index dbd71a8b2d..d0cb1e10e2 100755
--- a/test/functional/feature_init.py
+++ b/test/functional/feature_init.py
@@ -64,6 +64,8 @@ class InitStressTest(BitcoinTestFramework):
'addcon thread start',
'loadblk thread start',
'txindex thread start',
+ 'block filter index thread start',
+ 'coinstatsindex thread start',
'msghand thread start',
'net thread start',
'addcon thread start',
@@ -74,7 +76,7 @@ class InitStressTest(BitcoinTestFramework):
for terminate_line in lines_to_terminate_after:
self.log.info(f"Starting node and will exit after line '{terminate_line}'")
with node.wait_for_debug_log([terminate_line], ignore_case=True):
- node.start(extra_args=['-txindex=1'])
+ node.start(extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'])
self.log.debug("Terminating node after terminate line was found")
sigterm_node()
@@ -109,7 +111,7 @@ class InitStressTest(BitcoinTestFramework):
# investigate doing this later.
node.assert_start_raises_init_error(
- extra_args=['-txindex=1'],
+ extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'],
expected_msg=err_fragment,
match=ErrorMatch.PARTIAL_REGEX,
)
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
index ccb380e25b..3b6413d4a6 100755
--- a/test/functional/rpc_help.py
+++ b/test/functional/rpc_help.py
@@ -100,7 +100,7 @@ class HelpRpcTest(BitcoinTestFramework):
# command titles
titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
- components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util']
+ components = ['Blockchain', 'Control', 'Mining', 'Network', 'Rawtransactions', 'Util']
if self.is_wallet_compiled():
components.append('Wallet')
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index 013522a5e1..c7fbf679b6 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -55,17 +55,15 @@ def create_deterministic_address_bcrt1_p2tr_op_true():
def byte_to_base58(b, version):
result = ''
- str = b.hex()
- str = chr(version).encode('latin-1').hex() + str
- checksum = hash256(bytes.fromhex(str)).hex()
- str += checksum[:8]
- value = int('0x' + str, 0)
+ b = bytes([version]) + b # prepend version
+ b += hash256(b)[:4] # append checksum
+ value = int.from_bytes(b, 'big')
while value > 0:
result = chars[value % 58] + result
value //= 58
- while (str[:2] == '00'):
+ while b[0] == 0:
result = chars[0] + result
- str = str[2:]
+ b = b[1:]
return result
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index 174dc44a2a..b64f66e69b 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -144,7 +144,6 @@ def test_ipv6_local():
'''
Check for (local) IPv6 support.
'''
- import socket
# By using SOCK_DGRAM this will not actually make a connection, but it will
# fail if there is no route to IPv6 localhost.
have_ipv6 = True
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1a0d62aa8f..516e8be638 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -321,6 +321,7 @@ BASE_SCRIPTS = [
'rpc_getdescriptorinfo.py',
'rpc_mempool_entry_fee_fields_deprecation.py',
'rpc_help.py',
+ 'feature_dirsymlinks.py',
'feature_help.py',
'feature_shutdown.py',
'p2p_ibd_txrelay.py',
diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan
index ed8c75d617..26f3fdc7af 100644
--- a/test/sanitizer_suppressions/tsan
+++ b/test/sanitizer_suppressions/tsan
@@ -22,10 +22,6 @@ deadlock:sync_tests::potential_deadlock_detected
race:src/qt/test/*
deadlock:src/qt/test/*
-# Race in src/test/main.cpp
-# Can be removed once upgraded to boost test 1.74 in depends
-race:validation_chainstatemanager_tests
-
# External libraries
deadlock:libdb
race:libzmq