diff options
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) { @@ -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 |