aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--.gitignore2
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--Makefile.am10
-rw-r--r--build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj1
-rwxr-xr-xci/lint/04_install.sh2
-rwxr-xr-xci/test/00_setup_env_i686_multiprocess.sh2
-rwxr-xr-xci/test/00_setup_env_native_asan.sh4
-rwxr-xr-xci/test/00_setup_env_native_fuzz.sh6
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_msan.sh2
-rwxr-xr-xci/test/00_setup_env_native_msan.sh2
-rwxr-xr-xci/test/00_setup_env_native_previous_releases.sh2
-rwxr-xr-xci/test/00_setup_env_native_tidy.sh2
-rwxr-xr-xci/test/00_setup_env_native_tsan.sh6
-rwxr-xr-xci/test/01_base_install.sh2
-rw-r--r--configure.ac45
-rwxr-xr-xcontrib/guix/libexec/build.sh26
-rw-r--r--contrib/guix/manifest.scm7
-rw-r--r--contrib/guix/patches/glibc-2.27-fcommon.patch2
-rw-r--r--depends/hosts/darwin.mk2
-rw-r--r--depends/hosts/linux.mk8
-rw-r--r--depends/hosts/mingw32.mk2
-rw-r--r--depends/packages/expat.mk2
-rw-r--r--depends/packages/libmultiprocess.mk2
-rw-r--r--depends/packages/qrencode.mk16
-rw-r--r--depends/packages/qt.mk11
-rw-r--r--depends/packages/sqlite.mk1
-rw-r--r--depends/patches/qrencode/cmake_fixups.patch23
-rw-r--r--depends/patches/qt/fix_android_jni_static.patch1
-rw-r--r--depends/patches/qt/memory_resource.patch2
-rw-r--r--depends/patches/qt/use_android_ndk23.patch13
-rw-r--r--doc/README.md1
-rw-r--r--doc/build-unix.md4
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/design/libraries.md9
-rw-r--r--doc/developer-notes.md2
-rw-r--r--doc/dnsseed-policy.md2
-rw-r--r--doc/release-notes/release-notes-25.2.md74
-rw-r--r--doc/release-notes/release-notes-26.1.md106
-rw-r--r--doc/shared-libraries.md78
-rw-r--r--libbitcoinconsensus.pc.in10
-rw-r--r--src/.clang-tidy1
-rw-r--r--src/Makefile.am19
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/bench/bip324_ecdh.cpp2
-rw-r--r--src/bench/ellswift.cpp2
-rw-r--r--src/bench/verify_script.cpp18
-rw-r--r--src/bitcoin-cli.cpp5
-rw-r--r--src/blockencodings.cpp15
-rw-r--r--src/blockencodings.h4
-rw-r--r--src/crypto/chacha20poly1305.cpp13
-rw-r--r--src/crypto/sha256.cpp4
-rw-r--r--src/cuckoocache.h2
-rw-r--r--src/index/base.cpp2
-rw-r--r--src/kernel/chainparams.cpp2
-rw-r--r--src/kernel/checks.cpp5
-rw-r--r--src/kernel/mempool_persist.cpp23
-rw-r--r--src/key.h6
-rw-r--r--src/logging.cpp190
-rw-r--r--src/logging.h9
-rw-r--r--src/merkleblock.cpp3
-rw-r--r--src/net_processing.cpp4
-rw-r--r--src/node/interfaces.cpp1
-rw-r--r--src/policy/rbf.cpp4
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/randomenv.cpp10
-rw-r--r--src/rpc/client.cpp5
-rw-r--r--src/rpc/util.cpp6
-rw-r--r--src/rpc/util.h2
-rw-r--r--src/script/bitcoinconsensus.cpp157
-rw-r--r--src/script/bitcoinconsensus.h96
-rw-r--r--src/script/descriptor.cpp51
-rw-r--r--src/script/descriptor.h7
-rw-r--r--src/script/miniscript.h2
-rw-r--r--src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml2
-rw-r--r--src/secp256k1/.github/actions/run-in-docker-action/action.yml5
-rw-r--r--src/secp256k1/CMakeLists.txt41
-rw-r--r--src/secp256k1/CONTRIBUTING.md2
-rw-r--r--src/secp256k1/README.md6
-rwxr-xr-xsrc/secp256k1/ci/ci.sh3
-rw-r--r--src/secp256k1/cmake/AllTargetsCompileOptions.cmake12
-rw-r--r--src/secp256k1/configure.ac29
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.h4
-rw-r--r--src/secp256k1/doc/release-process.md72
-rw-r--r--src/secp256k1/include/secp256k1.h66
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h2
-rw-r--r--src/secp256k1/include/secp256k1_ellswift.h4
-rw-r--r--src/secp256k1/include/secp256k1_extrakeys.h10
-rw-r--r--src/secp256k1/include/secp256k1_preallocated.h14
-rw-r--r--src/secp256k1/include/secp256k1_recovery.h20
-rw-r--r--src/secp256k1/include/secp256k1_schnorrsig.h4
-rw-r--r--src/secp256k1/src/assumptions.h100
-rw-r--r--src/secp256k1/src/checkmem.h7
-rw-r--r--src/secp256k1/src/field.h4
-rw-r--r--src/secp256k1/src/modules/ellswift/tests_impl.h8
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h59
-rw-r--r--src/secp256k1/src/scalar_impl.h4
-rw-r--r--src/secp256k1/src/secp256k1.c39
-rw-r--r--src/secp256k1/src/tests.c67
-rw-r--r--src/secp256k1/src/util.h16
-rwxr-xr-xsrc/secp256k1/tools/check-abi.sh27
-rw-r--r--src/test/argsman_tests.cpp4
-rw-r--r--src/test/blockencodings_tests.cpp10
-rw-r--r--src/test/fuzz/partially_downloaded_block.cpp4
-rw-r--r--src/test/fuzz/rbf.cpp17
-rw-r--r--src/test/fuzz/script_bitcoin_consensus.cpp50
-rw-r--r--src/test/fuzz/util/descriptor.cpp2
-rw-r--r--src/test/miniscript_tests.cpp1
-rw-r--r--src/test/rbf_tests.cpp231
-rw-r--r--src/test/sanity_tests.cpp2
-rw-r--r--src/test/script_tests.cpp228
-rw-r--r--src/test/util_tests.cpp5
-rw-r--r--src/test/validation_block_tests.cpp1
-rw-r--r--src/txmempool.cpp9
-rw-r--r--src/univalue/include/univalue.h1
-rw-r--r--src/univalue/lib/univalue_write.cpp3
-rw-r--r--src/util/feefrac.cpp7
-rw-r--r--src/util/feefrac.h2
-rw-r--r--src/util/string.h1
-rw-r--r--src/util/time.cpp88
-rw-r--r--src/util/time.h3
-rw-r--r--src/validation.cpp2
-rw-r--r--src/validation.h4
-rw-r--r--src/wallet/interfaces.cpp4
-rw-r--r--src/wallet/receive.cpp8
-rw-r--r--src/wallet/rpc/addresses.cpp3
-rw-r--r--src/wallet/rpc/backup.cpp1
-rw-r--r--src/wallet/rpc/transactions.cpp8
-rw-r--r--src/wallet/rpc/wallet.cpp213
-rw-r--r--src/wallet/scriptpubkeyman.cpp82
-rw-r--r--src/wallet/scriptpubkeyman.h5
-rw-r--r--src/wallet/test/walletload_tests.cpp1
-rw-r--r--src/wallet/transaction.cpp2
-rw-r--r--src/wallet/transaction.h27
-rw-r--r--src/wallet/wallet.cpp135
-rw-r--r--src/wallet/wallet.h16
-rw-r--r--src/wallet/walletutil.cpp56
-rw-r--r--src/wallet/walletutil.h2
-rwxr-xr-xtest/functional/feature_assumevalid.py2
-rwxr-xr-xtest/functional/feature_index_prune.py2
-rwxr-xr-xtest/functional/p2p_block_sync.py2
-rwxr-xr-xtest/functional/p2p_compactblocks.py2
-rwxr-xr-xtest/functional/p2p_node_network_limited.py5
-rwxr-xr-xtest/functional/p2p_segwit.py8
-rwxr-xr-xtest/functional/test_framework/p2p.py30
-rwxr-xr-xtest/functional/test_framework/test_framework.py2
-rwxr-xr-xtest/functional/test_runner.py2
-rwxr-xr-xtest/functional/wallet_abandonconflict.py6
-rwxr-xr-xtest/functional/wallet_backwards_compatibility.py19
-rwxr-xr-xtest/functional/wallet_basic.py2
-rwxr-xr-xtest/functional/wallet_conflicts.py301
-rwxr-xr-xtest/functional/wallet_createwalletdescriptor.py123
-rwxr-xr-xtest/functional/wallet_gethdkeys.py185
-rwxr-xr-xtest/functional/wallet_groups.py5
-rwxr-xr-xtest/functional/wallet_importdescriptors.py2
-rwxr-xr-xtest/fuzz/test_runner.py24
156 files changed, 2188 insertions, 1571 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4b2f4f2913..b92e3c66d0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -62,7 +62,7 @@ jobs:
echo "TEST_BASE=$(git rev-list -n$((${{ env.MAX_COUNT }} + 1)) --reverse HEAD ^$(git rev-list -n1 --merges HEAD)^@ | head -1)" >> "$GITHUB_ENV"
- run: |
sudo apt-get update
- sudo apt-get install clang-15 ccache build-essential libtool autotools-dev automake pkg-config bsdmainutils python3-zmq libevent-dev libboost-dev libsqlite3-dev libdb++-dev systemtap-sdt-dev libminiupnpc-dev libnatpmp-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools qtwayland5 libqrencode-dev -y
+ sudo apt-get install clang-15 ccache build-essential libtool autotools-dev automake pkg-config bsdmainutils python3-zmq libevent-dev libboost-dev libsqlite3-dev libdb++-dev systemtap-sdt-dev libminiupnpc-dev libnatpmp-dev qtbase5-dev qttools5-dev qttools5-dev-tools qtwayland5 libqrencode-dev -y
- name: Compile and run tests
run: |
# Run tests on commits after the last merge commit and before the PR head commit
diff --git a/.gitignore b/.gitignore
index 3fe36aba89..f7bcbd1459 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,7 +136,6 @@ test/lint/test_runner/target/
/doc/doxygen/
-libbitcoinconsensus.pc
contrib/devtools/split-debug.sh
# Output from running db4 installation
@@ -145,7 +144,6 @@ db4/
# clang-check
*.plist
-osx_volname
dist/
/guix-build-*
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0ae4ff1a92..0ac6db76ed 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -66,9 +66,10 @@ Discussion about codebase improvements happens in GitHub issues and pull
requests.
The developer
-[mailing list](https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev)
+[mailing list](https://groups.google.com/g/bitcoindev)
should be used to discuss complicated or controversial consensus or P2P protocol changes before working on
a patch set.
+Archives can be found on [https://gnusha.org/pi/bitcoindev/](https://gnusha.org/pi/bitcoindev/).
Contributor Workflow
diff --git a/Makefile.am b/Makefile.am
index 5ea690dec8..cd1509a0ff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,11 +14,6 @@ endif
.PHONY: deploy FORCE
.INTERMEDIATE: $(COVERAGE_INFO)
-if BUILD_BITCOIN_LIBS
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libbitcoinconsensus.pc
-endif
-
BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT)
BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT)
BITCOIN_TEST_BIN=$(top_builddir)/src/test/$(BITCOIN_TEST_NAME)$(EXEEXT)
@@ -118,9 +113,6 @@ OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lp
$(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \
$(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings
-osx_volname:
- echo $(OSX_VOLNAME) >$@
-
if BUILD_DARWIN
$(OSX_ZIP): $(OSX_APP_BUILT) $(OSX_PACKAGING)
$(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) $(OSX_VOLNAME) -translations-dir=$(QT_TRANSLATION_DIR) -zip
@@ -338,7 +330,7 @@ clean-docs:
clean-local: clean-docs
rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ fuzz.coverage/ test/tmp/ cache/ $(OSX_APP)
rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache share/rpcauth/__pycache__
- rm -rf osx_volname dist/ test/lint/test_runner/target/ test/lint/__pycache__
+ rm -rf dist/ test/lint/test_runner/target/ test/lint/__pycache__
test-security-check:
if TARGET_DARWIN
diff --git a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
index 95fdcdb79b..a34ef41d16 100644
--- a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
+++ b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
@@ -15,7 +15,6 @@
<ClCompile Include="..\..\src\primitives\block.cpp" />
<ClCompile Include="..\..\src\primitives\transaction.cpp" />
<ClCompile Include="..\..\src\pubkey.cpp" />
- <ClCompile Include="..\..\src\script\bitcoinconsensus.cpp" />
<ClCompile Include="..\..\src\script\interpreter.cpp" />
<ClCompile Include="..\..\src\script\script.cpp" />
<ClCompile Include="..\..\src\script\script_error.cpp" />
diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh
index 47cb8864c2..6b12c53f2a 100755
--- a/ci/lint/04_install.sh
+++ b/ci/lint/04_install.sh
@@ -46,7 +46,7 @@ if [ ! -d "${LINT_RUNNER_PATH}" ]; then
fi
${CI_RETRY_EXE} pip3 install \
- codespell==2.2.5 \
+ codespell==2.2.6 \
flake8==6.1.0 \
lief==0.13.2 \
mypy==1.4.1 \
diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh
index a5f3682c36..00a4d781c2 100755
--- a/ci/test/00_setup_env_i686_multiprocess.sh
+++ b/ci/test/00_setup_env_i686_multiprocess.sh
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_multiprocess
-export CI_IMAGE_NAME_TAG="docker.io/amd64/ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="docker.io/amd64/ubuntu:24.04"
export PACKAGES="llvm clang g++-multilib"
export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
export GOAL="install"
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 840daf9708..668e9ecc8a 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -17,10 +17,10 @@ else
fi
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="systemtap-sdt-dev clang-17 llvm-17 libclang-rt-17-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}"
+export PACKAGES="systemtap-sdt-dev clang-18 llvm-18 libclang-rt-18-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}"
export NO_DEPENDS=1
export GOAL="install"
export BITCOIN_CONFIG="--enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 \
CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' \
--with-sanitizers=address,float-divide-by-zero,integer,undefined \
-CC='clang-17 -ftrivial-auto-var-init=pattern' CXX='clang++-17 -ftrivial-auto-var-init=pattern'"
+CC='clang-18 -ftrivial-auto-var-init=pattern' CXX='clang++-18 -ftrivial-auto-var-init=pattern'"
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index abee3c1541..f50561f875 100755
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
export CONTAINER_NAME=ci_native_fuzz
-export PACKAGES="clang-17 llvm-17 libclang-rt-17-dev libevent-dev libboost-dev libsqlite3-dev"
+export PACKAGES="clang-18 llvm-18 libclang-rt-18-dev libevent-dev libboost-dev libsqlite3-dev"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
@@ -16,6 +16,6 @@ export RUN_FUZZ_TESTS=true
export GOAL="install"
export CI_CONTAINER_CAP="--cap-add SYS_PTRACE" # If run with (ASan + LSan), the container needs access to ptrace (https://github.com/google/sanitizers/issues/764)
export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,float-divide-by-zero,integer \
-CC='clang-17 -ftrivial-auto-var-init=pattern' CXX='clang++-17 -ftrivial-auto-var-init=pattern'"
+CC='clang-18 -ftrivial-auto-var-init=pattern' CXX='clang++-18 -ftrivial-auto-var-init=pattern'"
export CCACHE_MAXSIZE=200M
-export LLVM_SYMBOLIZER_PATH="/usr/bin/llvm-symbolizer-17"
+export LLVM_SYMBOLIZER_PATH="/usr/bin/llvm-symbolizer-18"
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 0a9dee2ed8..36a172e42c 100755
--- a/ci/test/00_setup_env_native_fuzz_with_msan.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_msan.sh
@@ -17,7 +17,7 @@ export PACKAGES="ninja-build"
# BDB generates false-positives and will be removed in future
export DEP_OPTS="DEBUG=1 NO_BDB=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no CFLAGS='${MSAN_FLAGS}' CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE'"
export USE_MEMORY_SANITIZER="true"
export RUN_UNIT_TESTS="false"
export RUN_FUNCTIONAL_TESTS="false"
diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh
index cbcd51e218..431e4aba49 100755
--- a/ci/test/00_setup_env_native_msan.sh
+++ b/ci/test/00_setup_env_native_msan.sh
@@ -17,7 +17,7 @@ export PACKAGES="ninja-build"
# BDB generates false-positives and will be removed in future
export DEP_OPTS="DEBUG=1 NO_BDB=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
-export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening"
export USE_MEMORY_SANITIZER="true"
export RUN_FUNCTIONAL_TESTS="false"
export CCACHE_MAXSIZE=250M
diff --git a/ci/test/00_setup_env_native_previous_releases.sh b/ci/test/00_setup_env_native_previous_releases.sh
index 3166686d9a..9da3b18999 100755
--- a/ci/test/00_setup_env_native_previous_releases.sh
+++ b/ci/test/00_setup_env_native_previous_releases.sh
@@ -16,5 +16,5 @@ export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
export DOWNLOAD_PREVIOUS_RELEASES="true"
-export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports --enable-debug \
+export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --enable-debug \
CFLAGS=\"-g0 -O2 -funsigned-char\" CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS=\"-g0 -O2 -funsigned-char\""
diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh
index a5ba64da15..4c8658479b 100755
--- a/ci/test/00_setup_env_native_tidy.sh
+++ b/ci/test/00_setup_env_native_tidy.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
export CONTAINER_NAME=ci_native_tidy
export TIDY_LLVM_V="18"
-export PACKAGES="clang-${TIDY_LLVM_V} libclang-${TIDY_LLVM_V}-dev llvm-${TIDY_LLVM_V}-dev libomp-${TIDY_LLVM_V}-dev clang-tidy-${TIDY_LLVM_V} jq bear libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev"
+export PACKAGES="clang-${TIDY_LLVM_V} libclang-${TIDY_LLVM_V}-dev llvm-${TIDY_LLVM_V}-dev libomp-${TIDY_LLVM_V}-dev clang-tidy-${TIDY_LLVM_V} jq bear libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev qtbase5-dev qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index aa23bad809..3fcaa8c6c6 100755
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_tsan
export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04"
-export PACKAGES="clang-17 llvm-17 libclang-rt-17-dev libc++abi-17-dev libc++-17-dev python3-zmq"
-export DEP_OPTS="CC=clang-17 CXX='clang++-17 -stdlib=libc++'"
+export PACKAGES="clang-18 llvm-18 libclang-rt-18-dev libc++abi-18-dev libc++-18-dev python3-zmq"
+export DEP_OPTS="CC=clang-18 CXX='clang++-18 -stdlib=libc++'"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread"
+export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' --with-sanitizers=thread"
diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh
index 6f1498963a..25962a53e5 100755
--- a/ci/test/01_base_install.sh
+++ b/ci/test/01_base_install.sh
@@ -36,7 +36,7 @@ if [ -n "$PIP_PACKAGES" ]; then
fi
if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
- ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-18.1.1" /msan/llvm-project
+ ${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-18.1.3" /msan/llvm-project
cmake -G Ninja -B /msan/clang_build/ \
-DLLVM_ENABLE_PROJECTS="clang" \
diff --git a/configure.ac b/configure.ac
index ad195db0ca..63a012b35d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -626,15 +626,9 @@ AC_ARG_ENABLE([experimental-util-chainstate],
[build_bitcoin_chainstate=$enableval],
[build_bitcoin_chainstate=no])
-AC_ARG_WITH([libs],
- [AS_HELP_STRING([--with-libs],
- [build libraries (default=yes)])],
- [build_bitcoin_libs=$withval],
- [build_bitcoin_libs=yes])
-
AC_ARG_WITH([experimental-kernel-lib],
[AS_HELP_STRING([--with-experimental-kernel-lib],
- [build experimental bitcoinkernel library (default is to build if we're building libraries and the experimental build-chainstate executable)])],
+ [build experimental bitcoinkernel library (default is to build if we're building the experimental build-chainstate executable)])],
[build_experimental_kernel_lib=$withval],
[build_experimental_kernel_lib=auto])
@@ -974,8 +968,6 @@ AC_CHECK_DECLS([setsid])
AC_CHECK_DECLS([pipe2])
-AC_CHECK_FUNCS([timingsafe_bcmp])
-
AC_MSG_CHECKING([for __builtin_clzl])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[
(void) __builtin_clzl(0);
@@ -1092,22 +1084,6 @@ if test "$use_thread_local" = "yes" || test "$use_thread_local" = "auto"; then
LDFLAGS="$TEMP_LDFLAGS"
fi
-dnl check for gmtime_r(), fallback to gmtime_s() if that is unavailable
-dnl fail if neither are available.
-AC_MSG_CHECKING([for gmtime_r])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <ctime>]],
- [[ gmtime_r((const time_t *) nullptr, (struct tm *) nullptr); ]])],
- [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GMTIME_R], [1], [Define this symbol if gmtime_r is available]) ],
- [ AC_MSG_RESULT([no]);
- AC_MSG_CHECKING([for gmtime_s]);
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <ctime>]],
- [[ gmtime_s((struct tm *) nullptr, (const time_t *) nullptr); ]])],
- [ AC_MSG_RESULT([yes])],
- [ AC_MSG_RESULT([no]); AC_MSG_ERROR([Both gmtime_r and gmtime_s are unavailable]) ]
- )
- ]
-)
-
dnl Check for different ways of gathering OS randomness
AC_MSG_CHECKING([for Linux getrandom function])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@@ -1262,7 +1238,6 @@ if test "$enable_fuzz" = "yes"; then
build_bitcoin_chainstate=no
build_bitcoin_wallet=no
build_bitcoind=no
- build_bitcoin_libs=no
bitcoin_enable_qt=no
bitcoin_enable_qt_test=no
bitcoin_enable_qt_dbus=no
@@ -1421,7 +1396,7 @@ if test "$use_boost" = "yes"; then
dnl Check for Boost headers
AX_BOOST_BASE([1.73.0],[],[AC_MSG_ERROR([Boost is not available!])])
if test "$want_boost" = "no"; then
- AC_MSG_ERROR([only libbitcoinconsensus can be built without Boost])
+ AC_MSG_ERROR([Boost is required])
fi
dnl we don't use multi_index serialization
@@ -1593,18 +1568,8 @@ fi
AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"])
AC_MSG_RESULT($build_bitcoin_chainstate)
-AC_MSG_CHECKING([whether to build libraries])
-AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test $build_bitcoin_libs = "yes"])
-
-if test "$build_bitcoin_libs" = "yes"; then
- AC_DEFINE([HAVE_CONSENSUS_LIB], [1], [Define this symbol if the consensus lib has been built])
- AC_CONFIG_FILES([libbitcoinconsensus.pc:libbitcoinconsensus.pc.in])
-fi
-
AM_CONDITIONAL([BUILD_BITCOIN_KERNEL_LIB], [test "$build_experimental_kernel_lib" != "no" && ( test "$build_experimental_kernel_lib" = "yes" || test "$build_bitcoin_chainstate" = "yes" )])
-AC_MSG_RESULT($build_bitcoin_libs)
-
AC_LANG_POP
if test "$use_ccache" != "no"; then
@@ -1738,8 +1703,8 @@ else
AC_MSG_RESULT([no])
fi
-if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nononononononononono"; then
- AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests])
+if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then
+ AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests])
fi
AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"])
@@ -1837,7 +1802,6 @@ AC_SUBST(MINIUPNPC_CPPFLAGS)
AC_SUBST(MINIUPNPC_LIBS)
AC_SUBST(NATPMP_CPPFLAGS)
AC_SUBST(NATPMP_LIBS)
-AC_SUBST(HAVE_GMTIME_R)
AC_SUBST(HAVE_FDATASYNC)
AC_SUBST(HAVE_FULLFSYNC)
AC_SUBST(HAVE_O_CLOEXEC)
@@ -1899,7 +1863,6 @@ echo
echo "Options used to compile and link:"
echo " external signer = $use_external_signer"
echo " multiprocess = $build_multiprocess"
-echo " with libs = $build_bitcoin_libs"
echo " with wallet = $enable_wallet"
if test "$enable_wallet" != "no"; then
echo " with sqlite = $use_sqlite"
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index b301369ad9..9624221880 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -61,7 +61,6 @@ store_path() {
# Set environment variables to point the NATIVE toolchain to the right
# includes/libs
NATIVE_GCC="$(store_path gcc-toolchain)"
-NATIVE_GCC_STATIC="$(store_path gcc-toolchain static)"
unset LIBRARY_PATH
unset CPATH
@@ -70,12 +69,21 @@ unset CPLUS_INCLUDE_PATH
unset OBJC_INCLUDE_PATH
unset OBJCPLUS_INCLUDE_PATH
-export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC_STATIC}/lib"
export C_INCLUDE_PATH="${NATIVE_GCC}/include"
export CPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include"
export OBJC_INCLUDE_PATH="${NATIVE_GCC}/include"
export OBJCPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include"
+case "$HOST" in
+ *darwin*)
+ export LIBRARY_PATH="${NATIVE_GCC}/lib"
+ ;;
+ *)
+ NATIVE_GCC_STATIC="$(store_path gcc-toolchain static)"
+ export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC_STATIC}/lib"
+ ;;
+esac
+
# Set environment variables to point the CROSS toolchain to the right
# includes/libs for $HOST
case "$HOST" in
@@ -300,11 +308,9 @@ mkdir -p "$DISTSRC"
case "$HOST" in
*darwin*)
- make osx_volname ${V:+V=1}
make deploydir ${V:+V=1}
mkdir -p "unsigned-app-${HOST}"
cp --target-directory="unsigned-app-${HOST}" \
- osx_volname \
contrib/macdeploy/detached-sig-create.sh
mv --target-directory="unsigned-app-${HOST}" dist
(
@@ -321,26 +327,16 @@ mkdir -p "$DISTSRC"
(
cd installed
- case "$HOST" in
- *mingw*)
- mv --target-directory="$DISTNAME"/lib/ "$DISTNAME"/bin/*.dll
- ;;
- esac
-
# Prune libtool and object archives
find . -name "lib*.la" -delete
find . -name "lib*.a" -delete
- # Prune pkg-config files
- rm -rf "${DISTNAME}/lib/pkgconfig"
-
case "$HOST" in
*darwin*) ;;
*)
- # Split binaries and libraries from their debug symbols
+ # Split binaries from their debug symbols
{
find "${DISTNAME}/bin" -type f -executable -print0
- find "${DISTNAME}/lib" -type f -print0
} | xargs -0 -P"$JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg
;;
esac
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index e24a61bf9d..87dcf49bcb 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -500,6 +500,7 @@ inspecting signatures in Mach-O binaries.")
gzip
xz
;; Build tools
+ cmake-minimal
gnu-make
libtool
autoconf-2.71
@@ -528,12 +529,10 @@ inspecting signatures in Mach-O binaries.")
(list gcc-toolchain-12 "static")
(make-bitcoin-cross-toolchain target)))
((string-contains target "darwin")
- (list ;; Native GCC 10 toolchain
- gcc-toolchain-10
- (list gcc-toolchain-10 "static")
+ (list ;; Native GCC 11 toolchain
+ gcc-toolchain-11
binutils
clang-toolchain-17
- cmake-minimal
python-signapple
zip))
(else '())))))
diff --git a/contrib/guix/patches/glibc-2.27-fcommon.patch b/contrib/guix/patches/glibc-2.27-fcommon.patch
index 817aa85bb9..f8d14837fc 100644
--- a/contrib/guix/patches/glibc-2.27-fcommon.patch
+++ b/contrib/guix/patches/glibc-2.27-fcommon.patch
@@ -5,7 +5,7 @@ Date: Fri May 6 11:03:04 2022 +0100
build: use -fcommon to retain legacy behaviour with GCC 10
GCC 10 started using -fno-common by default, which causes issues with
- the powerpc builds using gibc 2.27. A patch was commited to glibc to fix
+ the powerpc builds using gibc 2.27. A patch was committed to glibc to fix
the issue, 18363b4f010da9ba459b13310b113ac0647c2fcc but is non-trvial
to backport, and was broken in at least one way, see the followup in
commit 7650321ce037302bfc2f026aa19e0213b8d02fe6.
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 29ad7ef252..8beedcc98a 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -105,7 +105,7 @@ endif
darwin_release_CFLAGS=-O2
darwin_release_CXXFLAGS=$(darwin_release_CFLAGS)
-darwin_debug_CFLAGS=-O1
+darwin_debug_CFLAGS=-O1 -g
darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS)
darwin_cmake_system=Darwin
diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk
index 8be23be57d..f5ce2bb0b8 100644
--- a/depends/hosts/linux.mk
+++ b/depends/hosts/linux.mk
@@ -10,10 +10,14 @@ endif
linux_release_CFLAGS=-O2
linux_release_CXXFLAGS=$(linux_release_CFLAGS)
-linux_debug_CFLAGS=-O1
+linux_debug_CFLAGS=-O1 -g
linux_debug_CXXFLAGS=$(linux_debug_CFLAGS)
-linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_LIBCPP_ENABLE_DEBUG_MODE=1
+# https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html
+linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
+
+# https://libcxx.llvm.org/Hardening.html
+linux_debug_CPPFLAGS+=-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG
ifeq (86,$(findstring 86,$(build_arch)))
i686_linux_CC=gcc -m32
diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk
index 15aa7cd25a..4c657358f6 100644
--- a/depends/hosts/mingw32.mk
+++ b/depends/hosts/mingw32.mk
@@ -14,7 +14,7 @@ endif
mingw32_release_CFLAGS=-O2
mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS)
-mingw32_debug_CFLAGS=-O1
+mingw32_debug_CFLAGS=-O1 -g
mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS)
mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index 2db283ef3c..2ec660109c 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -6,7 +6,7 @@ $(package)_sha256_hash=f79b8f904b749e3e0d20afeadecf8249c55b2e32d4ebb089ae378df47
# -D_DEFAULT_SOURCE defines __USE_MISC, which exposes additional
# definitions in endian.h, which are required for a working
-# endianess check in configure when building with -flto.
+# endianness check in configure when building with -flto.
define $(package)_set_vars
$(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk
index 765d649377..c292c49bfb 100644
--- a/depends/packages/libmultiprocess.mk
+++ b/depends/packages/libmultiprocess.mk
@@ -20,7 +20,7 @@ define $(package)_config_cmds
endef
define $(package)_build_cmds
- $(MAKE)
+ $(MAKE) multiprocess
endef
define $(package)_stage_cmds
diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk
index 9ebd2dd85a..4d852d833d 100644
--- a/depends/packages/qrencode.mk
+++ b/depends/packages/qrencode.mk
@@ -3,20 +3,22 @@ $(package)_version=4.1.1
$(package)_download_path=https://fukuchi.org/works/qrencode/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=e455d9732f8041cf5b9c388e345a641fd15707860f928e94507b1961256a6923
+$(package)_patches=cmake_fixups.patch
define $(package)_set_vars
-$(package)_config_opts=--disable-shared --without-tools --without-tests --without-png
-$(package)_config_opts += --disable-gprof --disable-gcov --disable-mudflap
-$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+$(package)_config_opts := -DWITH_TOOLS=NO -DWITH_TESTS=NO -DGPROF=OFF -DCOVERAGE=OFF
+$(package)_config_opts += -DCMAKE_DISABLE_FIND_PACKAGE_PNG=TRUE -DWITHOUT_PNG=ON
+$(package)_config_opts += -DCMAKE_DISABLE_FIND_PACKAGE_ICONV=TRUE
$(package)_cflags += -Wno-int-conversion -Wno-implicit-function-declaration
endef
define $(package)_preprocess_cmds
- cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub use
+ patch -p1 < $($(package)_patch_dir)/cmake_fixups.patch
endef
+
define $(package)_config_cmds
- $($(package)_autoconf)
+ $($(package)_cmake) -S . -B .
endef
define $(package)_build_cmds
@@ -26,7 +28,3 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
-
-define $(package)_postprocess_cmds
- rm lib/*.la
-endef
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index d09ad75eec..0acf4cf565 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -1,9 +1,9 @@
package=qt
-$(package)_version=5.15.11
+$(package)_version=5.15.13
$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules
$(package)_suffix=everywhere-opensource-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix)
-$(package)_sha256_hash=425ad301acd91ca66c10c0dabee0704e2d0cd2801a6b670115800cbb95f84846
+$(package)_sha256_hash=4cca51dcc1f22ceeee6b3e33cd1c3a60b14e85e24644dca3af89a2c2989ab809
$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm
$(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_linguist_tools = lrelease lupdate lconvert
@@ -15,7 +15,6 @@ $(package)_patches += no-xlib.patch
$(package)_patches += fix_android_jni_static.patch
$(package)_patches += dont_hardcode_pwd.patch
$(package)_patches += qtbase-moc-ignore-gcc-macro.patch
-$(package)_patches += use_android_ndk23.patch
$(package)_patches += rcc_hardcode_timestamp.patch
$(package)_patches += duplicate_lcqpafonts.patch
$(package)_patches += guix_cross_lib_path.patch
@@ -25,10 +24,10 @@ $(package)_patches += utc_from_string_no_optimize.patch
$(package)_patches += windows_lto.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
-$(package)_qttranslations_sha256_hash=a31785948c640b7c66d9fe2db4993728ca07f64e41c560b3625ad191b276ff20
+$(package)_qttranslations_sha256_hash=24d4c58bc2a40c0f44f59ee64af4192c7d0038c1e45af61646cfc5b65058f271
$(package)_qttools_file_name=qttools-$($(package)_suffix)
-$(package)_qttools_sha256_hash=7cd847ae6ff09416df617136eadcaf0eb98e3bc9b89979219a3ea8111fb8d339
+$(package)_qttools_sha256_hash=57c9794c572c4e02871f2e7581525752b0cf85ea16cfab23a4ac9ba7b39a5d34
$(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
@@ -177,6 +176,7 @@ $(package)_config_opts_mingw32 += -xplatform win32-g++
$(package)_config_opts_mingw32 += "QMAKE_CFLAGS = '$($(package)_cflags) $($(package)_cppflags)'"
$(package)_config_opts_mingw32 += "QMAKE_CXX = '$($(package)_cxx)'"
$(package)_config_opts_mingw32 += "QMAKE_CXXFLAGS = '$($(package)_cxxflags) $($(package)_cppflags)'"
+$(package)_config_opts_mingw32 += "QMAKE_LINK = '$($(package)_cxx)'"
$(package)_config_opts_mingw32 += "QMAKE_LFLAGS = '$($(package)_ldflags)'"
$(package)_config_opts_mingw32 += "QMAKE_LIB = '$($(package)_ar) rc'"
$(package)_config_opts_mingw32 += -device-option CROSS_COMPILE="$(host)-"
@@ -245,7 +245,6 @@ define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \
patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \
patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \
- patch -p1 -i $($(package)_patch_dir)/use_android_ndk23.patch && \
patch -p1 -i $($(package)_patch_dir)/memory_resource.patch && \
patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch && \
patch -p1 -i $($(package)_patch_dir)/duplicate_lcqpafonts.patch && \
diff --git a/depends/packages/sqlite.mk b/depends/packages/sqlite.mk
index 7d175ec4bb..15bc0f4d7a 100644
--- a/depends/packages/sqlite.mk
+++ b/depends/packages/sqlite.mk
@@ -8,7 +8,6 @@ define $(package)_set_vars
$(package)_config_opts=--disable-shared --disable-readline --disable-dynamic-extensions --enable-option-checking
$(package)_config_opts+= --disable-rtree --disable-fts4 --disable-fts5
# We avoid using `--enable-debug` because it overrides CFLAGS, a behavior we want to prevent.
-$(package)_cflags_debug += -g
$(package)_cppflags_debug += -DSQLITE_DEBUG
$(package)_cppflags+=-DSQLITE_DQS=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_OMIT_DEPRECATED
$(package)_cppflags+=-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_JSON -DSQLITE_LIKE_DOESNT_MATCH_BLOBS
diff --git a/depends/patches/qrencode/cmake_fixups.patch b/depends/patches/qrencode/cmake_fixups.patch
new file mode 100644
index 0000000000..7518d756cb
--- /dev/null
+++ b/depends/patches/qrencode/cmake_fixups.patch
@@ -0,0 +1,23 @@
+cmake: set minimum version to 3.5
+
+Correct some dev warning output.
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 773e037..a558145 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-cmake_minimum_required(VERSION 3.1.0)
++cmake_minimum_required(VERSION 3.5)
+
+ project(QRencode VERSION 4.1.1 LANGUAGES C)
+
+@@ -20,7 +20,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+ set(CMAKE_THREAD_PREFER_PTHREAD ON)
+ find_package(Threads)
+ find_package(PNG)
+-find_package(Iconv)
++find_package(ICONV)
+
+ if(CMAKE_USE_PTHREADS_INIT)
+ add_definitions(-DHAVE_LIBPTHREAD=1)
diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch
index 89c96026fb..79824f244a 100644
--- a/depends/patches/qt/fix_android_jni_static.patch
+++ b/depends/patches/qt/fix_android_jni_static.patch
@@ -15,4 +15,3 @@
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
m_javaVM = vm;
-
diff --git a/depends/patches/qt/memory_resource.patch b/depends/patches/qt/memory_resource.patch
index 650c328528..312f0669f6 100644
--- a/depends/patches/qt/memory_resource.patch
+++ b/depends/patches/qt/memory_resource.patch
@@ -17,7 +17,7 @@ and https://bugreports.qt.io/browse/QTBUG-114316
--- a/qtbase/src/corelib/global/qcompilerdetection.h
+++ b/qtbase/src/corelib/global/qcompilerdetection.h
-@@ -1050,16 +1050,22 @@
+@@ -1055,16 +1055,22 @@
# endif // !_HAS_CONSTEXPR
# endif // !__GLIBCXX__ && !_LIBCPP_VERSION
# endif // Q_OS_QNX
diff --git a/depends/patches/qt/use_android_ndk23.patch b/depends/patches/qt/use_android_ndk23.patch
deleted file mode 100644
index f22367d527..0000000000
--- a/depends/patches/qt/use_android_ndk23.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-Use Android NDK r23 LTS
-
---- old/qtbase/mkspecs/features/android/default_pre.prf
-+++ new/qtbase/mkspecs/features/android/default_pre.prf
-@@ -76,7 +76,7 @@ else: equals(QT_ARCH, x86_64): CROSS_COMPILE = $$NDK_LLVM_PATH/bin/x86_64-linux-
- else: equals(QT_ARCH, arm64-v8a): CROSS_COMPILE = $$NDK_LLVM_PATH/bin/aarch64-linux-android-
- else: CROSS_COMPILE = $$NDK_LLVM_PATH/bin/arm-linux-androideabi-
-
--QMAKE_RANLIB = $${CROSS_COMPILE}ranlib
-+QMAKE_RANLIB = $$NDK_LLVM_PATH/bin/llvm-ranlib
- QMAKE_LINK_SHLIB = $$QMAKE_LINK
- QMAKE_LFLAGS =
-
diff --git a/doc/README.md b/doc/README.md
index 446684b482..7b6dacaf4f 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -59,7 +59,6 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
- [Translation Strings Policy](translation_strings_policy.md)
- [JSON-RPC Interface](JSON-RPC-interface.md)
- [Unauthenticated REST Interface](REST-interface.md)
-- [Shared Libraries](shared-libraries.md)
- [BIPS](bips.md)
- [Dnsseed Policy](dnsseed-policy.md)
- [Benchmarking](benchmarking.md)
diff --git a/doc/build-unix.md b/doc/build-unix.md
index bf367fc421..de54fb4eeb 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -30,7 +30,7 @@ tuned to conserve memory with additional CXXFLAGS:
Alternatively, or in addition, debugging information can be skipped for compilation. The default compile flags are
`-g -O2`, and can be changed with:
- ./configure CXXFLAGS="-O2"
+ ./configure CXXFLAGS="-g0"
Finally, clang (often less resource hungry) can be used instead of gcc, which is used by default:
@@ -81,7 +81,7 @@ To build without GUI pass `--without-gui`.
To build with Qt 5 you need the following:
- sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools
+ sudo apt-get install qtbase5-dev qttools5-dev qttools5-dev-tools
Additionally, to support Wayland protocol for modern desktop environments:
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 237f617c02..1e48d225b0 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -30,7 +30,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| [Fontconfig](../depends/packages/fontconfig.mk) | [link](https://www.freedesktop.org/wiki/Software/fontconfig/) | [2.12.6](https://github.com/bitcoin/bitcoin/pull/23495) | 2.6 | Yes |
| [FreeType](../depends/packages/freetype.mk) | [link](https://freetype.org) | [2.11.0](https://github.com/bitcoin/bitcoin/commit/01544dd78ccc0b0474571da854e27adef97137fb) | 2.3.0 | Yes |
| [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [4.1.1](https://github.com/bitcoin/bitcoin/pull/27312) | | No |
-| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.11](https://github.com/bitcoin/bitcoin/pull/28769) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
+| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.13](https://github.com/bitcoin/bitcoin/pull/29732) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
### Networking
| Dependency | Releases | Version used | Minimum required | Runtime |
diff --git a/doc/design/libraries.md b/doc/design/libraries.md
index 7cda64e713..3346c8e81b 100644
--- a/doc/design/libraries.md
+++ b/doc/design/libraries.md
@@ -4,10 +4,9 @@
|--------------------------|-------------|
| *libbitcoin_cli* | RPC client functionality used by *bitcoin-cli* executable |
| *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). |
-| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet* and also exposed as a [shared library](../shared-libraries.md). |
-| *libbitcoinconsensus* | Shared library build of static *libbitcoin_consensus* library |
-| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node* and also exposed as a [shared library](../shared-libraries.md). |
-| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables |
+| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet*. |
+| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. |
+| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. |
| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. |
| *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. |
| *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). |
@@ -17,7 +16,7 @@
## Conventions
-- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. Exceptions are *libbitcoin_consensus* and *libbitcoin_kernel* which have external interfaces documented at [../shared-libraries.md](../shared-libraries.md).
+- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. An exception is *libbitcoin_kernel*, which, at some future point, will have a documented external interface.
- Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`libbitcoin_*_SOURCES`](../../src/Makefile.am) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like:
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 89c13600eb..cc3f0518e5 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -115,6 +115,8 @@ code.
Use `reinterpret_cast` and `const_cast` as appropriate.
- Prefer [`list initialization ({})`](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-list) where possible.
For example `int x{0};` instead of `int x = 0;` or `int x(0);`
+ - Recursion is checked by clang-tidy and thus must be made explicit. Use
+ `NOLINTNEXTLINE(misc-no-recursion)` to suppress the check.
For function calls a namespace should be specified explicitly, unless such functions have been declared within it.
Otherwise, [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl), also known as ADL, could be
diff --git a/doc/dnsseed-policy.md b/doc/dnsseed-policy.md
index 55a5c28258..99f48f2670 100644
--- a/doc/dnsseed-policy.md
+++ b/doc/dnsseed-policy.md
@@ -44,7 +44,7 @@ related to the DNS seed operation.
If these expectations cannot be satisfied the operator should
discontinue providing services and contact the active Bitcoin
Core development team as well as posting on
-[bitcoin-dev](https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev).
+[bitcoin-dev](https://groups.google.com/g/bitcoindev).
Behavior outside of these expectations may be reasonable in some
situations but should be discussed in public in advance.
diff --git a/doc/release-notes/release-notes-25.2.md b/doc/release-notes/release-notes-25.2.md
new file mode 100644
index 0000000000..3f050ebaef
--- /dev/null
+++ b/doc/release-notes/release-notes-25.2.md
@@ -0,0 +1,74 @@
+25.2 Release Notes
+==================
+
+Bitcoin Core version 25.2 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-25.2>
+
+This release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+Notable changes
+===============
+
+### Gui
+
+- gui#774 Fix crash on selecting "Mask values" in transaction view
+
+### RPC
+
+- #29003 rpc: fix getrawtransaction segfault
+
+### Wallet
+
+- #29176 wallet: Fix use-after-free in WalletBatch::EraseRecords
+- #29510 wallet: `getrawchangeaddress` and `getnewaddress` failures should not affect keypools for descriptor wallets
+
+### P2P and network changes
+
+- #29412 p2p: Don't process mutated blocks
+- #29524 p2p: Don't consider blocks mutated if they don't connect to known prev block
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Martin Zumsande
+- Sebastian Falbesoner
+- MarcoFalke
+- UdjinM6
+- dergoegge
+- Greg Sanders
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-notes/release-notes-26.1.md b/doc/release-notes/release-notes-26.1.md
new file mode 100644
index 0000000000..b5c6e63007
--- /dev/null
+++ b/doc/release-notes/release-notes-26.1.md
@@ -0,0 +1,106 @@
+26.1 Release Notes
+==================
+
+Bitcoin Core version 26.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-26.1/>
+
+This release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 11.0+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+Notable changes
+===============
+
+### Wallet
+
+- #28994 wallet: skip BnB when SFFO is enabled
+- #28920 wallet: birth time update during tx scanning
+- #29176 wallet: Fix use-after-free in WalletBatch::EraseRecords
+- #29510 wallet: getrawchangeaddress and getnewaddress failures should not affect keypools for descriptor wallets
+
+### RPC
+
+- #29003 rpc: fix getrawtransaction segfault
+- #28784 rpc: keep .cookie file if it was not generated
+
+### Logs
+
+- #29227 log mempool loading progress
+
+### P2P and network changes
+
+- #29200 net: create I2P sessions using both ECIES-X25519 and ElGamal encryption
+- #29412 p2p: Don't process mutated blocks
+- #29524 p2p: Don't consider blocks mutated if they don't connect to known prev block
+
+### Build
+
+- #29127 Use hardened runtime on macOS release builds.
+- #29195 build: Fix -Xclang -internal-isystem option
+
+### CI
+
+- #28992 ci: Use Ubuntu 24.04 Noble for asan,tsan,tidy,fuzz
+- #29080 ci: Set HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK to avoid unrelated failures
+- #29610 ci: Fix "macOS native" job
+
+### Miscellaneous
+
+- #28391 refactor: Simplify CTxMempool/BlockAssembler fields, remove some external mapTx access
+- #29179 test: wallet rescan with reorged parent + IsFromMe child in mempool
+- #28791 snapshots: don't core dump when running -checkblockindex after loadtxoutset
+- #29357 test: Drop x modifier in fsbridge::fopen call for MinGW builds
+- #29529 fuzz: restrict fopencookie usage to Linux & FreeBSD
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- dergoegge
+- fanquake
+- furszy
+- glozow
+- Greg Sanders
+- Hennadii Stepanov
+- Jon Atack
+- MarcoFalke
+- Mark Friedenbach
+- Martin Zumsande
+- Murch
+- Roman Zeyde
+- stickies-v
+- UdjinM6
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
+
diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md
deleted file mode 100644
index 3a448c6556..0000000000
--- a/doc/shared-libraries.md
+++ /dev/null
@@ -1,78 +0,0 @@
-Shared Libraries
-================
-
-## bitcoinconsensus
-***This library is deprecated and will be removed in v28***
-
-The purpose of this library is to make the verification functionality that is critical to Bitcoin's consensus available to other applications, e.g. to language bindings.
-
-### API
-
-The interface is defined in the C header `bitcoinconsensus.h` located in `src/script/bitcoinconsensus.h`.
-
-#### Version
-
-`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently `2`)*.
-
-#### Script Validation
-
-`bitcoinconsensus_verify_script`, `bitcoinconsensus_verify_script_with_amount` and `bitcoinconsensus_verify_script_with_spent_outputs` return an `int` with the status of the verification. It will be `1` if the input script correctly spends the previous output `scriptPubKey`.
-
-##### Parameters
-###### bitcoinconsensus_verify_script
-- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending.
-- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`.
-- `const unsigned char *txTo` - The transaction with the input that is spending the previous output.
-- `unsigned int txToLen` - The number of bytes for the `txTo`.
-- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`.
-- `unsigned int flags` - The script validation flags *(see below)*.
-- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*.
-
-###### bitcoinconsensus_verify_script_with_amount
-- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending.
-- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`.
-- `int64_t amount` - The amount spent in the input
-- `const unsigned char *txTo` - The transaction with the input that is spending the previous output.
-- `unsigned int txToLen` - The number of bytes for the `txTo`.
-- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`.
-- `unsigned int flags` - The script validation flags *(see below)*.
-- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*.
-
-###### bitcoinconsensus_verify_script_with_spent_outputs
-- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending.
-- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`.
-- `int64_t amount` - The amount spent in the input
-- `const unsigned char *txTo` - The transaction with the input that is spending the previous output.
-- `unsigned int txToLen` - The number of bytes for the `txTo`.
-- `UTXO *spentOutputs` - Previous outputs spent in the transaction. `UTXO` is a struct composed by `const unsigned char *scriptPubKey`, `unsigned int scriptPubKeySize` (the number of bytes for the `scriptPubKey`) and `unsigned int value`.
-- `unsigned int spentOutputsLen` - The number of bytes for the `spentOutputs`.
-- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`.
-- `unsigned int flags` - The script validation flags *(see below)*.
-- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*.
-
-##### Script Flags
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE`
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH` - Evaluate P2SH ([BIP16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)) subscripts
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG` - Enforce strict DER ([BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)) compliance
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY` - Enforce NULLDUMMY ([BIP147](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki))
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY` - Enable CHECKLOCKTIMEVERIFY ([BIP65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki))
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY` - Enable CHECKSEQUENCEVERIFY ([BIP112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki))
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS` - Enable WITNESS ([BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki))
-- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT` - Enable TAPROOT ([BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki), [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki), [BIP342](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki))
-
-##### Errors
-- `bitcoinconsensus_ERR_OK` - No errors with input parameters *(see the return value of `bitcoinconsensus_verify_script` for the verification status)*
-- `bitcoinconsensus_ERR_TX_INDEX` - An invalid index for `txTo`
-- `bitcoinconsensus_ERR_TX_SIZE_MISMATCH` - `txToLen` did not match with the size of `txTo`
-- `bitcoinconsensus_ERR_DESERIALIZE` - An error deserializing `txTo`
-- `bitcoinconsensus_ERR_AMOUNT_REQUIRED` - Input amount is required if WITNESS is used
-- `bitcoinconsensus_ERR_INVALID_FLAGS` - Script verification `flags` are invalid (i.e. not part of the libconsensus interface)
-- `bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required if TAPROOT is used
-- `bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH` - Spent outputs size doesn't match tx inputs size
-
-### Example Implementations
-- [NBitcoin](https://github.com/MetacoSA/NBitcoin/blob/5e1055cd7c4186dee4227c344af8892aea54faec/NBitcoin/Script.cs#L979-#L1031) (.NET Bindings)
-- [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus) (Node.js Bindings)
-- [java-libbitcoinconsensus](https://github.com/dexX7/java-libbitcoinconsensus) (Java Bindings)
-- [bitcoinconsensus-php](https://github.com/Bit-Wasp/bitcoinconsensus-php) (PHP Bindings)
-- [rust-bitcoinconsensus](https://github.com/rust-bitcoin/rust-bitcoinconsensus) (Rust Bindings) \ No newline at end of file
diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in
deleted file mode 100644
index 1ceab280bb..0000000000
--- a/libbitcoinconsensus.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: @PACKAGE_NAME@ consensus library
-Description: Library for the Bitcoin consensus protocol.
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lbitcoinconsensus
-Cflags: -I${includedir}
diff --git a/src/.clang-tidy b/src/.clang-tidy
index e4b789dcaa..a00400f083 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -6,6 +6,7 @@ bugprone-string-constructor,
bugprone-use-after-move,
bugprone-lambda-function-name,
misc-unused-using-decls,
+misc-no-recursion,
modernize-use-default-member-init,
modernize-use-emplace,
modernize-use-noexcept,
diff --git a/src/Makefile.am b/src/Makefile.am
index 558975cd82..7673d2f545 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,9 +39,6 @@ LIBSECP256K1=secp256k1/libsecp256k1.la
if ENABLE_ZMQ
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
endif
-if BUILD_BITCOIN_LIBS
-LIBBITCOINCONSENSUS=libbitcoinconsensus.la
-endif
if BUILD_BITCOIN_KERNEL_LIB
LIBBITCOINKERNEL=libbitcoinkernel.la
endif
@@ -650,7 +647,6 @@ libbitcoin_consensus_a_SOURCES = \
primitives/transaction.h \
pubkey.cpp \
pubkey.h \
- script/bitcoinconsensus.cpp \
script/interpreter.cpp \
script/interpreter.h \
script/script.cpp \
@@ -1011,21 +1007,6 @@ libbitcoinkernel_la-clientversion.l$(OBJEXT): obj/build.h
endif # BUILD_BITCOIN_KERNEL_LIB
#
-# bitcoinconsensus library #
-if BUILD_BITCOIN_LIBS
-lib_LTLIBRARIES += $(LIBBITCOINCONSENSUS)
-
-include_HEADERS = script/bitcoinconsensus.h
-libbitcoinconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libbitcoin_crypto_base_la_SOURCES) $(libbitcoin_consensus_a_SOURCES)
-
-libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
-libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1)
-libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL -DDISABLE_OPTIMIZED_SHA256
-libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-
-endif
-#
-
CTAES_DIST = crypto/ctaes/bench.c
CTAES_DIST += crypto/ctaes/ctaes.c
CTAES_DIST += crypto/ctaes/ctaes.h
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index d345b41a0a..cf88a02b95 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -365,7 +365,6 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/rpc.cpp \
test/fuzz/script.cpp \
test/fuzz/script_assets_test_minimizer.cpp \
- test/fuzz/script_bitcoin_consensus.cpp \
test/fuzz/script_descriptor_cache.cpp \
test/fuzz/script_flags.cpp \
test/fuzz/script_format.cpp \
diff --git a/src/bench/bip324_ecdh.cpp b/src/bench/bip324_ecdh.cpp
index 659da0f08e..fb10c2957e 100644
--- a/src/bench/bip324_ecdh.cpp
+++ b/src/bench/bip324_ecdh.cpp
@@ -27,7 +27,7 @@ static void BIP324_ECDH(benchmark::Bench& bench)
bench.batch(1).unit("ecdh").run([&] {
CKey key;
- key.Set(UCharCast(key_data.data()), UCharCast(key_data.data()) + 32, true);
+ key.Set(key_data.data(), key_data.data() + 32, true);
EllSwiftPubKey our_ellswift(our_ellswift_data);
EllSwiftPubKey their_ellswift(their_ellswift_data);
diff --git a/src/bench/ellswift.cpp b/src/bench/ellswift.cpp
index 82e8dec982..9441b4863e 100644
--- a/src/bench/ellswift.cpp
+++ b/src/bench/ellswift.cpp
@@ -17,7 +17,7 @@ static void EllSwiftCreate(benchmark::Bench& bench)
bench.batch(1).unit("pubkey").run([&] {
auto ret = key.EllSwiftCreate(MakeByteSpan(entropy));
/* Use the first 32 bytes of the ellswift encoded public key as next private key. */
- key.Set(UCharCast(ret.data()), UCharCast(ret.data()) + 32, true);
+ key.Set(ret.data(), ret.data() + 32, true);
assert(key.IsValid());
/* Use the last 32 bytes of the ellswift encoded public key as next entropy. */
std::copy(ret.begin() + 32, ret.begin() + 64, MakeWritableByteSpan(entropy).begin());
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index e7166a91cf..ee750bc1f8 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -2,15 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <bench/bench.h>
#include <key.h>
-#if defined(HAVE_CONSENSUS_LIB)
-#include <script/bitcoinconsensus.h>
-#endif
#include <script/script.h>
#include <script/interpreter.h>
#include <streams.h>
@@ -63,17 +56,6 @@ static void VerifyScriptBench(benchmark::Bench& bench)
&err);
assert(err == SCRIPT_ERR_OK);
assert(success);
-
-#if defined(HAVE_CONSENSUS_LIB)
- DataStream stream;
- stream << TX_WITH_WITNESS(txSpend);
- int csuccess = bitcoinconsensus_verify_script_with_amount(
- txCredit.vout[0].scriptPubKey.data(),
- txCredit.vout[0].scriptPubKey.size(),
- txCredit.vout[0].nValue,
- (const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr);
- assert(csuccess == 1);
-#endif
});
ECC_Stop();
}
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index f0e27cb675..129deeec60 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -827,7 +827,10 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
if (response.error != -1) {
responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
}
- throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the bitcoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
+ throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\n"
+ "Make sure the bitcoind server is running and that you are connecting to the correct RPC port.\n"
+ "Use \"bitcoin-cli -help\" for more info.",
+ host, port, responseErrorMessage));
} else if (response.status == HTTP_UNAUTHORIZED) {
if (failedToGetAuthCookie) {
throw std::runtime_error(strprintf(
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 1e940e8f03..5a4513d281 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -40,14 +40,14 @@ void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
shorttxidk1 = shorttxidhash.GetUint64(1);
}
-uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {
+uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const Wtxid& wtxid) const {
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids");
- return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;
+ return SipHashUint256(shorttxidk0, shorttxidk1, wtxid) & 0xffffffffffffL;
}
-ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {
+ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn) {
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
return READ_STATUS_INVALID;
if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZABLE_TRANSACTION_WEIGHT)
@@ -134,11 +134,14 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
}
for (size_t i = 0; i < extra_txn.size(); i++) {
- uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first);
+ if (extra_txn[i] == nullptr) {
+ continue;
+ }
+ uint64_t shortid = cmpctblock.GetShortID(extra_txn[i]->GetWitnessHash());
std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
if (idit != shorttxids.end()) {
if (!have_txn[idit->second]) {
- txn_available[idit->second] = extra_txn[i].second;
+ txn_available[idit->second] = extra_txn[i];
have_txn[idit->second] = true;
mempool_count++;
extra_count++;
@@ -150,7 +153,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
// Note that we don't want duplication between extra_txn and mempool to
// trigger this case, so we compare witness hashes first
if (txn_available[idit->second] &&
- txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) {
+ txn_available[idit->second]->GetWitnessHash() != extra_txn[i]->GetWitnessHash()) {
txn_available[idit->second].reset();
mempool_count--;
extra_count--;
diff --git a/src/blockencodings.h b/src/blockencodings.h
index fb0f734ff8..2b1fabadd6 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -111,7 +111,7 @@ public:
CBlockHeaderAndShortTxIDs(const CBlock& block);
- uint64_t GetShortID(const uint256& txhash) const;
+ uint64_t GetShortID(const Wtxid& wtxid) const;
size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }
@@ -142,7 +142,7 @@ public:
explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
- ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
+ ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn);
bool IsTxAvailable(size_t index) const;
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
};
diff --git a/src/crypto/chacha20poly1305.cpp b/src/crypto/chacha20poly1305.cpp
index 3e8051c2dc..b969bb1a29 100644
--- a/src/crypto/chacha20poly1305.cpp
+++ b/src/crypto/chacha20poly1305.cpp
@@ -2,10 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <crypto/chacha20poly1305.h>
#include <crypto/common.h>
@@ -30,10 +26,7 @@ void AEADChaCha20Poly1305::SetKey(Span<const std::byte> key) noexcept
namespace {
-#ifndef HAVE_TIMINGSAFE_BCMP
-#define HAVE_TIMINGSAFE_BCMP
-
-int timingsafe_bcmp(const unsigned char* b1, const unsigned char* b2, size_t n) noexcept
+int timingsafe_bcmp_internal(const unsigned char* b1, const unsigned char* b2, size_t n) noexcept
{
const unsigned char *p1 = b1, *p2 = b2;
int ret = 0;
@@ -42,8 +35,6 @@ int timingsafe_bcmp(const unsigned char* b1, const unsigned char* b2, size_t n)
return (ret != 0);
}
-#endif
-
/** Compute poly1305 tag. chacha20 must be set to the right nonce, block 0. Will be at block 1 after. */
void ComputeTag(ChaCha20& chacha20, Span<const std::byte> aad, Span<const std::byte> cipher, Span<std::byte> tag) noexcept
{
@@ -97,7 +88,7 @@ bool AEADChaCha20Poly1305::Decrypt(Span<const std::byte> cipher, Span<const std:
m_chacha20.Seek(nonce, 0);
std::byte expected_tag[EXPANSION];
ComputeTag(m_chacha20, aad, cipher.first(cipher.size() - EXPANSION), expected_tag);
- if (timingsafe_bcmp(UCharCast(expected_tag), UCharCast(cipher.last(EXPANSION).data()), EXPANSION)) return false;
+ if (timingsafe_bcmp_internal(UCharCast(expected_tag), UCharCast(cipher.last(EXPANSION).data()), EXPANSION)) return false;
// Decrypt (starting at block 1).
m_chacha20.Crypt(cipher.first(plain1.size()), plain1);
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 4c7bb6f20f..301f22a248 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -20,7 +20,7 @@
#include <asm/hwcap.h>
#endif
-#if defined(MAC_OSX) && defined(ENABLE_ARM_SHANI)
+#if defined(__APPLE__) && defined(ENABLE_ARM_SHANI)
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
@@ -670,7 +670,7 @@ std::string SHA256AutoDetect(sha256_implementation::UseImplementation use_implem
#endif
#endif
-#if defined(MAC_OSX)
+#if defined(__APPLE__)
int val = 0;
size_t len = sizeof(val);
if (sysctlbyname("hw.optional.arm.FEAT_SHA256", &val, &len, nullptr, 0) == 0) {
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index cb0b362143..df320ed465 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -359,7 +359,7 @@ public:
* @param bytes the approximate number of bytes to use for this data
* structure
* @returns A pair of the maximum number of elements storable (see setup()
- * documentation for more detail) and the approxmiate total size of these
+ * documentation for more detail) and the approximate total size of these
* elements in bytes or std::nullopt if the size requested is too large.
*/
std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t bytes)
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 13d8ba5a01..a203ce4a9f 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -162,9 +162,9 @@ void BaseIndex::Sync()
const CBlockIndex* pindex_next = WITH_LOCK(cs_main, return NextSyncBlock(pindex, m_chainstate->m_chain));
if (!pindex_next) {
SetBestBlockIndex(pindex);
- m_synced = true;
// No need to handle errors in Commit. See rationale above.
Commit();
+ m_synced = true;
break;
}
if (pindex_next->pprev != pindex && !Rewind(pindex, pindex_next->pprev)) {
diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp
index 264a2fd681..26c261eba2 100644
--- a/src/kernel/chainparams.cpp
+++ b/src/kernel/chainparams.cpp
@@ -133,7 +133,7 @@ public:
// release ASAP to avoid it where possible.
vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
- vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
+ vSeeds.emplace_back("dnsseed.bitcoin.dashjr-list-of-p2p-nodes.us."); // Luke Dashjr
vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd
vSeeds.emplace_back("seed.btc.petertodd.net."); // Peter Todd, only supports x1, x5, x9, and xd
diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp
index bf8a2ec74c..45a5e25093 100644
--- a/src/kernel/checks.cpp
+++ b/src/kernel/checks.cpp
@@ -6,7 +6,6 @@
#include <key.h>
#include <random.h>
-#include <util/time.h>
#include <util/translation.h>
#include <memory>
@@ -23,10 +22,6 @@ util::Result<void> SanityChecks(const Context&)
return util::Error{Untranslated("OS cryptographic RNG sanity check failure. Aborting.")};
}
- if (!ChronoSanityCheck()) {
- return util::Error{Untranslated("Clock epoch mismatch. Aborting.")};
- }
-
return {};
}
diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp
index 57c5168e9f..f06f609379 100644
--- a/src/kernel/mempool_persist.cpp
+++ b/src/kernel/mempool_persist.cpp
@@ -44,7 +44,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
AutoFile file{opts.mockable_fopen_function(load_path, "rb")};
if (file.IsNull()) {
- LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
+ LogInfo("Failed to open mempool file. Continuing anyway.\n");
return false;
}
@@ -70,12 +70,12 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
uint64_t total_txns_to_load;
file >> total_txns_to_load;
uint64_t txns_tried = 0;
- LogInfo("Loading %u mempool transactions from disk...\n", total_txns_to_load);
+ LogInfo("Loading %u mempool transactions from file...\n", total_txns_to_load);
int next_tenth_to_report = 0;
while (txns_tried < total_txns_to_load) {
const int percentage_done(100.0 * txns_tried / total_txns_to_load);
if (next_tenth_to_report < percentage_done / 10) {
- LogInfo("Progress loading mempool transactions from disk: %d%% (tried %u, %u remaining)\n",
+ LogInfo("Progress loading mempool transactions from file: %d%% (tried %u, %u remaining)\n",
percentage_done, txns_tried, total_txns_to_load - txns_tried);
next_tenth_to_report = percentage_done / 10;
}
@@ -138,11 +138,11 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
}
}
} catch (const std::exception& e) {
- LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
+ LogInfo("Failed to deserialize mempool data on file: %s. Continuing anyway.\n", e.what());
return false;
}
- LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast);
+ LogInfo("Imported mempool transactions from file: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast);
return true;
}
@@ -184,7 +184,9 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
}
file.SetXor(xor_key);
- file << (uint64_t)vinfo.size();
+ uint64_t mempool_transactions_to_write(vinfo.size());
+ file << mempool_transactions_to_write;
+ LogInfo("Writing %u mempool transactions to file...\n", mempool_transactions_to_write);
for (const auto& i : vinfo) {
file << TX_WITH_WITNESS(*(i.tx));
file << int64_t{count_seconds(i.m_time)};
@@ -194,7 +196,7 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
file << mapDeltas;
- LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
+ LogInfo("Writing %d unbroadcast transactions to file.\n", unbroadcast_txids.size());
file << unbroadcast_txids;
if (!skip_file_commit && !FileCommit(file.Get()))
@@ -205,11 +207,12 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
}
auto last = SteadyClock::now();
- LogPrintf("Dumped mempool: %.3fs to copy, %.3fs to dump\n",
+ LogInfo("Dumped mempool: %.3fs to copy, %.3fs to dump, %d bytes dumped to file\n",
Ticks<SecondsDouble>(mid - start),
- Ticks<SecondsDouble>(last - mid));
+ Ticks<SecondsDouble>(last - mid),
+ fs::file_size(dump_path));
} catch (const std::exception& e) {
- LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
+ LogInfo("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
return false;
}
return true;
diff --git a/src/key.h b/src/key.h
index d6b26f891d..53acd179ba 100644
--- a/src/key.h
+++ b/src/key.h
@@ -223,6 +223,12 @@ struct CExtKey {
a.key == b.key;
}
+ CExtKey() = default;
+ CExtKey(const CExtPubKey& xpub, const CKey& key_in) : nDepth(xpub.nDepth), nChild(xpub.nChild), chaincode(xpub.chaincode), key(key_in)
+ {
+ std::copy(xpub.vchFingerprint, xpub.vchFingerprint + sizeof(xpub.vchFingerprint), vchFingerprint);
+ }
+
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
[[nodiscard]] bool Derive(CExtKey& out, unsigned int nChild) const;
diff --git a/src/logging.cpp b/src/logging.cpp
index 42f100ded6..578650f856 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -9,9 +9,8 @@
#include <util/threadnames.h>
#include <util/time.h>
-#include <algorithm>
#include <array>
-#include <mutex>
+#include <map>
#include <optional>
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
@@ -142,49 +141,57 @@ bool BCLog::Logger::DefaultShrinkDebugFile() const
return m_categories == BCLog::NONE;
}
-struct CLogCategoryDesc {
- BCLog::LogFlags flag;
- std::string category;
-};
-
-const CLogCategoryDesc LogCategories[] =
-{
- {BCLog::NONE, "0"},
- {BCLog::NONE, ""},
- {BCLog::NET, "net"},
- {BCLog::TOR, "tor"},
- {BCLog::MEMPOOL, "mempool"},
- {BCLog::HTTP, "http"},
- {BCLog::BENCH, "bench"},
- {BCLog::ZMQ, "zmq"},
- {BCLog::WALLETDB, "walletdb"},
- {BCLog::RPC, "rpc"},
- {BCLog::ESTIMATEFEE, "estimatefee"},
- {BCLog::ADDRMAN, "addrman"},
- {BCLog::SELECTCOINS, "selectcoins"},
- {BCLog::REINDEX, "reindex"},
- {BCLog::CMPCTBLOCK, "cmpctblock"},
- {BCLog::RAND, "rand"},
- {BCLog::PRUNE, "prune"},
- {BCLog::PROXY, "proxy"},
- {BCLog::MEMPOOLREJ, "mempoolrej"},
- {BCLog::LIBEVENT, "libevent"},
- {BCLog::COINDB, "coindb"},
- {BCLog::QT, "qt"},
- {BCLog::LEVELDB, "leveldb"},
- {BCLog::VALIDATION, "validation"},
- {BCLog::I2P, "i2p"},
- {BCLog::IPC, "ipc"},
+static const std::map<std::string, BCLog::LogFlags> LOG_CATEGORIES_BY_STR{
+ {"0", BCLog::NONE},
+ {"", BCLog::NONE},
+ {"net", BCLog::NET},
+ {"tor", BCLog::TOR},
+ {"mempool", BCLog::MEMPOOL},
+ {"http", BCLog::HTTP},
+ {"bench", BCLog::BENCH},
+ {"zmq", BCLog::ZMQ},
+ {"walletdb", BCLog::WALLETDB},
+ {"rpc", BCLog::RPC},
+ {"estimatefee", BCLog::ESTIMATEFEE},
+ {"addrman", BCLog::ADDRMAN},
+ {"selectcoins", BCLog::SELECTCOINS},
+ {"reindex", BCLog::REINDEX},
+ {"cmpctblock", BCLog::CMPCTBLOCK},
+ {"rand", BCLog::RAND},
+ {"prune", BCLog::PRUNE},
+ {"proxy", BCLog::PROXY},
+ {"mempoolrej", BCLog::MEMPOOLREJ},
+ {"libevent", BCLog::LIBEVENT},
+ {"coindb", BCLog::COINDB},
+ {"qt", BCLog::QT},
+ {"leveldb", BCLog::LEVELDB},
+ {"validation", BCLog::VALIDATION},
+ {"i2p", BCLog::I2P},
+ {"ipc", BCLog::IPC},
#ifdef DEBUG_LOCKCONTENTION
- {BCLog::LOCK, "lock"},
+ {"lock", BCLog::LOCK},
#endif
- {BCLog::UTIL, "util"},
- {BCLog::BLOCKSTORAGE, "blockstorage"},
- {BCLog::TXRECONCILIATION, "txreconciliation"},
- {BCLog::SCAN, "scan"},
- {BCLog::TXPACKAGES, "txpackages"},
- {BCLog::ALL, "1"},
- {BCLog::ALL, "all"},
+ {"blockstorage", BCLog::BLOCKSTORAGE},
+ {"txreconciliation", BCLog::TXRECONCILIATION},
+ {"scan", BCLog::SCAN},
+ {"txpackages", BCLog::TXPACKAGES},
+ {"1", BCLog::ALL},
+ {"all", BCLog::ALL},
+};
+
+static const std::unordered_map<BCLog::LogFlags, std::string> LOG_CATEGORIES_BY_FLAG{
+ // Swap keys and values from LOG_CATEGORIES_BY_STR.
+ [](const std::map<std::string, BCLog::LogFlags>& in) {
+ std::unordered_map<BCLog::LogFlags, std::string> out;
+ for (const auto& [k, v] : in) {
+ switch (v) {
+ case BCLog::NONE: out.emplace(BCLog::NONE, ""); break;
+ case BCLog::ALL: out.emplace(BCLog::ALL, "all"); break;
+ default: out.emplace(v, k);
+ }
+ }
+ return out;
+ }(LOG_CATEGORIES_BY_STR)
};
bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
@@ -193,11 +200,10 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
flag = BCLog::ALL;
return true;
}
- for (const CLogCategoryDesc& category_desc : LogCategories) {
- if (category_desc.category == str) {
- flag = category_desc.flag;
- return true;
- }
+ auto it = LOG_CATEGORIES_BY_STR.find(str);
+ if (it != LOG_CATEGORIES_BY_STR.end()) {
+ flag = it->second;
+ return true;
}
return false;
}
@@ -221,76 +227,9 @@ std::string BCLog::Logger::LogLevelToStr(BCLog::Level level)
std::string LogCategoryToStr(BCLog::LogFlags category)
{
- // Each log category string representation should sync with LogCategories
- switch (category) {
- case BCLog::LogFlags::NONE:
- return "";
- case BCLog::LogFlags::NET:
- return "net";
- case BCLog::LogFlags::TOR:
- return "tor";
- case BCLog::LogFlags::MEMPOOL:
- return "mempool";
- case BCLog::LogFlags::HTTP:
- return "http";
- case BCLog::LogFlags::BENCH:
- return "bench";
- case BCLog::LogFlags::ZMQ:
- return "zmq";
- case BCLog::LogFlags::WALLETDB:
- return "walletdb";
- case BCLog::LogFlags::RPC:
- return "rpc";
- case BCLog::LogFlags::ESTIMATEFEE:
- return "estimatefee";
- case BCLog::LogFlags::ADDRMAN:
- return "addrman";
- case BCLog::LogFlags::SELECTCOINS:
- return "selectcoins";
- case BCLog::LogFlags::REINDEX:
- return "reindex";
- case BCLog::LogFlags::CMPCTBLOCK:
- return "cmpctblock";
- case BCLog::LogFlags::RAND:
- return "rand";
- case BCLog::LogFlags::PRUNE:
- return "prune";
- case BCLog::LogFlags::PROXY:
- return "proxy";
- case BCLog::LogFlags::MEMPOOLREJ:
- return "mempoolrej";
- case BCLog::LogFlags::LIBEVENT:
- return "libevent";
- case BCLog::LogFlags::COINDB:
- return "coindb";
- case BCLog::LogFlags::QT:
- return "qt";
- case BCLog::LogFlags::LEVELDB:
- return "leveldb";
- case BCLog::LogFlags::VALIDATION:
- return "validation";
- case BCLog::LogFlags::I2P:
- return "i2p";
- case BCLog::LogFlags::IPC:
- return "ipc";
-#ifdef DEBUG_LOCKCONTENTION
- case BCLog::LogFlags::LOCK:
- return "lock";
-#endif
- case BCLog::LogFlags::UTIL:
- return "util";
- case BCLog::LogFlags::BLOCKSTORAGE:
- return "blockstorage";
- case BCLog::LogFlags::TXRECONCILIATION:
- return "txreconciliation";
- case BCLog::LogFlags::SCAN:
- return "scan";
- case BCLog::LogFlags::TXPACKAGES:
- return "txpackages";
- case BCLog::LogFlags::ALL:
- return "all";
- }
- assert(false);
+ auto it = LOG_CATEGORIES_BY_FLAG.find(category);
+ assert(it != LOG_CATEGORIES_BY_FLAG.end());
+ return it->second;
}
static std::optional<BCLog::Level> GetLogLevel(const std::string& level_str)
@@ -312,18 +251,11 @@ static std::optional<BCLog::Level> GetLogLevel(const std::string& level_str)
std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const
{
- // Sort log categories by alphabetical order.
- std::array<CLogCategoryDesc, std::size(LogCategories)> categories;
- std::copy(std::begin(LogCategories), std::end(LogCategories), categories.begin());
- std::sort(categories.begin(), categories.end(), [](auto a, auto b) { return a.category < b.category; });
-
std::vector<LogCategory> ret;
- for (const CLogCategoryDesc& category_desc : categories) {
- if (category_desc.flag == BCLog::NONE || category_desc.flag == BCLog::ALL) continue;
- LogCategory catActive;
- catActive.category = category_desc.category;
- catActive.active = WillLogCategory(category_desc.flag);
- ret.push_back(catActive);
+ for (const auto& [category, flag] : LOG_CATEGORIES_BY_STR) {
+ if (flag != BCLog::NONE && flag != BCLog::ALL) {
+ ret.push_back(LogCategory{.category = category, .active = WillLogCategory(flag)});
+ }
}
return ret;
}
diff --git a/src/logging.h b/src/logging.h
index 2d358a52f1..cfef65221f 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -65,11 +65,10 @@ namespace BCLog {
#ifdef DEBUG_LOCKCONTENTION
LOCK = (1 << 24),
#endif
- UTIL = (1 << 25),
- BLOCKSTORAGE = (1 << 26),
- TXRECONCILIATION = (1 << 27),
- SCAN = (1 << 28),
- TXPACKAGES = (1 << 29),
+ BLOCKSTORAGE = (1 << 25),
+ TXRECONCILIATION = (1 << 26),
+ SCAN = (1 << 27),
+ TXPACKAGES = (1 << 28),
ALL = ~(uint32_t)0,
};
enum class Level {
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index c75f5c5e60..669c6e3b70 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -54,6 +54,7 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std:
txn = CPartialMerkleTree(vHashes, vMatch);
}
+// NOLINTNEXTLINE(misc-no-recursion)
uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
//we can never have zero txs in a merkle block, we always need the coinbase tx
//if we do not have this assert, we can hit a memory access violation when indexing into vTxid
@@ -74,6 +75,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve
}
}
+// NOLINTNEXTLINE(misc-no-recursion)
void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) {
// determine whether this node is the parent of at least one matched txid
bool fParentOfMatch = false;
@@ -92,6 +94,7 @@ void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const st
}
}
+// NOLINTNEXTLINE(misc-no-recursion)
uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {
if (nBitsUsed >= vBits.size()) {
// overflowed the bits array - failure
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 6996af38cb..39ffff97d2 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1006,7 +1006,7 @@ private:
/** Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
* The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
* these are kept in a ring buffer */
- std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex);
+ std::vector<CTransactionRef> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex);
/** Offset into vExtraTxnForCompact to insert the next tx */
size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0;
@@ -1802,7 +1802,7 @@ void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)
return;
if (!vExtraTxnForCompact.size())
vExtraTxnForCompact.resize(m_opts.max_extra_txs);
- vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
+ vExtraTxnForCompact[vExtraTxnForCompactIt] = tx;
vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
}
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index f9a372e3de..4d2d83812e 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -406,6 +406,7 @@ public:
NodeContext* m_context{nullptr};
};
+// NOLINTNEXTLINE(misc-no-recursion)
bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active, const BlockManager& blockman)
{
if (!index) return false;
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index a2c6990657..84c3352b9d 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -190,9 +190,7 @@ std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(
CAmount replacement_fees,
int64_t replacement_vsize)
{
- // Require that the replacement strictly improve the mempool's feerate diagram.
- std::vector<FeeFrac> old_diagram, new_diagram;
-
+ // Require that the replacement strictly improves the mempool's feerate diagram.
const auto diagram_results{pool.CalculateFeerateDiagramsForRBF(replacement_fees, replacement_vsize, direct_conflicts, all_conflicts)};
if (!diagram_results.has_value()) {
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d816a72ca3..d0f7c64357 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -396,6 +396,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
return successful;
}
+// NOLINTNEXTLINE(misc-no-recursion)
QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) const
{
auto setting = [&]{ return node().getPersistentSetting(SettingName(option) + suffix); };
@@ -508,6 +509,7 @@ QFont OptionsModel::getFontForMoney() const
return getFontForChoice(m_font_money);
}
+// NOLINTNEXTLINE(misc-no-recursion)
bool OptionsModel::setOption(OptionID option, const QVariant& value, const std::string& suffix)
{
auto changed = [&] { return value.isValid() && value != getOption(option, suffix); };
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index da81a61651..123b5cc06c 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -13,6 +13,7 @@
#include <compat/compat.h>
#include <compat/cpuid.h>
#include <crypto/sha512.h>
+#include <span.h>
#include <support/cleanse.h>
#include <util/time.h>
@@ -357,10 +358,19 @@ void RandAddStaticEnv(CSHA512& hasher)
hasher << &hasher << &RandAddStaticEnv << &malloc << &errno << &environ;
// Hostname
+#ifdef WIN32
+ constexpr DWORD max_size = MAX_COMPUTERNAME_LENGTH + 1;
+ char hname[max_size];
+ DWORD size = max_size;
+ if (GetComputerNameA(hname, &size) != 0) {
+ hasher.Write(UCharCast(hname), size);
+ }
+#else
char hname[256];
if (gethostname(hname, 256) == 0) {
hasher.Write((const unsigned char*)hname, strnlen(hname, 256));
}
+#endif
#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
// Network interfaces
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index eb05f33b42..b8dc148eae 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -277,6 +277,11 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "logging", 1, "exclude" },
{ "disconnectnode", 1, "nodeid" },
{ "upgradewallet", 0, "version" },
+ { "gethdkeys", 0, "active_only" },
+ { "gethdkeys", 0, "options" },
+ { "gethdkeys", 0, "private" },
+ { "createwalletdescriptor", 1, "options" },
+ { "createwalletdescriptor", 1, "internal" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 51c88cc1ba..6e332e3855 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -414,6 +414,7 @@ struct Sections {
/**
* Recursive helper to translate an RPCArg into sections
*/
+ // NOLINTNEXTLINE(misc-no-recursion)
void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NONE)
{
const auto indent = std::string(current_indent, ' ');
@@ -953,6 +954,7 @@ std::string RPCArg::ToDescriptionString(bool is_named_arg) const
return ret;
}
+// NOLINTNEXTLINE(misc-no-recursion)
void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const int current_indent) const
{
// Indentation
@@ -1086,6 +1088,7 @@ static std::optional<UniValue::VType> ExpectedType(RPCResult::Type type)
NONFATAL_UNREACHABLE();
}
+// NOLINTNEXTLINE(misc-no-recursion)
UniValue RPCResult::MatchesType(const UniValue& result) const
{
if (m_skip_type_check) {
@@ -1164,6 +1167,7 @@ void RPCResult::CheckInnerDoc() const
CHECK_NONFATAL(inner_needed != m_inner.empty());
}
+// NOLINTNEXTLINE(misc-no-recursion)
std::string RPCArg::ToStringObj(const bool oneline) const
{
std::string res;
@@ -1202,6 +1206,7 @@ std::string RPCArg::ToStringObj(const bool oneline) const
NONFATAL_UNREACHABLE();
}
+// NOLINTNEXTLINE(misc-no-recursion)
std::string RPCArg::ToString(const bool oneline) const
{
if (oneline && !m_opts.oneline_description.empty()) {
@@ -1228,6 +1233,7 @@ std::string RPCArg::ToString(const bool oneline) const
case Type::OBJ:
case Type::OBJ_NAMED_PARAMS:
case Type::OBJ_USER_KEYS: {
+ // NOLINTNEXTLINE(misc-no-recursion)
const std::string res = Join(m_inner, ",", [&](const RPCArg& i) { return i.ToStringObj(oneline); });
if (m_type == Type::OBJ) {
return "{" + res + "}";
diff --git a/src/rpc/util.h b/src/rpc/util.h
index ad3ed97b2e..f6ee6a317a 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -162,6 +162,7 @@ struct RPCArgOptions {
//!< methods set the also_positional flag and read values from both positions.
};
+// NOLINTNEXTLINE(misc-no-recursion)
struct RPCArg {
enum class Type {
OBJ,
@@ -271,6 +272,7 @@ struct RPCArg {
std::string ToDescriptionString(bool is_named_arg) const;
};
+// NOLINTNEXTLINE(misc-no-recursion)
struct RPCResult {
enum class Type {
OBJ,
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
deleted file mode 100644
index c4eccacf41..0000000000
--- a/src/script/bitcoinconsensus.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-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 <script/bitcoinconsensus.h>
-
-#include <primitives/transaction.h>
-#include <pubkey.h>
-#include <script/interpreter.h>
-
-namespace {
-
-/** A class that deserializes a single CTransaction one time. */
-class TxInputStream
-{
-public:
- TxInputStream(const unsigned char *txTo, size_t txToLen) :
- m_data(txTo),
- m_remaining(txToLen)
- {}
-
- void read(Span<std::byte> dst)
- {
- if (dst.size() > m_remaining) {
- throw std::ios_base::failure(std::string(__func__) + ": end of data");
- }
-
- if (dst.data() == nullptr) {
- throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
- }
-
- if (m_data == nullptr) {
- throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
- }
-
- memcpy(dst.data(), m_data, dst.size());
- m_remaining -= dst.size();
- m_data += dst.size();
- }
-
- template<typename T>
- TxInputStream& operator>>(T&& obj)
- {
- ::Unserialize(*this, obj);
- return *this;
- }
-
-private:
- const unsigned char* m_data;
- size_t m_remaining;
-};
-
-inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
-{
- if (ret)
- *ret = serror;
- return 0;
-}
-
-} // namespace
-
-/** Check that all specified flags are part of the libconsensus interface. */
-static bool verify_flags(unsigned int flags)
-{
- return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
-}
-
-static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
- const unsigned char *txTo , unsigned int txToLen,
- const UTXO *spentOutputs, unsigned int spentOutputsLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
-{
- if (!verify_flags(flags)) {
- return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS);
- }
-
- if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT && spentOutputs == nullptr) {
- return set_error(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED);
- }
-
- try {
- TxInputStream stream(txTo, txToLen);
- CTransaction tx(deserialize, TX_WITH_WITNESS, stream);
-
- std::vector<CTxOut> spent_outputs;
- if (spentOutputs != nullptr) {
- if (spentOutputsLen != tx.vin.size()) {
- return set_error(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH);
- }
- for (size_t i = 0; i < spentOutputsLen; i++) {
- CScript spk = CScript(spentOutputs[i].scriptPubKey, spentOutputs[i].scriptPubKey + spentOutputs[i].scriptPubKeySize);
- const CAmount& value = spentOutputs[i].value;
- CTxOut tx_out = CTxOut(value, spk);
- spent_outputs.push_back(tx_out);
- }
- }
-
- if (nIn >= tx.vin.size())
- return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
- if (GetSerializeSize(TX_WITH_WITNESS(tx)) != txToLen)
- return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
-
- // Regardless of the verification result, the tx did not error.
- set_error(err, bitcoinconsensus_ERR_OK);
-
- PrecomputedTransactionData txdata(tx);
-
- if (spentOutputs != nullptr && flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT) {
- txdata.Init(tx, std::move(spent_outputs));
- }
-
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
- } catch (const std::exception&) {
- return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
- }
-}
-
-int bitcoinconsensus_verify_script_with_spent_outputs(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
- const unsigned char *txTo , unsigned int txToLen,
- const UTXO *spentOutputs, unsigned int spentOutputsLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
-{
- CAmount am(amount);
- return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
-}
-
-int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
- const unsigned char *txTo , unsigned int txToLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
-{
- CAmount am(amount);
- UTXO *spentOutputs = nullptr;
- unsigned int spentOutputsLen = 0;
- return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
-}
-
-
-int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
- const unsigned char *txTo , unsigned int txToLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
-{
- if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
- return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
- }
-
- CAmount am(0);
- UTXO *spentOutputs = nullptr;
- unsigned int spentOutputsLen = 0;
- return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
-}
-
-unsigned int bitcoinconsensus_version()
-{
- // Just use the API version for now
- return BITCOINCONSENSUS_API_VER;
-}
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
deleted file mode 100644
index a202b5ba06..0000000000
--- a/src/script/bitcoinconsensus.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_SCRIPT_BITCOINCONSENSUS_H
-#define BITCOIN_SCRIPT_BITCOINCONSENSUS_H
-
-#include <stdint.h>
-
-#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
- #if defined(_WIN32)
- #if defined(HAVE_DLLEXPORT_ATTRIBUTE)
- #define EXPORT_SYMBOL __declspec(dllexport)
- #else
- #define EXPORT_SYMBOL
- #endif
- #elif defined(HAVE_DEFAULT_VISIBILITY_ATTRIBUTE)
- #define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
- #endif
-#elif defined(MSC_VER) && !defined(STATIC_LIBBITCOINCONSENSUS)
- #define EXPORT_SYMBOL __declspec(dllimport)
-#endif
-
-#ifndef EXPORT_SYMBOL
- #define EXPORT_SYMBOL
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define BITCOINCONSENSUS_API_VER 2
-
-typedef enum bitcoinconsensus_error_t
-{
- bitcoinconsensus_ERR_OK = 0,
- bitcoinconsensus_ERR_TX_INDEX,
- bitcoinconsensus_ERR_TX_SIZE_MISMATCH,
- bitcoinconsensus_ERR_TX_DESERIALIZE,
- bitcoinconsensus_ERR_AMOUNT_REQUIRED,
- bitcoinconsensus_ERR_INVALID_FLAGS,
- bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED,
- bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH
-} bitcoinconsensus_error;
-
-/** Script verification flags */
-enum
-{
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY = (1U << 4), // enforce NULLDUMMY (BIP147)
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), // enable CHECKSEQUENCEVERIFY (BIP112)
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141)
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT = (1U << 17), // enable TAPROOT (BIPs 341 & 342)
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL = bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG |
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY |
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS |
- bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT
-};
-
-typedef struct {
- const unsigned char *scriptPubKey;
- unsigned int scriptPubKeySize;
- int64_t value;
-} UTXO;
-
-/// Returns 1 if the input nIn of the serialized transaction pointed to by
-/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under
-/// the additional constraints specified by flags.
-/// If not nullptr, err will contain an error/success code for the operation
-EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
- const unsigned char *txTo , unsigned int txToLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
-
-EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
- const unsigned char *txTo , unsigned int txToLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
-
-EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_spent_outputs(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
- const unsigned char *txTo , unsigned int txToLen,
- const UTXO *spentOutputs, unsigned int spentOutputsLen,
- unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
-
-EXPORT_SYMBOL unsigned int bitcoinconsensus_version();
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#undef EXPORT_SYMBOL
-
-#endif // BITCOIN_SCRIPT_BITCOINCONSENSUS_H
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index c6bc5f8f1d..a11d4dcbd5 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -212,6 +212,11 @@ public:
/** Derive a private key, if private data is available in arg. */
virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
+
+ /** Return the non-extended public key for this PubkeyProvider, if it has one. */
+ virtual std::optional<CPubKey> GetRootPubKey() const = 0;
+ /** Return the extended public key for this PubkeyProvider, if it has one. */
+ virtual std::optional<CExtPubKey> GetRootExtPubKey() const = 0;
};
class OriginPubkeyProvider final : public PubkeyProvider
@@ -265,6 +270,14 @@ public:
{
return m_provider->GetPrivKey(pos, arg, key);
}
+ std::optional<CPubKey> GetRootPubKey() const override
+ {
+ return m_provider->GetRootPubKey();
+ }
+ std::optional<CExtPubKey> GetRootExtPubKey() const override
+ {
+ return m_provider->GetRootExtPubKey();
+ }
};
/** An object representing a parsed constant public key in a descriptor. */
@@ -310,6 +323,14 @@ public:
{
return arg.GetKey(m_pubkey.GetID(), key);
}
+ std::optional<CPubKey> GetRootPubKey() const override
+ {
+ return m_pubkey;
+ }
+ std::optional<CExtPubKey> GetRootExtPubKey() const override
+ {
+ return std::nullopt;
+ }
};
enum class DeriveType {
@@ -525,6 +546,14 @@ public:
key = extkey.key;
return true;
}
+ std::optional<CPubKey> GetRootPubKey() const override
+ {
+ return std::nullopt;
+ }
+ std::optional<CExtPubKey> GetRootExtPubKey() const override
+ {
+ return m_root_extkey;
+ }
};
/** Base class for all Descriptor implementations. */
@@ -570,6 +599,7 @@ public:
COMPAT, // string calculation that mustn't change over time to stay compatible with previous software versions
};
+ // NOLINTNEXTLINE(misc-no-recursion)
bool IsSolvable() const override
{
for (const auto& arg : m_subdescriptor_args) {
@@ -578,6 +608,7 @@ public:
return true;
}
+ // NOLINTNEXTLINE(misc-no-recursion)
bool IsRange() const final
{
for (const auto& pubkey : m_pubkey_args) {
@@ -589,6 +620,7 @@ public:
return false;
}
+ // NOLINTNEXTLINE(misc-no-recursion)
virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const
{
size_t pos = 0;
@@ -601,6 +633,7 @@ public:
return true;
}
+ // NOLINTNEXTLINE(misc-no-recursion)
virtual bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr) const
{
std::string extra = ToStringExtra();
@@ -653,6 +686,7 @@ public:
return ret;
}
+ // NOLINTNEXTLINE(misc-no-recursion)
bool ExpandHelper(int pos, const SigningProvider& arg, const DescriptorCache* read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache) const
{
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
@@ -694,6 +728,7 @@ public:
return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &read_cache, output_scripts, out, nullptr);
}
+ // NOLINTNEXTLINE(misc-no-recursion)
void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
{
for (const auto& p : m_pubkey_args) {
@@ -720,6 +755,20 @@ public:
std::optional<int64_t> MaxSatisfactionWeight(bool) const override { return {}; }
std::optional<int64_t> MaxSatisfactionElems() const override { return {}; }
+
+ // NOLINTNEXTLINE(misc-no-recursion)
+ void GetPubKeys(std::set<CPubKey>& pubkeys, std::set<CExtPubKey>& ext_pubs) const override
+ {
+ for (const auto& p : m_pubkey_args) {
+ std::optional<CPubKey> pub = p->GetRootPubKey();
+ if (pub) pubkeys.insert(*pub);
+ std::optional<CExtPubKey> ext_pub = p->GetRootExtPubKey();
+ if (ext_pub) ext_pubs.insert(*ext_pub);
+ }
+ for (const auto& arg : m_subdescriptor_args) {
+ arg->GetPubKeys(pubkeys, ext_pubs);
+ }
+ }
};
/** A parsed addr(A) descriptor. */
@@ -1537,6 +1586,7 @@ struct KeyParser {
};
/** Parse a script in a particular context. */
+// NOLINTNEXTLINE(misc-no-recursion)
std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
{
using namespace spanparsing;
@@ -1844,6 +1894,7 @@ std::unique_ptr<DescriptorImpl> InferMultiA(const CScript& script, ParseScriptCo
return std::make_unique<MultiADescriptor>(match->first, std::move(keys));
}
+// NOLINTNEXTLINE(misc-no-recursion)
std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
{
if (ctx == ParseScriptContext::P2TR && script.size() == 34 && script[0] == 32 && script[33] == OP_CHECKSIG) {
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index caa5d1608d..e78a775330 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -158,6 +158,13 @@ struct Descriptor {
/** Get the maximum size number of stack elements for satisfying this descriptor. */
virtual std::optional<int64_t> MaxSatisfactionElems() const = 0;
+
+ /** Return all (extended) public keys for this descriptor, including any from subdescriptors.
+ *
+ * @param[out] pubkeys Any public keys
+ * @param[out] ext_pubs Any extended public keys
+ */
+ virtual void GetPubKeys(std::set<CPubKey>& pubkeys, std::set<CExtPubKey>& ext_pubs) const = 0;
};
/** Parse a `descriptor` string. Included private keys are put in `out`.
diff --git a/src/script/miniscript.h b/src/script/miniscript.h
index 76b952350b..f635fa7340 100644
--- a/src/script/miniscript.h
+++ b/src/script/miniscript.h
@@ -1617,7 +1617,7 @@ public:
//! Produce a witness for this script, if possible and given the information available in the context.
//! The non-malleable satisfaction is guaranteed to be valid if it exists, and ValidSatisfaction()
//! is true. If IsSane() holds, this satisfaction is guaranteed to succeed in case the node's
- //! conditions are satisfied (private keys and hash preimages available, locktimes satsified).
+ //! conditions are satisfied (private keys and hash preimages available, locktimes satisfied).
template<typename Ctx>
Availability Satisfy(const Ctx& ctx, std::vector<std::vector<unsigned char>>& stack, bool nonmalleable = true) const {
auto ret = ProduceInput(ctx);
diff --git a/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml b/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml
index 094ff891f7..ce10eb2686 100644
--- a/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml
+++ b/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml
@@ -16,7 +16,7 @@ runs:
cat valgrind_fingerprint
shell: bash
- - uses: actions/cache@v3
+ - uses: actions/cache@v4
id: cache
with:
path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }}
diff --git a/src/secp256k1/.github/actions/run-in-docker-action/action.yml b/src/secp256k1/.github/actions/run-in-docker-action/action.yml
index dbfaa4fece..74933686a0 100644
--- a/src/secp256k1/.github/actions/run-in-docker-action/action.yml
+++ b/src/secp256k1/.github/actions/run-in-docker-action/action.yml
@@ -36,6 +36,11 @@ runs:
load: true
cache-from: type=gha
+ - # Workaround for https://github.com/google/sanitizers/issues/1614 .
+ # The underlying issue has been fixed in clang 18.1.3.
+ run: sudo sysctl -w vm.mmap_rnd_bits=28
+ shell: bash
+
- # Tell Docker to pass environment variables in `env` into the container.
run: >
docker run \
diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt
index cf0dc3ba93..9ef7defe51 100644
--- a/src/secp256k1/CMakeLists.txt
+++ b/src/secp256k1/CMakeLists.txt
@@ -51,29 +51,40 @@ endif()
option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
-option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
-if(SECP256K1_ENABLE_MODULE_ECDH)
- add_compile_definitions(ENABLE_MODULE_ECDH=1)
-endif()
+## Modules
+# We declare all options before processing them, to make sure we can express
+# dependendencies while processing.
+option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
-if(SECP256K1_ENABLE_MODULE_RECOVERY)
- add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
-endif()
-
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
+option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
+
+# Processing must be done in a topological sorting of the dependency graph
+# (dependent module first).
+if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
+ add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
+endif()
+
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
+ endif()
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
endif()
+
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
endif()
-option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
-if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
- add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
+if(SECP256K1_ENABLE_MODULE_RECOVERY)
+ add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_ECDH)
+ add_compile_definitions(ENABLE_MODULE_ECDH=1)
endif()
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
@@ -254,9 +265,14 @@ if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUST
enable_testing()
endif()
+set(SECP256K1_LATE_CFLAGS "" CACHE STRING "Compiler flags that are added to the command line after all other flags added by the build system.")
+include(AllTargetsCompileOptions)
+
add_subdirectory(src)
+all_targets_compile_options(src "${SECP256K1_LATE_CFLAGS}")
if(SECP256K1_BUILD_EXAMPLES)
add_subdirectory(examples)
+ all_targets_compile_options(examples "${SECP256K1_LATE_CFLAGS}")
endif()
message("\n")
@@ -330,6 +346,9 @@ else()
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
endif()
+if(SECP256K1_LATE_CFLAGS)
+ message("SECP256K1_LATE_CFLAGS ................. ${SECP256K1_LATE_CFLAGS}")
+endif()
message("\n")
if(SECP256K1_EXPERIMENTAL)
message(
diff --git a/src/secp256k1/CONTRIBUTING.md b/src/secp256k1/CONTRIBUTING.md
index a5e457913a..5fbf7332c9 100644
--- a/src/secp256k1/CONTRIBUTING.md
+++ b/src/secp256k1/CONTRIBUTING.md
@@ -44,7 +44,7 @@ The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Co
In addition, libsecp256k1 tries to maintain the following coding conventions:
-* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Morever, it should be possible to use the library without any heap allocations.
+* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations.
* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)).
* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)).
* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory.
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 4013e6a93b..6e88eb4ecb 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -79,9 +79,9 @@ To maintain a pristine source tree, CMake encourages to perform an out-of-source
$ mkdir build && cd build
$ cmake ..
- $ make
- $ make check # run the test suite
- $ sudo make install # optional
+ $ cmake --build .
+ $ ctest # run the test suite
+ $ sudo cmake --build . --target install # optional
To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags.
diff --git a/src/secp256k1/ci/ci.sh b/src/secp256k1/ci/ci.sh
index 9cc715955e..3999af4f1c 100755
--- a/src/secp256k1/ci/ci.sh
+++ b/src/secp256k1/ci/ci.sh
@@ -17,7 +17,8 @@ print_environment() {
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
EXAMPLES \
HOST WRAPPER_CMD \
- CC CFLAGS CPPFLAGS AR NM
+ CC CFLAGS CPPFLAGS AR NM \
+ UBSAN_OPTIONS ASAN_OPTIONS LSAN_OPTIONS
do
eval "isset=\${$var+x}"
if [ -n "$isset" ]; then
diff --git a/src/secp256k1/cmake/AllTargetsCompileOptions.cmake b/src/secp256k1/cmake/AllTargetsCompileOptions.cmake
new file mode 100644
index 0000000000..6e420e0fde
--- /dev/null
+++ b/src/secp256k1/cmake/AllTargetsCompileOptions.cmake
@@ -0,0 +1,12 @@
+# Add compile options to all targets added in the subdirectory.
+function(all_targets_compile_options dir options)
+ get_directory_property(targets DIRECTORY ${dir} BUILDSYSTEM_TARGETS)
+ separate_arguments(options)
+ set(compiled_target_types STATIC_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY EXECUTABLE)
+ foreach(target ${targets})
+ get_target_property(type ${target} TYPE)
+ if(type IN_LIST compiled_target_types)
+ target_compile_options(${target} PRIVATE ${options})
+ endif()
+ endforeach()
+endfunction()
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 2c1596775e..158ed5d769 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -387,29 +387,32 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
### Handle module options
###
-if test x"$enable_module_ecdh" = x"yes"; then
- SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
-fi
-
-if test x"$enable_module_recovery" = x"yes"; then
- SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1"
+# Processing must be done in a reverse topological sorting of the dependency graph
+# (dependent module first).
+if test x"$enable_module_ellswift" = x"yes"; then
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
fi
if test x"$enable_module_schnorrsig" = x"yes"; then
- SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
+ if test x"$enable_module_extrakeys" = x"no"; then
+ AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.])
+ fi
enable_module_extrakeys=yes
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
fi
-if test x"$enable_module_ellswift" = x"yes"; then
- SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
-fi
-
-# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
-# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1"
fi
+if test x"$enable_module_recovery" = x"yes"; then
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1"
+fi
+
+if test x"$enable_module_ecdh" = x"yes"; then
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
+fi
+
if test x"$enable_external_default_callbacks" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
fi
diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h
index 034a38e6a0..37c8c691f2 100644
--- a/src/secp256k1/contrib/lax_der_parsing.h
+++ b/src/secp256k1/contrib/lax_der_parsing.h
@@ -67,8 +67,8 @@ extern "C" {
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
* Args: ctx: a secp256k1 context object
- * Out: sig: a pointer to a signature object
- * In: input: a pointer to the signature to be parsed
+ * Out: sig: pointer to a signature object
+ * In: input: pointer to the signature to be parsed
* inputlen: the length of the array pointed to be input
*
* This function will accept any valid DER encoded signature, even if the
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
index 51e337a5ab..cdf62430df 100644
--- a/src/secp256k1/doc/release-process.md
+++ b/src/secp256k1/doc/release-process.md
@@ -1,4 +1,4 @@
-# Release Process
+# Release process
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
@@ -14,31 +14,30 @@ This process also assumes that there will be no minor releases for old major rel
We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
-## Sanity Checks
-Perform these checks before creating a release:
+## Sanity checks
+Perform these checks when reviewing the release PR (see below):
1. Ensure `make distcheck` doesn't fail.
-```shell
-./autogen.sh && ./configure --enable-dev-mode && make distcheck
-```
+ ```shell
+ ./autogen.sh && ./configure --enable-dev-mode && make distcheck
+ ```
2. Check installation with autotools:
-```shell
-dir=$(mktemp -d)
-./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir
-gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
-```
+ ```shell
+ dir=$(mktemp -d)
+ ./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir
+ gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
+ ```
3. Check installation with CMake:
-```shell
-dir=$(mktemp -d)
-build=$(mktemp -d)
-cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -RlAh $dir
-gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
-```
-4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to ensure there are no unexpected ABI incompatibilities and that the version number and release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required.
-
-```shell
-tools/check-abi.sh
-```
+ ```shell
+ dir=$(mktemp -d)
+ build=$(mktemp -d)
+ cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -RlAh $dir
+ gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
+ ```
+4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required.
+ ```shell
+ tools/check-abi.sh
+ ```
## Regular release
@@ -47,27 +46,29 @@ tools/check-abi.sh
* adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
* removing the `[Unreleased]` section header, and
* including an entry for `### ABI Compatibility` if it doesn't exist,
- * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
- * if this is not a patch release
- * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
+ * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and,
+ * if this is not a patch release,
+ * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and
* updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
-2. After the PR is merged, tag the commit and push it:
+2. Perform the [sanity checks](#sanity-checks) on the PR branch.
+3. After the PR is merged, tag the commit, and push the tag:
```
RELEASE_COMMIT=<merge commit of step 1>
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
-3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
+4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
* sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
* adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
If other maintainers are not present to approve the PR, it can be merged without ACKs.
-4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
+5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
+6. Send an announcement email to the bitcoin-dev mailing list.
## Maintenance release
-Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
+Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists.
1. If there's no maintenance branch `$MAJOR.$MINOR`, create one:
```
@@ -75,19 +76,18 @@ Note that bugfixes only need to be backported to releases for which no compatibl
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
```
2. Open a pull request to the `$MAJOR.$MINOR` branch that
- * includes the bugfixes,
+ * includes the bug fixes,
* finalizes the release notes similar to a regular release,
* increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
-3. After the PRs are merged, update the release branch and tag the commit:
+3. Perform the [sanity checks](#sanity-checks) on the PR branch.
+4. After the PRs are merged, update the release branch, tag the commit, and push the tag:
```
git checkout $MAJOR.$MINOR && git pull
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
- ```
-4. Push tag:
- ```
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
-5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
-6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).
+6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
+7. Send an announcement email to the bitcoin-dev mailing list.
+8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 936f0b42b7..f4053f2a93 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -265,7 +265,7 @@ SECP256K1_API void secp256k1_selftest(void);
* memory allocation entirely, see secp256k1_context_static and the functions in
* secp256k1_preallocated.h.
*
- * Returns: a newly created context object.
+ * Returns: pointer to a newly created context object.
* In: flags: Always set to SECP256K1_CONTEXT_NONE (see below).
*
* The only valid non-deprecated flag in recent library versions is
@@ -296,8 +296,8 @@ SECP256K1_API secp256k1_context *secp256k1_context_create(
* Cloning secp256k1_context_static is not possible, and should not be emulated by
* the caller (e.g., using memcpy). Create a new context instead.
*
- * Returns: a newly created context object.
- * Args: ctx: an existing context to copy (not secp256k1_context_static)
+ * Returns: pointer to a newly created context object.
+ * Args: ctx: pointer to a context to copy (not secp256k1_context_static).
*/
SECP256K1_API secp256k1_context *secp256k1_context_clone(
const secp256k1_context *ctx
@@ -313,7 +313,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_clone(
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
* be used instead.
*
- * Args: ctx: an existing context to destroy, constructed using
+ * Args: ctx: pointer to a context to destroy, constructed using
* secp256k1_context_create or secp256k1_context_clone
* (i.e., not secp256k1_context_static).
*/
@@ -350,8 +350,8 @@ SECP256K1_API void secp256k1_context_destroy(
* fails. In this case, the corresponding default handler will be called with
* the data pointer argument set to NULL.
*
- * Args: ctx: an existing context object.
- * In: fun: a pointer to a function to call when an illegal argument is
+ * Args: ctx: pointer to a context object.
+ * In: fun: pointer to a function to call when an illegal argument is
* passed to the API, taking a message and an opaque pointer.
* (NULL restores the default handler.)
* data: the opaque pointer to pass to fun above, must be NULL for the default handler.
@@ -377,8 +377,8 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
* for that). After this callback returns, anything may happen, including
* crashing.
*
- * Args: ctx: an existing context object.
- * In: fun: a pointer to a function to call when an internal error occurs,
+ * Args: ctx: pointer to a context object.
+ * In: fun: pointer to a function to call when an internal error occurs,
* taking a message and an opaque pointer (NULL restores the
* default handler, see secp256k1_context_set_illegal_callback
* for details).
@@ -395,7 +395,7 @@ SECP256K1_API void secp256k1_context_set_error_callback(
/** Create a secp256k1 scratch space object.
*
* Returns: a newly created scratch space.
- * Args: ctx: an existing context object.
+ * Args: ctx: pointer to a context object.
* In: size: amount of memory to be available as scratch space. Some extra
* (<100 bytes) will be allocated for extra accounting.
*/
@@ -407,7 +407,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_sc
/** Destroy a secp256k1 scratch space.
*
* The pointer may not be used afterwards.
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object.
* scratch: space to destroy
*/
SECP256K1_API void secp256k1_scratch_space_destroy(
@@ -419,7 +419,7 @@ SECP256K1_API void secp256k1_scratch_space_destroy(
*
* Returns: 1 if the public key was fully valid.
* 0 if the public key could not be parsed or is invalid.
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object.
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
* parsed version of input. If not, its value is undefined.
* In: input: pointer to a serialized public key
@@ -439,14 +439,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
/** Serialize a pubkey object into a serialized byte sequence.
*
* Returns: 1 always.
- * Args: ctx: a secp256k1 context object.
- * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if
+ * Args: ctx: pointer to a context object.
+ * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if
* compressed==1) byte array to place the serialized key
* in.
- * In/Out: outputlen: a pointer to an integer which is initially set to the
+ * In/Out: outputlen: pointer to an integer which is initially set to the
* size of output, and is overwritten with the written
* size.
- * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * In: pubkey: pointer to a secp256k1_pubkey containing an
* initialized public key.
* flags: SECP256K1_EC_COMPRESSED if serialization should be in
* compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
@@ -464,7 +464,7 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize(
* Returns: <0 if the first public key is less than the second
* >0 if the first public key is greater than the second
* 0 if the two public keys are equal
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
*/
@@ -477,9 +477,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
/** Parse an ECDSA signature in compact (64 bytes) format.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
- * Args: ctx: a secp256k1 context object
- * Out: sig: a pointer to a signature object
- * In: input64: a pointer to the 64-byte array to parse
+ * Args: ctx: pointer to a context object
+ * Out: sig: pointer to a signature object
+ * In: input64: pointer to the 64-byte array to parse
*
* The signature must consist of a 32-byte big endian R value, followed by a
* 32-byte big endian S value. If R or S fall outside of [0..order-1], the
@@ -498,9 +498,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
/** Parse a DER ECDSA signature.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
- * Args: ctx: a secp256k1 context object
- * Out: sig: a pointer to a signature object
- * In: input: a pointer to the signature to be parsed
+ * Args: ctx: pointer to a context object
+ * Out: sig: pointer to a signature object
+ * In: input: pointer to the signature to be parsed
* inputlen: the length of the array pointed to be input
*
* This function will accept any valid DER encoded signature, even if the
@@ -520,13 +520,13 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
/** Serialize an ECDSA signature in DER format.
*
* Returns: 1 if enough space was available to serialize, 0 otherwise
- * Args: ctx: a secp256k1 context object
- * Out: output: a pointer to an array to store the DER serialization
- * In/Out: outputlen: a pointer to a length integer. Initially, this integer
+ * Args: ctx: pointer to a context object
+ * Out: output: pointer to an array to store the DER serialization
+ * In/Out: outputlen: pointer to a length integer. Initially, this integer
* should be set to the length of output. After the call
* it will be set to the length of the serialization (even
* if 0 was returned).
- * In: sig: a pointer to an initialized signature object
+ * In: sig: pointer to an initialized signature object
*/
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
const secp256k1_context *ctx,
@@ -538,9 +538,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
/** Serialize an ECDSA signature in compact (64 byte) format.
*
* Returns: 1
- * Args: ctx: a secp256k1 context object
- * Out: output64: a pointer to a 64-byte array to store the compact serialization
- * In: sig: a pointer to an initialized signature object
+ * Args: ctx: pointer to a context object
+ * Out: output64: pointer to a 64-byte array to store the compact serialization
+ * In: sig: pointer to an initialized signature object
*
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
*/
@@ -554,7 +554,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
*
* Returns: 1: correct signature
* 0: incorrect or unparseable signature
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object
* In: sig: the signature being verified.
* msghash32: the 32-byte message hash being verified.
* The verifier must make sure to apply a cryptographic
@@ -585,12 +585,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
/** Convert a signature to a normalized lower-S form.
*
* Returns: 1 if sigin was not normalized, 0 if it already was.
- * Args: ctx: a secp256k1 context object
- * Out: sigout: a pointer to a signature to fill with the normalized form,
+ * Args: ctx: pointer to a context object
+ * Out: sigout: pointer to a signature to fill with the normalized form,
* or copy if the input was already normalized. (can be NULL if
* you're only interested in whether the input was already
* normalized).
- * In: sigin: a pointer to a signature to check/normalize (can be identical to sigout)
+ * In: sigin: pointer to a signature to check/normalize (can be identical to sigout)
*
* With ECDSA a third-party can forge a second distinct signature of the same
* message, given a single initial signature, but without knowing the key. This
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
index 515e174299..4d9da3461d 100644
--- a/src/secp256k1/include/secp256k1_ecdh.h
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -39,7 +39,7 @@ SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_de
* 0: scalar was invalid (zero or overflow) or hashfp returned 0
* Args: ctx: pointer to a context object.
* Out: output: pointer to an array to be filled by hashfp.
- * In: pubkey: a pointer to a secp256k1_pubkey containing an initialized public key.
+ * In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key.
* seckey: a 32-byte scalar with which to multiply the point.
* hashfp: pointer to a hash function. If NULL,
* secp256k1_ecdh_hash_function_sha256 is used
diff --git a/src/secp256k1/include/secp256k1_ellswift.h b/src/secp256k1/include/secp256k1_ellswift.h
index f79bd88396..ae37287f82 100644
--- a/src/secp256k1/include/secp256k1_ellswift.h
+++ b/src/secp256k1/include/secp256k1_ellswift.h
@@ -87,7 +87,7 @@ SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_
* Returns: 1 always.
* Args: ctx: pointer to a context object
* Out: ell64: pointer to a 64-byte array to be filled
- * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * In: pubkey: pointer to a secp256k1_pubkey containing an
* initialized public key
* rnd32: pointer to 32 bytes of randomness
*
@@ -169,7 +169,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
* (will not be NULL)
* ell_b64: pointer to the 64-byte encoded public key of party B
* (will not be NULL)
- * seckey32: a pointer to our 32-byte secret key
+ * seckey32: pointer to our 32-byte secret key
* party: boolean indicating which party we are: zero if we are
* party A, non-zero if we are party B. seckey32 must be
* the private key corresponding to that party's ell_?64.
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
index 7fcce68e68..ad70b92f95 100644
--- a/src/secp256k1/include/secp256k1_extrakeys.h
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -39,7 +39,7 @@ typedef struct {
* Returns: 1 if the public key was fully valid.
* 0 if the public key could not be parsed or is invalid.
*
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object.
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
* parsed version of input. If not, it's set to an invalid value.
* In: input32: pointer to a serialized xonly_pubkey.
@@ -54,9 +54,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
*
* Returns: 1 always.
*
- * Args: ctx: a secp256k1 context object.
- * Out: output32: a pointer to a 32-byte array to place the serialized key in.
- * In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an initialized public key.
+ * Args: ctx: pointer to a context object.
+ * Out: output32: pointer to a 32-byte array to place the serialized key in.
+ * In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key.
*/
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
const secp256k1_context *ctx,
@@ -69,7 +69,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize(
* Returns: <0 if the first public key is less than the second
* >0 if the first public key is greater than the second
* 0 if the two public keys are equal
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object.
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
*/
diff --git a/src/secp256k1/include/secp256k1_preallocated.h b/src/secp256k1/include/secp256k1_preallocated.h
index f37744777b..f2d95c245e 100644
--- a/src/secp256k1/include/secp256k1_preallocated.h
+++ b/src/secp256k1/include/secp256k1_preallocated.h
@@ -52,8 +52,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size(
* in the memory. In simpler words, the prealloc pointer (or any pointer derived
* from it) should not be used during the lifetime of the context object.
*
- * Returns: a newly created context object.
- * In: prealloc: a pointer to a rewritable contiguous block of memory of
+ * Returns: pointer to newly created context object.
+ * In: prealloc: pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above.
* flags: which parts of the context to initialize.
@@ -72,7 +72,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create(
* caller-provided memory.
*
* Returns: the required size of the caller-provided memory block.
- * In: ctx: an existing context to copy.
+ * In: ctx: pointer to a context to copy.
*/
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
const secp256k1_context *ctx
@@ -91,9 +91,9 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
* Cloning secp256k1_context_static is not possible, and should not be emulated by
* the caller (e.g., using memcpy). Create a new context instead.
*
- * Returns: a newly created context object.
- * Args: ctx: an existing context to copy (not secp256k1_context_static).
- * In: prealloc: a pointer to a rewritable contiguous block of memory of
+ * Returns: pointer to a newly created context object.
+ * Args: ctx: pointer to a context to copy (not secp256k1_context_static).
+ * In: prealloc: pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above.
*/
@@ -118,7 +118,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone(
* preallocated pointer given to secp256k1_context_preallocated_create or
* secp256k1_context_preallocated_clone.
*
- * Args: ctx: an existing context to destroy, constructed using
+ * Args: ctx: pointer to a context to destroy, constructed using
* secp256k1_context_preallocated_create or
* secp256k1_context_preallocated_clone
* (i.e., not secp256k1_context_static).
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
index b12ca4d972..341b8bac63 100644
--- a/src/secp256k1/include/secp256k1_recovery.h
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -28,9 +28,9 @@ typedef struct {
/** Parse a compact ECDSA signature (64 bytes + recovery id).
*
* Returns: 1 when the signature could be parsed, 0 otherwise
- * Args: ctx: a secp256k1 context object
- * Out: sig: a pointer to a signature object
- * In: input64: a pointer to a 64-byte compact signature
+ * Args: ctx: pointer to a context object
+ * Out: sig: pointer to a signature object
+ * In: input64: pointer to a 64-byte compact signature
* recid: the recovery id (0, 1, 2 or 3)
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
@@ -43,9 +43,9 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
/** Convert a recoverable signature into a normal signature.
*
* Returns: 1
- * Args: ctx: a secp256k1 context object.
- * Out: sig: a pointer to a normal signature.
- * In: sigin: a pointer to a recoverable signature.
+ * Args: ctx: pointer to a context object.
+ * Out: sig: pointer to a normal signature.
+ * In: sigin: pointer to a recoverable signature.
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
const secp256k1_context *ctx,
@@ -56,10 +56,10 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
*
* Returns: 1
- * Args: ctx: a secp256k1 context object.
- * Out: output64: a pointer to a 64-byte array of the compact signature.
- * recid: a pointer to an integer to hold the recovery id.
- * In: sig: a pointer to an initialized signature object.
+ * Args: ctx: pointer to a context object.
+ * Out: output64: pointer to a 64-byte array of the compact signature.
+ * recid: pointer to an integer to hold the recovery id.
+ * In: sig: pointer to an initialized signature object.
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
const secp256k1_context *ctx,
diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h
index 26358533f6..23163de2fb 100644
--- a/src/secp256k1/include/secp256k1_schnorrsig.h
+++ b/src/secp256k1/include/secp256k1_schnorrsig.h
@@ -169,11 +169,11 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
*
* Returns: 1: correct signature
* 0: incorrect signature
- * Args: ctx: a secp256k1 context object.
+ * Args: ctx: pointer to a context object.
* In: sig64: pointer to the 64-byte signature to verify.
* msg: the message being verified. Can only be NULL if msglen is 0.
* msglen: length of the message
- * pubkey: pointer to an x-only public key to verify with (cannot be NULL)
+ * pubkey: pointer to an x-only public key to verify with
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
const secp256k1_context *ctx,
diff --git a/src/secp256k1/src/assumptions.h b/src/secp256k1/src/assumptions.h
index 8ed04209e9..7961005350 100644
--- a/src/secp256k1/src/assumptions.h
+++ b/src/secp256k1/src/assumptions.h
@@ -19,65 +19,69 @@
reduce the odds of experiencing an unwelcome surprise.
*/
-struct secp256k1_assumption_checker {
- /* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
- allowed. */
- int dummy_array[(
- /* Bytes are 8 bits. */
- (CHAR_BIT == 8) &&
+#if defined(__has_attribute)
+# if __has_attribute(__unavailable__)
+__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function.")))
+# endif
+#endif
+static void secp256k1_assumption_checker(void) {
+ /* Bytes are 8 bits. */
+ STATIC_ASSERT(CHAR_BIT == 8);
- /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
- without signed overflow, which would be undefined behaviour. */
- (UINT_MAX <= UINT32_MAX) &&
+ /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
+ without signed overflow, which would be undefined behaviour. */
+ STATIC_ASSERT(UINT_MAX <= UINT32_MAX);
- /* Conversions from unsigned to signed outside of the bounds of the signed type are
- implementation-defined. Verify that they function as reinterpreting the lower
- bits of the input in two's complement notation. Do this for conversions:
- - from uint(N)_t to int(N)_t with negative result
- - from uint(2N)_t to int(N)_t with negative result
- - from int(2N)_t to int(N)_t with negative result
- - from int(2N)_t to int(N)_t with positive result */
+ /* Conversions from unsigned to signed outside of the bounds of the signed type are
+ implementation-defined. Verify that they function as reinterpreting the lower
+ bits of the input in two's complement notation. Do this for conversions:
+ - from uint(N)_t to int(N)_t with negative result
+ - from uint(2N)_t to int(N)_t with negative result
+ - from int(2N)_t to int(N)_t with negative result
+ - from int(2N)_t to int(N)_t with positive result */
- /* To int8_t. */
- ((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
- ((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
- ((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
- ((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
+ /* To int8_t. */
+ STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55));
+ STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33);
+ STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF);
+ STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34);
- /* To int16_t. */
- ((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
- ((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
- ((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
- ((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
+ /* To int16_t. */
+ STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322);
+ STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C);
+ STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4);
+ STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678);
- /* To int32_t. */
- ((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
- ((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
- ((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
- ((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
+ /* To int32_t. */
+ STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B);
+ STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE);
+ STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8);
+ STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789);
- /* To int64_t. */
- ((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
+ /* To int64_t. */
+ STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL);
#if defined(SECP256K1_INT128_NATIVE)
- ((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
- (((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
- (((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
+ STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL);
+ STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL);
+ STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL);
- /* To int128_t. */
- ((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
+ /* To int128_t. */
+ STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL));
#endif
- /* Right shift on negative signed values is implementation defined. Verify that it
- acts as a right shift in two's complement with sign extension (i.e duplicating
- the top bit into newly added bits). */
- ((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
- ((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
- ((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
- ((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
+ /* Right shift on negative signed values is implementation defined. Verify that it
+ acts as a right shift in two's complement with sign extension (i.e duplicating
+ the top bit into newly added bits). */
+ STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA);
+ STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A);
+ STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48);
+ STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL);
#if defined(SECP256K1_INT128_NATIVE)
- ((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
+ STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL));
#endif
- 1) * 2 - 1];
-};
+
+ /* This function is not supposed to be called. */
+ VERIFY_CHECK(0);
+}
#endif /* SECP256K1_ASSUMPTIONS_H */
diff --git a/src/secp256k1/src/checkmem.h b/src/secp256k1/src/checkmem.h
index f2169decfc..7e333ce5f3 100644
--- a/src/secp256k1/src/checkmem.h
+++ b/src/secp256k1/src/checkmem.h
@@ -30,6 +30,8 @@
* - SECP256K1_CHECKMEM_DEFINE(p, len):
* - marks the len-byte memory pointed to by p as defined data (public data, in the
* context of constant-time checking).
+ * - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len):
+ * - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer.
*
*/
@@ -48,11 +50,16 @@
# define SECP256K1_CHECKMEM_ENABLED 1
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
+# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
# define SECP256K1_CHECKMEM_RUNNING() (1)
# endif
#endif
+#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE
+# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
+#endif
+
/* If valgrind integration is desired (through the VALGRIND define), implement the
* SECP256K1_CHECKMEM_* macros using valgrind. */
#if !defined SECP256K1_CHECKMEM_ENABLED
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index bd589bf8a8..8c65a3aff6 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -255,8 +255,8 @@ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
/** Multiply two field elements.
*
* On input, a and b must be valid field elements; r does not need to be initialized.
- * r and a may point to the same object, but neither can be equal to b. The magnitudes
- * of a and b must not exceed 8.
+ * r and a may point to the same object, but neither may point to the object pointed
+ * to by b. The magnitudes of a and b must not exceed 8.
* Performs {r = a * b}
* On output, r will have magnitude 1, but won't be normalized.
*/
diff --git a/src/secp256k1/src/modules/ellswift/tests_impl.h b/src/secp256k1/src/modules/ellswift/tests_impl.h
index 7d1efbc492..f96e3a1268 100644
--- a/src/secp256k1/src/modules/ellswift/tests_impl.h
+++ b/src/secp256k1/src/modules/ellswift/tests_impl.h
@@ -188,9 +188,9 @@ void run_ellswift_tests(void) {
CHECK(ret == ((testcase->enc_bitmap >> c) & 1));
if (ret) {
secp256k1_fe x2;
- CHECK(check_fe_equal(&t, &testcase->encs[c]));
+ CHECK(fe_equal(&t, &testcase->encs[c]));
secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]);
- CHECK(check_fe_equal(&testcase->x, &x2));
+ CHECK(fe_equal(&testcase->x, &x2));
}
}
}
@@ -203,7 +203,7 @@ void run_ellswift_tests(void) {
CHECK(ret);
ret = secp256k1_pubkey_load(CTX, &ge, &pubkey);
CHECK(ret);
- CHECK(check_fe_equal(&testcase->x, &ge.x));
+ CHECK(fe_equal(&testcase->x, &ge.x));
CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y);
}
for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) {
@@ -290,7 +290,7 @@ void run_ellswift_tests(void) {
secp256k1_ecmult(&resj, &decj, &sec, NULL);
secp256k1_ge_set_gej(&res, &resj);
/* Compare. */
- CHECK(check_fe_equal(&res.x, &share_x));
+ CHECK(fe_equal(&res.x, &share_x));
}
/* Verify the joint behavior of secp256k1_ellswift_xdh */
for (i = 0; i < 200 * COUNT; i++) {
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 7b9c542f07..82cd957f16 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -462,6 +462,14 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
: "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m0, sizeof(m0));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m1, sizeof(m1));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m2, sizeof(m2));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m3, sizeof(m3));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m4, sizeof(m4));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m5, sizeof(m5));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&m6, sizeof(m6));
+
/* Reduce 385 bits into 258. */
__asm__ __volatile__(
/* Preload */
@@ -541,6 +549,12 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
: "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc");
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&p0, sizeof(p0));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&p1, sizeof(p1));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&p2, sizeof(p2));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&p3, sizeof(p3));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&p4, sizeof(p4));
+
/* Reduce 258 bits into 256. */
__asm__ __volatile__(
/* Preload */
@@ -586,6 +600,10 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
: "=g"(c)
: "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
+
+ SECP256K1_CHECKMEM_MSAN_DEFINE(r, sizeof(*r));
+ SECP256K1_CHECKMEM_MSAN_DEFINE(&c, sizeof(c));
+
#else
secp256k1_uint128 c128;
uint64_t c, c0, c1, c2;
@@ -663,7 +681,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
}
-static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) {
+static void secp256k1_scalar_mul_512(uint64_t *l8, const secp256k1_scalar *a, const secp256k1_scalar *b) {
#ifdef USE_ASM_X86_64
const uint64_t *pb = b->d;
__asm__ __volatile__(
@@ -678,7 +696,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
/* (rax,rdx) = a0 * b0 */
"movq %%r15, %%rax\n"
"mulq %%r11\n"
- /* Extract l0 */
+ /* Extract l8[0] */
"movq %%rax, 0(%%rsi)\n"
/* (r8,r9,r10) = (rdx) */
"movq %%rdx, %%r8\n"
@@ -696,7 +714,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
"addq %%rax, %%r8\n"
"adcq %%rdx, %%r9\n"
"adcq $0, %%r10\n"
- /* Extract l1 */
+ /* Extract l8[1] */
"movq %%r8, 8(%%rsi)\n"
"xorq %%r8, %%r8\n"
/* (r9,r10,r8) += a0 * b2 */
@@ -717,7 +735,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
"addq %%rax, %%r9\n"
"adcq %%rdx, %%r10\n"
"adcq $0, %%r8\n"
- /* Extract l2 */
+ /* Extract l8[2] */
"movq %%r9, 16(%%rsi)\n"
"xorq %%r9, %%r9\n"
/* (r10,r8,r9) += a0 * b3 */
@@ -746,7 +764,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
"addq %%rax, %%r10\n"
"adcq %%rdx, %%r8\n"
"adcq $0, %%r9\n"
- /* Extract l3 */
+ /* Extract l8[3] */
"movq %%r10, 24(%%rsi)\n"
"xorq %%r10, %%r10\n"
/* (r8,r9,r10) += a1 * b3 */
@@ -767,7 +785,7 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
"addq %%rax, %%r8\n"
"adcq %%rdx, %%r9\n"
"adcq $0, %%r10\n"
- /* Extract l4 */
+ /* Extract l8[4] */
"movq %%r8, 32(%%rsi)\n"
"xorq %%r8, %%r8\n"
/* (r9,r10,r8) += a2 * b3 */
@@ -782,51 +800,54 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
"addq %%rax, %%r9\n"
"adcq %%rdx, %%r10\n"
"adcq $0, %%r8\n"
- /* Extract l5 */
+ /* Extract l8[5] */
"movq %%r9, 40(%%rsi)\n"
/* (r10,r8) += a3 * b3 */
"movq %%r15, %%rax\n"
"mulq %%r14\n"
"addq %%rax, %%r10\n"
"adcq %%rdx, %%r8\n"
- /* Extract l6 */
+ /* Extract l8[6] */
"movq %%r10, 48(%%rsi)\n"
- /* Extract l7 */
+ /* Extract l8[7] */
"movq %%r8, 56(%%rsi)\n"
: "+d"(pb)
- : "S"(l), "D"(a->d)
+ : "S"(l8), "D"(a->d)
: "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory");
+
+ SECP256K1_CHECKMEM_MSAN_DEFINE(l8, sizeof(*l8) * 8);
+
#else
/* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0;
- /* l[0..7] = a[0..3] * b[0..3]. */
+ /* l8[0..7] = a[0..3] * b[0..3]. */
muladd_fast(a->d[0], b->d[0]);
- extract_fast(l[0]);
+ extract_fast(l8[0]);
muladd(a->d[0], b->d[1]);
muladd(a->d[1], b->d[0]);
- extract(l[1]);
+ extract(l8[1]);
muladd(a->d[0], b->d[2]);
muladd(a->d[1], b->d[1]);
muladd(a->d[2], b->d[0]);
- extract(l[2]);
+ extract(l8[2]);
muladd(a->d[0], b->d[3]);
muladd(a->d[1], b->d[2]);
muladd(a->d[2], b->d[1]);
muladd(a->d[3], b->d[0]);
- extract(l[3]);
+ extract(l8[3]);
muladd(a->d[1], b->d[3]);
muladd(a->d[2], b->d[2]);
muladd(a->d[3], b->d[1]);
- extract(l[4]);
+ extract(l8[4]);
muladd(a->d[2], b->d[3]);
muladd(a->d[3], b->d[2]);
- extract(l[5]);
+ extract(l8[5]);
muladd_fast(a->d[3], b->d[3]);
- extract_fast(l[6]);
+ extract_fast(l8[6]);
VERIFY_CHECK(c1 == 0);
- l[7] = c0;
+ l8[7] = c0;
#endif
}
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index bbba83e937..972d8041b0 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -229,7 +229,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
* <= {triangle inequality}
* a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2|
* < {Lemma 1 and Lemma 2}
- * a1*(2^-1 + epslion1) + a2*(2^-1 + epsilon2)
+ * a1*(2^-1 + epsilon1) + a2*(2^-1 + epsilon2)
* < {rounding up to an integer}
* (a1 + a2 + 1)/2
* < {rounding up to a power of 2}
@@ -247,7 +247,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
* <= {triangle inequality}
* (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2|
* < {Lemma 1 and Lemma 2}
- * (-b1)*(2^-1 + epslion1) + b2*(2^-1 + epsilon2)
+ * (-b1)*(2^-1 + epsilon1) + b2*(2^-1 + epsilon2)
* < {rounding up to an integer}
* (-b1 + b2)/2 + 1
* < {rounding up to a power of 2}
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 4c11e7f0b8..15a5eede67 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -237,36 +237,25 @@ static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx,
}
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
- if (sizeof(secp256k1_ge_storage) == 64) {
- /* When the secp256k1_ge_storage type is exactly 64 byte, use its
- * representation inside secp256k1_pubkey, as conversion is very fast.
- * Note that secp256k1_pubkey_save must use the same representation. */
- secp256k1_ge_storage s;
- memcpy(&s, &pubkey->data[0], sizeof(s));
- secp256k1_ge_from_storage(ge, &s);
- } else {
- /* Otherwise, fall back to 32-byte big endian for X and Y. */
- secp256k1_fe x, y;
- ARG_CHECK(secp256k1_fe_set_b32_limit(&x, pubkey->data));
- ARG_CHECK(secp256k1_fe_set_b32_limit(&y, pubkey->data + 32));
- secp256k1_ge_set_xy(ge, &x, &y);
- }
+ secp256k1_ge_storage s;
+
+ /* We require that the secp256k1_ge_storage type is exactly 64 bytes.
+ * This is formally not guaranteed by the C standard, but should hold on any
+ * sane compiler in the real world. */
+ STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
+ memcpy(&s, &pubkey->data[0], 64);
+ secp256k1_ge_from_storage(ge, &s);
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
return 1;
}
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
- if (sizeof(secp256k1_ge_storage) == 64) {
- secp256k1_ge_storage s;
- secp256k1_ge_to_storage(&s, ge);
- memcpy(&pubkey->data[0], &s, sizeof(s));
- } else {
- VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
- secp256k1_fe_normalize_var(&ge->x);
- secp256k1_fe_normalize_var(&ge->y);
- secp256k1_fe_get_b32(pubkey->data, &ge->x);
- secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);
- }
+ secp256k1_ge_storage s;
+
+ STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
+ VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
+ secp256k1_ge_to_storage(&s, ge);
+ memcpy(&pubkey->data[0], &s, 64);
}
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index bec1c45585..85b4881295 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -2927,20 +2927,18 @@ static void run_scalar_tests(void) {
secp256k1_scalar_set_b32(&r2, res[i][1], &overflow);
CHECK(!overflow);
secp256k1_scalar_mul(&z, &x, &y);
- CHECK(!secp256k1_scalar_check_overflow(&z));
CHECK(secp256k1_scalar_eq(&r1, &z));
if (!secp256k1_scalar_is_zero(&y)) {
secp256k1_scalar_inverse(&zz, &y);
- CHECK(!secp256k1_scalar_check_overflow(&zz));
secp256k1_scalar_inverse_var(&zzv, &y);
CHECK(secp256k1_scalar_eq(&zzv, &zz));
secp256k1_scalar_mul(&z, &z, &zz);
- CHECK(!secp256k1_scalar_check_overflow(&z));
CHECK(secp256k1_scalar_eq(&x, &z));
secp256k1_scalar_mul(&zz, &zz, &y);
- CHECK(!secp256k1_scalar_check_overflow(&zz));
CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz));
}
+ secp256k1_scalar_mul(&z, &x, &x);
+ CHECK(secp256k1_scalar_eq(&r2, &z));
}
}
}
@@ -2955,7 +2953,7 @@ static void random_fe_non_square(secp256k1_fe *ns) {
}
}
-static int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe an = *a;
secp256k1_fe bn = *b;
secp256k1_fe_normalize_weak(&an);
@@ -3092,7 +3090,7 @@ static void run_field_half(void) {
#endif
secp256k1_fe_normalize_weak(&u);
secp256k1_fe_add(&u, &u);
- CHECK(check_fe_equal(&t, &u));
+ CHECK(fe_equal(&t, &u));
/* Check worst-case input: ensure the LSB is 1 so that P will be added,
* which will also cause all carries to be 1, since all limbs that can
@@ -3111,7 +3109,7 @@ static void run_field_half(void) {
#endif
secp256k1_fe_normalize_weak(&u);
secp256k1_fe_add(&u, &u);
- CHECK(check_fe_equal(&t, &u));
+ CHECK(fe_equal(&t, &u));
}
}
@@ -3138,7 +3136,7 @@ static void run_field_misc(void) {
secp256k1_fe_add(&z, &q); /* z = x+v */
q = x; /* q = x */
secp256k1_fe_add_int(&q, v); /* q = x+v */
- CHECK(check_fe_equal(&q, &z));
+ CHECK(fe_equal(&q, &z));
/* Test the fe equality and comparison operations. */
CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);
CHECK(secp256k1_fe_equal(&x, &x));
@@ -3198,27 +3196,27 @@ static void run_field_misc(void) {
secp256k1_fe_add(&y, &x);
z = x;
secp256k1_fe_mul_int(&z, 3);
- CHECK(check_fe_equal(&y, &z));
+ CHECK(fe_equal(&y, &z));
secp256k1_fe_add(&y, &x);
secp256k1_fe_add(&z, &x);
- CHECK(check_fe_equal(&z, &y));
+ CHECK(fe_equal(&z, &y));
z = x;
secp256k1_fe_mul_int(&z, 5);
secp256k1_fe_mul(&q, &x, &fe5);
- CHECK(check_fe_equal(&z, &q));
+ CHECK(fe_equal(&z, &q));
secp256k1_fe_negate(&x, &x, 1);
secp256k1_fe_add(&z, &x);
secp256k1_fe_add(&q, &x);
- CHECK(check_fe_equal(&y, &z));
- CHECK(check_fe_equal(&q, &y));
+ CHECK(fe_equal(&y, &z));
+ CHECK(fe_equal(&q, &y));
/* Check secp256k1_fe_half. */
z = x;
secp256k1_fe_half(&z);
secp256k1_fe_add(&z, &z);
- CHECK(check_fe_equal(&x, &z));
+ CHECK(fe_equal(&x, &z));
secp256k1_fe_add(&z, &z);
secp256k1_fe_half(&z);
- CHECK(check_fe_equal(&x, &z));
+ CHECK(fe_equal(&x, &z));
}
}
@@ -3287,18 +3285,31 @@ static void run_fe_mul(void) {
}
static void run_sqr(void) {
- secp256k1_fe x, s;
+ int i;
+ secp256k1_fe x, y, lhs, rhs, tmp;
- {
- int i;
- secp256k1_fe_set_int(&x, 1);
- secp256k1_fe_negate(&x, &x, 1);
+ secp256k1_fe_set_int(&x, 1);
+ secp256k1_fe_negate(&x, &x, 1);
- for (i = 1; i <= 512; ++i) {
- secp256k1_fe_mul_int(&x, 2);
- secp256k1_fe_normalize(&x);
- secp256k1_fe_sqr(&s, &x);
- }
+ for (i = 1; i <= 512; ++i) {
+ secp256k1_fe_mul_int(&x, 2);
+ secp256k1_fe_normalize(&x);
+
+ /* Check that (x+y)*(x-y) = x^2 - y*2 for some random values y */
+ random_fe_test(&y);
+
+ lhs = x;
+ secp256k1_fe_add(&lhs, &y); /* lhs = x+y */
+ secp256k1_fe_negate(&tmp, &y, 1); /* tmp = -y */
+ secp256k1_fe_add(&tmp, &x); /* tmp = x-y */
+ secp256k1_fe_mul(&lhs, &lhs, &tmp); /* lhs = (x+y)*(x-y) */
+
+ secp256k1_fe_sqr(&rhs, &x); /* rhs = x^2 */
+ secp256k1_fe_sqr(&tmp, &y); /* tmp = y^2 */
+ secp256k1_fe_negate(&tmp, &tmp, 1); /* tmp = -y^2 */
+ secp256k1_fe_add(&rhs, &tmp); /* rhs = x^2 - y^2 */
+
+ CHECK(fe_equal(&lhs, &rhs));
}
}
@@ -3620,9 +3631,9 @@ static void run_inverse_tests(void)
for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) {
for (var = 0; var <= 1; ++var) {
test_inverse_field(&x_fe, &fe_cases[i][0], var);
- check_fe_equal(&x_fe, &fe_cases[i][1]);
+ CHECK(fe_equal(&x_fe, &fe_cases[i][1]));
test_inverse_field(&x_fe, &fe_cases[i][1], var);
- check_fe_equal(&x_fe, &fe_cases[i][0]);
+ CHECK(fe_equal(&x_fe, &fe_cases[i][0]));
}
}
for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) {
@@ -4558,7 +4569,7 @@ static void ecmult_const_mult_xonly(void) {
/* Check that resj's X coordinate corresponds with resx. */
secp256k1_fe_sqr(&v, &resj.z);
secp256k1_fe_mul(&v, &v, &resx);
- CHECK(check_fe_equal(&v, &resj.x));
+ CHECK(fe_equal(&v, &resj.x));
}
/* Test that secp256k1_ecmult_const_xonly correctly rejects X coordinates not on curve. */
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 187bf1c5e0..154d9ebcf1 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -51,13 +51,27 @@ static void print_buf_plain(const unsigned char *buf, size_t len) {
# define SECP256K1_INLINE inline
# endif
+/** Assert statically that expr is true.
+ *
+ * This is a statement-like macro and can only be used inside functions.
+ */
+#define STATIC_ASSERT(expr) do { \
+ switch(0) { \
+ case 0: \
+ /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \
+ case /* ERROR: static assertion failed */ (expr): \
+ ; \
+ } \
+} while(0)
+
/** Assert statically that expr is an integer constant expression, and run stmt.
*
* Useful for example to enforce that magnitude arguments are constant.
*/
#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \
switch(42) { \
- case /* ERROR: integer argument is not constant */ expr: \
+ /* C allows only integer constant expressions as case labels. */ \
+ case /* ERROR: integer argument is not constant */ (expr): \
break; \
default: ; \
} \
diff --git a/src/secp256k1/tools/check-abi.sh b/src/secp256k1/tools/check-abi.sh
index 8f6119cd8e..55c945ac16 100755
--- a/src/secp256k1/tools/check-abi.sh
+++ b/src/secp256k1/tools/check-abi.sh
@@ -3,17 +3,19 @@
set -eu
default_base_version="$(git describe --match "v*.*.*" --abbrev=0)"
-default_new_version="master"
+default_new_version="HEAD"
display_help_and_exit() {
- echo "Usage: $0 <base_ver> <new_ver>"
+ echo "Usage: $0 [<base_ver> [<new_ver>]]"
echo ""
echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI"
echo " of a new version of libsecp256k1 has changed in a backward-incompatible way."
echo ""
echo "Options:"
- echo " base_ver Specify the base version (default: $default_base_version)"
- echo " new_ver Specify the new version (default: $default_new_version)"
+ echo " base_ver Specify the base version as a git commit-ish"
+ echo " (default: most recent reachable tag matching \"v.*.*\", currently \"$default_base_version\")"
+ echo " new_ver Specify the new version as a git commit-ish"
+ echo " (default: $default_new_version)"
echo " -h, --help Display this help message"
exit 0
}
@@ -23,9 +25,11 @@ if [ "$#" -eq 0 ]; then
new_version="$default_new_version"
elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then
display_help_and_exit
-elif [ "$#" -eq 2 ]; then
+elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then
base_version="$1"
- new_version="$2"
+ if [ "$#" -eq 2 ]; then
+ new_version="$2"
+ fi
else
echo "Invalid usage. See help:"
echo ""
@@ -33,7 +37,8 @@ else
fi
checkout_and_build() {
- git worktree add -d "$1" "$2"
+ _orig_dir="$(pwd)"
+ git worktree add --detach "$1" "$2"
cd "$1"
mkdir build && cd build
cmake -S .. --preset dev-mode \
@@ -45,20 +50,18 @@ checkout_and_build() {
-DSECP256K1_BUILD_EXAMPLES=OFF
cmake --build . -j "$(nproc)"
abi-dumper src/libsecp256k1.so -o ABI.dump -lver "$2"
+ cd "$_orig_dir"
}
echo "Comparing $base_version (base version) to $new_version (new version)"
echo
-original_dir="$(pwd)"
-
-base_source_dir=$(mktemp -d)
+base_source_dir="$(mktemp -d)"
checkout_and_build "$base_source_dir" "$base_version"
-new_source_dir=$(mktemp -d)
+new_source_dir="$(mktemp -d)"
checkout_and_build "$new_source_dir" "$new_version"
-cd "$original_dir"
abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump"
git worktree remove "$base_source_dir"
git worktree remove "$new_source_dir"
diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp
index 1f46efe464..340208a1c9 100644
--- a/src/test/argsman_tests.cpp
+++ b/src/test/argsman_tests.cpp
@@ -904,7 +904,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
// If check below fails, should manually dump the results with:
//
- // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge
+ // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=argsman_tests/util_ArgsMerge
//
// And verify diff against previous results to make sure the changes are expected.
//
@@ -1007,7 +1007,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
// If check below fails, should manually dump the results with:
//
- // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge
+ // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=argsman_tests/util_ChainMerge
//
// And verify diff against previous results to make sure the changes are expected.
//
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 763f0f897e..05355fb21d 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -14,7 +14,7 @@
#include <boost/test/unit_test.hpp>
-std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
+std::vector<CTransactionRef> extra_txn;
BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup)
@@ -126,7 +126,7 @@ public:
explicit TestHeaderAndShortIDs(const CBlock& block) :
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block}) {}
- uint64_t GetShortID(const uint256& txhash) const {
+ uint64_t GetShortID(const Wtxid& txhash) const {
DataStream stream{};
stream << *this;
CBlockHeaderAndShortTxIDs base;
@@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
shortIDs.prefilledtxn.resize(1);
shortIDs.prefilledtxn[0] = {1, block.vtx[1]};
shortIDs.shorttxids.resize(2);
- shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetHash());
- shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetHash());
+ shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetWitnessHash());
+ shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetWitnessHash());
DataStream stream{};
stream << shortIDs;
@@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
shortIDs.prefilledtxn[0] = {0, block.vtx[0]};
shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1
shortIDs.shorttxids.resize(1);
- shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetHash());
+ shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetWitnessHash());
DataStream stream{};
stream << shortIDs;
diff --git a/src/test/fuzz/partially_downloaded_block.cpp b/src/test/fuzz/partially_downloaded_block.cpp
index 4a4b46da60..ab75afe066 100644
--- a/src/test/fuzz/partially_downloaded_block.cpp
+++ b/src/test/fuzz/partially_downloaded_block.cpp
@@ -60,7 +60,7 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
// The coinbase is always available
available.insert(0);
- std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
+ std::vector<CTransactionRef> extra_txn;
for (size_t i = 1; i < block->vtx.size(); ++i) {
auto tx{block->vtx[i]};
@@ -68,7 +68,7 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
bool add_to_mempool{fuzzed_data_provider.ConsumeBool()};
if (add_to_extra_txn) {
- extra_txn.emplace_back(tx->GetWitnessHash(), tx);
+ extra_txn.emplace_back(tx);
available.insert(i);
}
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index 42008c6ad9..754aff4e70 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -127,6 +127,10 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
}
mempool_txs.emplace_back(*child);
pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back()));
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ pool.PrioritiseTransaction(mempool_txs.back().GetHash().ToUint256(), fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(-100000, 100000));
+ }
}
// Pick some transactions at random to be the direct conflicts
@@ -174,5 +178,16 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
// If internals report error, wrapper should too
auto err_tuple{ImprovesFeerateDiagram(pool, direct_conflicts, all_conflicts, replacement_fees, replacement_vsize)};
- if (!calc_results.has_value()) assert(err_tuple.has_value());
+ if (!calc_results.has_value()) {
+ assert(err_tuple.value().first == DiagramCheckError::UNCALCULABLE);
+ } else {
+ // Diagram check succeeded
+ if (!err_tuple.has_value()) {
+ // New diagram's final fee should always match or exceed old diagram's
+ assert(calc_results->first.back().fee <= calc_results->second.back().fee);
+ } else if (calc_results->first.back().fee > calc_results->second.back().fee) {
+ // Or it failed, and if old diagram had higher fees, it should be a failure
+ assert(err_tuple.value().first == DiagramCheckError::FAILURE);
+ }
+ }
}
diff --git a/src/test/fuzz/script_bitcoin_consensus.cpp b/src/test/fuzz/script_bitcoin_consensus.cpp
deleted file mode 100644
index 846389863d..0000000000
--- a/src/test/fuzz/script_bitcoin_consensus.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2020 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <script/bitcoinconsensus.h>
-#include <script/interpreter.h>
-#include <test/fuzz/FuzzedDataProvider.h>
-#include <test/fuzz/fuzz.h>
-#include <test/fuzz/util.h>
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-FUZZ_TARGET(script_bitcoin_consensus)
-{
- FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- const std::vector<uint8_t> random_bytes_1 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- const std::vector<uint8_t> random_bytes_2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- const CAmount money = ConsumeMoney(fuzzed_data_provider);
- bitcoinconsensus_error err;
- bitcoinconsensus_error* err_p = fuzzed_data_provider.ConsumeBool() ? &err : nullptr;
- const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
- const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
- assert(bitcoinconsensus_version() == BITCOINCONSENSUS_API_VER);
- if ((flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
- return;
- }
- (void)bitcoinconsensus_verify_script(random_bytes_1.data(), random_bytes_1.size(), random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
- (void)bitcoinconsensus_verify_script_with_amount(random_bytes_1.data(), random_bytes_1.size(), money, random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
-
- std::vector<UTXO> spent_outputs;
- std::vector<std::vector<unsigned char>> spent_spks;
- if (n_in <= 24386) {
- spent_outputs.reserve(n_in);
- spent_spks.reserve(n_in);
- for (size_t i = 0; i < n_in; ++i) {
- spent_spks.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));
- const CAmount value{ConsumeMoney(fuzzed_data_provider)};
- const auto spk_size{static_cast<unsigned>(spent_spks.back().size())};
- spent_outputs.push_back({.scriptPubKey = spent_spks.back().data(), .scriptPubKeySize = spk_size, .value = value});
- }
- }
-
- const auto spent_outs_size{static_cast<unsigned>(spent_outputs.size())};
-
- (void)bitcoinconsensus_verify_script_with_spent_outputs(
- random_bytes_1.data(), random_bytes_1.size(), money, random_bytes_2.data(), random_bytes_2.size(),
- spent_outputs.data(), spent_outs_size, n_in, flags, err_p);
-}
diff --git a/src/test/fuzz/util/descriptor.cpp b/src/test/fuzz/util/descriptor.cpp
index df78bdf314..0fed2bc5e1 100644
--- a/src/test/fuzz/util/descriptor.cpp
+++ b/src/test/fuzz/util/descriptor.cpp
@@ -15,7 +15,7 @@ void MockedDescriptorConverter::Init() {
// an extended one.
if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i) || IdIsXOnlyPubKey(i) || IdIsConstPrivKey(i)) {
CKey privkey;
- privkey.Set(UCharCast(key_data.begin()), UCharCast(key_data.end()), !IdIsUnCompPubKey(i));
+ privkey.Set(key_data.begin(), key_data.end(), !IdIsUnCompPubKey(i));
if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i)) {
CPubKey pubkey{privkey.GetPubKey()};
keys_str[i] = HexStr(pubkey);
diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index 1f28e61bc9..a3699f84b6 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -297,6 +297,7 @@ using miniscript::operator"" _mst;
using Node = miniscript::Node<CPubKey>;
/** Compute all challenges (pubkeys, hashes, timelocks) that occur in a given Miniscript. */
+// NOLINTNEXTLINE(misc-no-recursion)
std::set<Challenge> FindChallenges(const NodeRef& ref) {
std::set<Challenge> chal;
for (const auto& key : ref->keys) {
diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp
index 961fd62fe4..ed33969710 100644
--- a/src/test/rbf_tests.cpp
+++ b/src/test/rbf_tests.cpp
@@ -37,6 +37,37 @@ static inline CTransactionRef make_tx(const std::vector<CTransactionRef>& inputs
return MakeTransactionRef(tx);
}
+// Make two child transactions from parent (which must have at least 2 outputs).
+// Each tx will have the same outputs, using the amounts specified in output_values.
+static inline std::pair<CTransactionRef, CTransactionRef> make_two_siblings(const CTransactionRef parent,
+ const std::vector<CAmount>& output_values)
+{
+ assert(parent->vout.size() >= 2);
+
+ // First tx takes first parent output
+ CMutableTransaction tx1 = CMutableTransaction();
+ tx1.vin.resize(1);
+ tx1.vout.resize(output_values.size());
+
+ tx1.vin[0].prevout.hash = parent->GetHash();
+ tx1.vin[0].prevout.n = 0;
+ // Add a witness so wtxid != txid
+ CScriptWitness witness;
+ witness.stack.emplace_back(10);
+ tx1.vin[0].scriptWitness = witness;
+
+ for (size_t i = 0; i < output_values.size(); ++i) {
+ tx1.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx1.vout[i].nValue = output_values[i];
+ }
+
+ // Second tx takes second parent output
+ CMutableTransaction tx2 = tx1;
+ tx2.vin[0].prevout.n = 1;
+
+ return std::make_pair(MakeTransactionRef(tx1), MakeTransactionRef(tx2));
+}
+
static CTransactionRef add_descendants(const CTransactionRef& tx, int32_t num_descendants, CTxMemPool& pool)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
{
@@ -67,6 +98,20 @@ static CTransactionRef add_descendant_to_parents(const std::vector<CTransactionR
return child_tx;
}
+// Makes two children for a single parent
+static std::pair<CTransactionRef, CTransactionRef> add_children_to_parent(const CTransactionRef parent, CTxMemPool& pool)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
+{
+ AssertLockHeld(::cs_main);
+ AssertLockHeld(pool.cs);
+ TestMemPoolEntryHelper entry;
+ // Assumes this isn't already spent in mempool
+ auto children_tx = make_two_siblings(/*parent=*/parent, /*output_values=*/{50 * CENT});
+ pool.addUnchecked(entry.FromTx(children_tx.first));
+ pool.addUnchecked(entry.FromTx(children_tx.second));
+ return children_tx;
+}
+
BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
{
CTxMemPool& pool = *Assert(m_node.mempool);
@@ -116,6 +161,10 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
const auto tx12 = make_tx(/*inputs=*/ {m_coinbase_txns[8]}, /*output_values=*/ {995 * CENT});
pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx12));
+ // Will make two children of this single parent
+ const auto tx13 = make_tx(/*inputs=*/ {m_coinbase_txns[9]}, /*output_values=*/ {995 * CENT, 995 * CENT});
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx13));
+
const auto entry1_normal = pool.GetIter(tx1->GetHash()).value();
const auto entry2_normal = pool.GetIter(tx2->GetHash()).value();
const auto entry3_low = pool.GetIter(tx3->GetHash()).value();
@@ -128,6 +177,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
const auto entry10_unchained = pool.GetIter(tx10->GetHash()).value();
const auto entry11_unchained = pool.GetIter(tx11->GetHash()).value();
const auto entry12_unchained = pool.GetIter(tx12->GetHash()).value();
+ const auto entry13_unchained = pool.GetIter(tx13->GetHash()).value();
BOOST_CHECK_EQUAL(entry1_normal->GetFee(), normal_fee);
BOOST_CHECK_EQUAL(entry2_normal->GetFee(), normal_fee);
@@ -261,7 +311,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
// Tests for CheckConflictTopology
// Tx4 has 23 descendants
- BOOST_CHECK(pool.CheckConflictTopology(set_34_cpfp).has_value());
+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology(set_34_cpfp).value(), strprintf("%s has 23 descendants, max 1 allowed", entry4_high->GetSharedTx()->GetHash().ToString()));
// No descendants yet
BOOST_CHECK(pool.CheckConflictTopology({entry9_unchained}) == std::nullopt);
@@ -292,6 +342,14 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry11_unchained}).value(), strprintf("%s is not the only parent of child %s", entry11_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry12_unchained}).value(), strprintf("%s is not the only parent of child %s", entry12_unchained->GetSharedTx()->GetHash().ToString(), entry_two_parent_child->GetSharedTx()->GetHash().ToString()));
BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_two_parent_child}).value(), strprintf("%s has 2 ancestors, max 1 allowed", entry_two_parent_child->GetSharedTx()->GetHash().ToString()));
+
+ // Single parent with two children, we will conflict with the siblings directly only
+ const auto two_siblings = add_children_to_parent(tx13, pool);
+ const auto entry_sibling_1 = pool.GetIter(two_siblings.first->GetHash()).value();
+ const auto entry_sibling_2 = pool.GetIter(two_siblings.second->GetHash()).value();
+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_sibling_1}).value(), strprintf("%s is not the only child of parent %s", entry_sibling_1->GetSharedTx()->GetHash().ToString(), entry13_unchained->GetSharedTx()->GetHash().ToString()));
+ BOOST_CHECK_EQUAL(pool.CheckConflictTopology({entry_sibling_2}).value(), strprintf("%s is not the only child of parent %s", entry_sibling_2->GetSharedTx()->GetHash().ToString(), entry13_unchained->GetSharedTx()->GetHash().ToString()));
+
}
BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)
@@ -327,6 +385,17 @@ BOOST_FIXTURE_TEST_CASE(improves_feerate, TestChain100Setup)
// With one more satoshi it does
BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size) == std::nullopt);
+ // With prioritisation of in-mempool conflicts, it affects the results of the comparison using the same args as just above
+ pool.PrioritiseTransaction(entry1->GetSharedTx()->GetHash(), /*nFeeDelta=*/1);
+ const auto res2 = ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee + 1, tx1_size + tx2_size);
+ BOOST_CHECK(res2.has_value());
+ BOOST_CHECK(res2.value().first == DiagramCheckError::FAILURE);
+ BOOST_CHECK(res2.value().second == "insufficient feerate: does not improve feerate diagram");
+ pool.PrioritiseTransaction(entry1->GetSharedTx()->GetHash(), /*nFeeDelta=*/-1);
+
+ // With one less vB it does
+ BOOST_CHECK(ImprovesFeerateDiagram(pool, {entry1}, {entry1, entry2}, tx1_fee + tx2_fee, tx1_size + tx2_size - 1) == std::nullopt);
+
// Adding a grandchild makes the cluster size 3, which is uncalculable
const auto tx3 = make_tx(/*inputs=*/ {tx2}, /*output_values=*/ {995 * CENT});
pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx3));
@@ -347,38 +416,33 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
const CAmount normal_fee{CENT/10};
const CAmount high_fee{CENT};
- // low -> high -> medium fee transactions that would result in two chunks together
+ // low -> high -> medium fee transactions that would result in two chunks together since they
+ // are all same size
const auto low_tx = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});
pool.addUnchecked(entry.Fee(low_fee).FromTx(low_tx));
const auto entry_low = pool.GetIter(low_tx->GetHash()).value();
const auto low_size = entry_low->GetTxSize();
- std::vector<FeeFrac> old_diagram, new_diagram;
-
// Replacement of size 1
- const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};
- BOOST_CHECK(replace_one.has_value());
- old_diagram = replace_one->first;
- new_diagram = replace_one->second;
- BOOST_CHECK(old_diagram.size() == 2);
- BOOST_CHECK(new_diagram.size() == 2);
- BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));
- BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(new_diagram[1] == FeeFrac(0, 1));
+ {
+ const auto replace_one{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/0, /*replacement_vsize=*/1, {entry_low}, {entry_low})};
+ BOOST_CHECK(replace_one.has_value());
+ std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee, low_size)};
+ BOOST_CHECK(replace_one->first == expected_old_diagram);
+ std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(0, 1)};
+ BOOST_CHECK(replace_one->second == expected_new_diagram);
+ }
// Non-zero replacement fee/size
- const auto replace_one_fee{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low})};
- BOOST_CHECK(replace_one_fee.has_value());
- old_diagram = replace_one_fee->first;
- new_diagram = replace_one_fee->second;
- BOOST_CHECK(old_diagram.size() == 2);
- BOOST_CHECK(new_diagram.size() == 2);
- BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee, low_size));
- BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));
+ {
+ const auto replace_one_fee{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low})};
+ BOOST_CHECK(replace_one_fee.has_value());
+ std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee, low_size)};
+ BOOST_CHECK(replace_one_fee->first == expected_old_diagram);
+ std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size)};
+ BOOST_CHECK(replace_one_fee->second == expected_new_diagram);
+ }
// Add a second transaction to the cluster that will make a single chunk, to be evicted in the RBF
const auto high_tx = make_tx(/*inputs=*/ {low_tx}, /*output_values=*/ {995 * CENT});
@@ -386,29 +450,24 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
const auto entry_high = pool.GetIter(high_tx->GetHash()).value();
const auto high_size = entry_high->GetTxSize();
- const auto replace_single_chunk{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high})};
- BOOST_CHECK(replace_single_chunk.has_value());
- old_diagram = replace_single_chunk->first;
- new_diagram = replace_single_chunk->second;
- BOOST_CHECK(old_diagram.size() == 2);
- BOOST_CHECK(new_diagram.size() == 2);
- BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));
- BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));
+ {
+ const auto replace_single_chunk{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_low}, {entry_low, entry_high})};
+ BOOST_CHECK(replace_single_chunk.has_value());
+ std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee + high_fee, low_size + high_size)};
+ BOOST_CHECK(replace_single_chunk->first == expected_old_diagram);
+ std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size)};
+ BOOST_CHECK(replace_single_chunk->second == expected_new_diagram);
+ }
// Conflict with the 2nd tx, resulting in new diagram with three entries
- const auto replace_cpfp_child{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high})};
- BOOST_CHECK(replace_cpfp_child.has_value());
- old_diagram = replace_cpfp_child->first;
- new_diagram = replace_cpfp_child->second;
- BOOST_CHECK(old_diagram.size() == 2);
- BOOST_CHECK(new_diagram.size() == 3);
- BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(old_diagram[1] == FeeFrac(low_fee + high_fee, low_size + high_size));
- BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size));
- BOOST_CHECK(new_diagram[2] == FeeFrac(low_fee + high_fee, low_size + low_size));
+ {
+ const auto replace_cpfp_child{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high}, {entry_high})};
+ BOOST_CHECK(replace_cpfp_child.has_value());
+ std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(low_fee + high_fee, low_size + high_size)};
+ BOOST_CHECK(replace_cpfp_child->first == expected_old_diagram);
+ std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size), FeeFrac(low_fee + high_fee, low_size + low_size)};
+ BOOST_CHECK(replace_cpfp_child->second == expected_new_diagram);
+ }
// third transaction causes the topology check to fail
const auto normal_tx = make_tx(/*inputs=*/ {high_tx}, /*output_values=*/ {995 * CENT});
@@ -416,11 +475,11 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
const auto entry_normal = pool.GetIter(normal_tx->GetHash()).value();
const auto normal_size = entry_normal->GetTxSize();
- const auto replace_too_large{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal})};
- BOOST_CHECK(!replace_too_large.has_value());
- BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf("%s has 2 descendants, max 1 allowed", low_tx->GetHash().GetHex()));
- old_diagram.clear();
- new_diagram.clear();
+ {
+ const auto replace_too_large{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/normal_fee, /*replacement_vsize=*/normal_size, {entry_low}, {entry_low, entry_high, entry_normal})};
+ BOOST_CHECK(!replace_too_large.has_value());
+ BOOST_CHECK_EQUAL(util::ErrorString(replace_too_large).original, strprintf("%s has 2 descendants, max 1 allowed", low_tx->GetHash().GetHex()));
+ }
// Make a size 2 cluster that is itself two chunks; evict both txns
const auto high_tx_2 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {10 * COIN});
@@ -433,19 +492,16 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
const auto entry_low_2 = pool.GetIter(low_tx_2->GetHash()).value();
const auto low_size_2 = entry_low_2->GetTxSize();
- const auto replace_two_chunks_single_cluster{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2})};
- BOOST_CHECK(replace_two_chunks_single_cluster.has_value());
- old_diagram = replace_two_chunks_single_cluster->first;
- new_diagram = replace_two_chunks_single_cluster->second;
- BOOST_CHECK(old_diagram.size() == 3);
- BOOST_CHECK(new_diagram.size() == 2);
- BOOST_CHECK(old_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(old_diagram[1] == FeeFrac(high_fee, high_size_2));
- BOOST_CHECK(old_diagram[2] == FeeFrac(low_fee + high_fee, low_size_2 + high_size_2));
- BOOST_CHECK(new_diagram[0] == FeeFrac(0, 0));
- BOOST_CHECK(new_diagram[1] == FeeFrac(high_fee, low_size_2));
-
- // You can have more than two direct conflicts if the there are multiple effected clusters, all of size 2 or less
+ {
+ const auto replace_two_chunks_single_cluster{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {entry_high_2}, {entry_high_2, entry_low_2})};
+ BOOST_CHECK(replace_two_chunks_single_cluster.has_value());
+ std::vector<FeeFrac> expected_old_diagram{FeeFrac(0, 0), FeeFrac(high_fee, high_size_2), FeeFrac(low_fee + high_fee, low_size_2 + high_size_2)};
+ BOOST_CHECK(replace_two_chunks_single_cluster->first == expected_old_diagram);
+ std::vector<FeeFrac> expected_new_diagram{FeeFrac(0, 0), FeeFrac(high_fee, low_size_2)};
+ BOOST_CHECK(replace_two_chunks_single_cluster->second == expected_new_diagram);
+ }
+
+ // You can have more than two direct conflicts if the there are multiple affected clusters, all of size 2 or less
const auto conflict_1 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {10 * COIN});
pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1));
const auto conflict_1_entry = pool.GetIter(conflict_1->GetHash()).value();
@@ -458,40 +514,37 @@ BOOST_FIXTURE_TEST_CASE(calc_feerate_diagram_rbf, TestChain100Setup)
pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_3));
const auto conflict_3_entry = pool.GetIter(conflict_3->GetHash()).value();
- const auto replace_multiple_clusters{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry})};
-
- BOOST_CHECK(replace_multiple_clusters.has_value());
- old_diagram = replace_multiple_clusters->first;
- new_diagram = replace_multiple_clusters->second;
- BOOST_CHECK(old_diagram.size() == 4);
- BOOST_CHECK(new_diagram.size() == 2);
+ {
+ const auto replace_multiple_clusters{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry})};
+ BOOST_CHECK(replace_multiple_clusters.has_value());
+ BOOST_CHECK(replace_multiple_clusters->first.size() == 4);
+ BOOST_CHECK(replace_multiple_clusters->second.size() == 2);
+ }
- // Add a child transaction to conflict_1 and make it cluster size 2, still one chunk due to same feerate
+ // Add a child transaction to conflict_1 and make it cluster size 2, two chunks due to same feerate
const auto conflict_1_child = make_tx(/*inputs=*/{conflict_1}, /*output_values=*/ {995 * CENT});
pool.addUnchecked(entry.Fee(low_fee).FromTx(conflict_1_child));
const auto conflict_1_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();
- const auto replace_multiple_clusters_2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry})};
+ {
+ const auto replace_multiple_clusters_2{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry})};
- BOOST_CHECK(replace_multiple_clusters_2.has_value());
- old_diagram = replace_multiple_clusters_2->first;
- new_diagram = replace_multiple_clusters_2->second;
- BOOST_CHECK(old_diagram.size() == 4);
- BOOST_CHECK(new_diagram.size() == 2);
- old_diagram.clear();
- new_diagram.clear();
+ BOOST_CHECK(replace_multiple_clusters_2.has_value());
+ BOOST_CHECK(replace_multiple_clusters_2->first.size() == 5);
+ BOOST_CHECK(replace_multiple_clusters_2->second.size() == 2);
+ }
// Add another descendant to conflict_1, making the cluster size > 2 should fail at this point.
const auto conflict_1_grand_child = make_tx(/*inputs=*/{conflict_1_child}, /*output_values=*/ {995 * CENT});
pool.addUnchecked(entry.Fee(high_fee).FromTx(conflict_1_grand_child));
const auto conflict_1_grand_child_entry = pool.GetIter(conflict_1_child->GetHash()).value();
- const auto replace_cluster_size_3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry, conflict_1_grand_child_entry})};
+ {
+ const auto replace_cluster_size_3{pool.CalculateFeerateDiagramsForRBF(/*replacement_fees=*/high_fee, /*replacement_vsize=*/low_size, {conflict_1_entry, conflict_2_entry, conflict_3_entry}, {conflict_1_entry, conflict_2_entry, conflict_3_entry, conflict_1_child_entry, conflict_1_grand_child_entry})};
- BOOST_CHECK(!replace_cluster_size_3.has_value());
- BOOST_CHECK_EQUAL(util::ErrorString(replace_cluster_size_3).original, strprintf("%s has 2 descendants, max 1 allowed", conflict_1->GetHash().GetHex()));
- BOOST_CHECK(old_diagram.empty());
- BOOST_CHECK(new_diagram.empty());
+ BOOST_CHECK(!replace_cluster_size_3.has_value());
+ BOOST_CHECK_EQUAL(util::ErrorString(replace_cluster_size_3).original, strprintf("%s has 2 descendants, max 1 allowed", conflict_1->GetHash().GetHex()));
+ }
}
BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)
@@ -503,18 +556,21 @@ BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)
std::vector<FeeFrac> new_diagram{{FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1050, 400}}};
BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));
+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(new_diagram, old_diagram)));
// Incomparable diagrams
old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};
new_diagram = {FeeFrac{0, 0}, FeeFrac{1000, 300}, FeeFrac{1000, 400}};
BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);
+ BOOST_CHECK(CompareFeerateDiagram(new_diagram, old_diagram) == std::partial_ordering::unordered);
// Strictly better but smaller size.
old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};
new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 300}};
BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));
+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(new_diagram, old_diagram)));
// New diagram is strictly better due to the first chunk, even though
// second chunk contributes no fees
@@ -522,24 +578,28 @@ BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)
new_diagram = {FeeFrac{0, 0}, FeeFrac{1100, 100}, FeeFrac{1100, 200}};
BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));
+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(new_diagram, old_diagram)));
// Feerate of first new chunk is better with, but second chunk is worse
old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};
new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{999, 350}, FeeFrac{1150, 1000}};
BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);
+ BOOST_CHECK(CompareFeerateDiagram(new_diagram, old_diagram) == std::partial_ordering::unordered);
// If we make the second chunk slightly better, the new diagram now wins.
old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};
new_diagram = {FeeFrac{0, 0}, FeeFrac{750, 100}, FeeFrac{1000, 350}, FeeFrac{1150, 500}};
BOOST_CHECK(std::is_lt(CompareFeerateDiagram(old_diagram, new_diagram)));
+ BOOST_CHECK(std::is_gt(CompareFeerateDiagram(new_diagram, old_diagram)));
// Identical diagrams, cannot be strictly better
old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};
new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}};
BOOST_CHECK(std::is_eq(CompareFeerateDiagram(old_diagram, new_diagram)));
+ BOOST_CHECK(std::is_eq(CompareFeerateDiagram(new_diagram, old_diagram)));
// Same aggregate fee, but different total size (trigger single tail fee check step)
old_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 399}};
@@ -547,8 +607,6 @@ BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)
// No change in evaluation when tail check needed.
BOOST_CHECK(std::is_gt(CompareFeerateDiagram(old_diagram, new_diagram)));
-
- // Padding works on either argument
BOOST_CHECK(std::is_lt(CompareFeerateDiagram(new_diagram, old_diagram)));
// Trigger multiple tail fee check steps
@@ -561,6 +619,7 @@ BOOST_AUTO_TEST_CASE(feerate_diagram_utilities)
// Multiple tail fee check steps, unordered result
new_diagram = {FeeFrac{0, 0}, FeeFrac{950, 300}, FeeFrac{1050, 400}, FeeFrac{1050, 401}, FeeFrac{1050, 402}, FeeFrac{1051, 403}};
BOOST_CHECK(CompareFeerateDiagram(old_diagram, new_diagram) == std::partial_ordering::unordered);
+ BOOST_CHECK(CompareFeerateDiagram(new_diagram, old_diagram) == std::partial_ordering::unordered);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 451bc99d44..68f82b760c 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -4,7 +4,6 @@
#include <key.h>
#include <test/util/setup_common.h>
-#include <util/time.h>
#include <boost/test/unit_test.hpp>
@@ -13,7 +12,6 @@ BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(basic_sanity)
{
BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "secp256k1 sanity test");
- BOOST_CHECK_MESSAGE(ChronoSanityCheck() == true, "chrono epoch test");
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index ac457d9c77..0af2fdce08 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -2,10 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <test/data/script_tests.json.h>
#include <test/data/bip341_wallet_vectors.json.h>
@@ -27,10 +23,6 @@
#include <util/fs.h>
#include <util/strencodings.h>
-#if defined(HAVE_CONSENSUS_LIB)
-#include <script/bitcoinconsensus.h>
-#endif
-
#include <cstdint>
#include <fstream>
#include <string>
@@ -143,21 +135,6 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
if (combined_flags & SCRIPT_VERIFY_WITNESS && ~combined_flags & SCRIPT_VERIFY_P2SH) continue;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags));
}
-
-#if defined(HAVE_CONSENSUS_LIB)
- DataStream stream;
- stream << TX_WITH_WITNESS(tx2);
- uint32_t libconsensus_flags{flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL};
- if (libconsensus_flags == flags) {
- int expectedSuccessCode = expect ? 1 : 0;
- if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, UCharCast(stream.data()), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
- } else {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, UCharCast(stream.data()), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
- }
- }
-#endif
}
void static NegateSignatureS(std::vector<unsigned char>& vchSig) {
@@ -1498,179 +1475,6 @@ static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
return scriptwitness;
}
-#if defined(HAVE_CONSENSUS_LIB)
-
-/* Test simple (successful) usage of bitcoinconsensus_verify_script */
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_returns_true)
-{
- unsigned int libconsensus_flags = 0;
- int nIn = 0;
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_1;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << TX_WITH_WITNESS(spendTx);
-
- bitcoinconsensus_error err;
- int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 1);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_OK);
-}
-
-/* Test bitcoinconsensus_verify_script returns invalid tx index err*/
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_index_err)
-{
- unsigned int libconsensus_flags = 0;
- int nIn = 3;
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_EQUAL;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << TX_WITH_WITNESS(spendTx);
-
- bitcoinconsensus_error err;
- int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_INDEX);
-}
-
-/* Test bitcoinconsensus_verify_script returns tx size mismatch err*/
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_size)
-{
- unsigned int libconsensus_flags = 0;
- int nIn = 0;
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_EQUAL;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << TX_WITH_WITNESS(spendTx);
-
- bitcoinconsensus_error err;
- int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size() * 2, nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
-}
-
-/* Test bitcoinconsensus_verify_script returns invalid tx serialization error */
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_serialization)
-{
- unsigned int libconsensus_flags = 0;
- int nIn = 0;
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_EQUAL;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << 0xffffffff;
-
- bitcoinconsensus_error err;
- int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_DESERIALIZE);
-}
-
-/* Test bitcoinconsensus_verify_script returns amount required error */
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_amount_required_err)
-{
- unsigned int libconsensus_flags = bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS;
- int nIn = 0;
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_EQUAL;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << TX_WITH_WITNESS(spendTx);
-
- bitcoinconsensus_error err;
- int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
-}
-
-/* Test bitcoinconsensus_verify_script returns invalid flags err */
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_invalid_flags)
-{
- unsigned int libconsensus_flags = 1 << 3;
- int nIn = 0;
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_EQUAL;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << TX_WITH_WITNESS(spendTx);
-
- bitcoinconsensus_error err;
- int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_INVALID_FLAGS);
-}
-
-/* Test bitcoinconsensus_verify_script returns spent outputs required err */
-BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_spent_outputs_required_err)
-{
- unsigned int libconsensus_flags{bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT};
- const int nIn{0};
-
- CScript scriptPubKey;
- CScript scriptSig;
- CScriptWitness wit;
-
- scriptPubKey << OP_EQUAL;
- CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
- CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
-
- DataStream stream;
- stream << TX_WITH_WITNESS(spendTx);
-
- bitcoinconsensus_error err;
- int result{bitcoinconsensus_verify_script_with_spent_outputs(scriptPubKey.data(), scriptPubKey.size(), creditTx.vout[0].nValue, UCharCast(stream.data()), stream.size(), nullptr, 0, nIn, libconsensus_flags, &err)};
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED);
-
- result = bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), creditTx.vout[0].nValue, UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED);
-
- result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err);
- BOOST_CHECK_EQUAL(result, 0);
- BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED);
-}
-
-#endif // defined(HAVE_CONSENSUS_LIB)
-
static std::vector<unsigned int> AllConsensusFlags()
{
std::vector<unsigned int> ret;
@@ -1718,28 +1522,12 @@ static void AssetTest(const UniValue& test)
txdata.Init(tx, std::vector<CTxOut>(prevouts));
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata);
-#if defined(HAVE_CONSENSUS_LIB)
- DataStream stream;
- stream << TX_WITH_WITNESS(tx);
- std::vector<UTXO> utxos;
- utxos.resize(prevouts.size());
- for (size_t i = 0; i < prevouts.size(); i++) {
- utxos[i].scriptPubKey = prevouts[i].scriptPubKey.data();
- utxos[i].scriptPubKeySize = prevouts[i].scriptPubKey.size();
- utxos[i].value = prevouts[i].nValue;
- }
-#endif
-
for (const auto flags : ALL_CONSENSUS_FLAGS) {
// "final": true tests are valid for all flags. Others are only valid with flags that are
// a subset of test_flags.
if (fin || ((flags & test_flags) == flags)) {
bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr);
BOOST_CHECK(ret);
-#if defined(HAVE_CONSENSUS_LIB)
- int lib_ret = bitcoinconsensus_verify_script_with_spent_outputs(prevouts[idx].scriptPubKey.data(), prevouts[idx].scriptPubKey.size(), prevouts[idx].nValue, UCharCast(stream.data()), stream.size(), utxos.data(), utxos.size(), idx, flags, nullptr);
- BOOST_CHECK(lib_ret == 1);
-#endif
}
}
}
@@ -1752,27 +1540,11 @@ static void AssetTest(const UniValue& test)
txdata.Init(tx, std::vector<CTxOut>(prevouts));
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata);
-#if defined(HAVE_CONSENSUS_LIB)
- DataStream stream;
- stream << TX_WITH_WITNESS(tx);
- std::vector<UTXO> utxos;
- utxos.resize(prevouts.size());
- for (size_t i = 0; i < prevouts.size(); i++) {
- utxos[i].scriptPubKey = prevouts[i].scriptPubKey.data();
- utxos[i].scriptPubKeySize = prevouts[i].scriptPubKey.size();
- utxos[i].value = prevouts[i].nValue;
- }
-#endif
-
for (const auto flags : ALL_CONSENSUS_FLAGS) {
// If a test is supposed to fail with test_flags, it should also fail with any superset thereof.
if ((flags & test_flags) == test_flags) {
bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr);
BOOST_CHECK(!ret);
-#if defined(HAVE_CONSENSUS_LIB)
- int lib_ret = bitcoinconsensus_verify_script_with_spent_outputs(prevouts[idx].scriptPubKey.data(), prevouts[idx].scriptPubKey.size(), prevouts[idx].nValue, UCharCast(stream.data()), stream.size(), utxos.data(), utxos.size(), idx, flags, nullptr);
- BOOST_CHECK(lib_ret == 0);
-#endif
}
}
}
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 47808a2a58..9a2add748e 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -290,13 +290,18 @@ BOOST_AUTO_TEST_CASE(util_TrimString)
BOOST_AUTO_TEST_CASE(util_FormatISO8601DateTime)
{
+ BOOST_CHECK_EQUAL(FormatISO8601DateTime(971890963199), "32767-12-31T23:59:59Z");
+ BOOST_CHECK_EQUAL(FormatISO8601DateTime(971890876800), "32767-12-31T00:00:00Z");
BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777), "2011-09-30T23:36:17Z");
BOOST_CHECK_EQUAL(FormatISO8601DateTime(0), "1970-01-01T00:00:00Z");
}
BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
{
+ BOOST_CHECK_EQUAL(FormatISO8601Date(971890963199), "32767-12-31");
+ BOOST_CHECK_EQUAL(FormatISO8601Date(971890876800), "32767-12-31");
BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30");
+ BOOST_CHECK_EQUAL(FormatISO8601Date(0), "1970-01-01");
}
BOOST_AUTO_TEST_CASE(util_FormatMoney)
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 316ab86c2b..69f4e305ab 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -127,6 +127,7 @@ std::shared_ptr<const CBlock> MinerTestingSetup::BadBlock(const uint256& prev_ha
return ret;
}
+// NOLINTNEXTLINE(misc-no-recursion)
void MinerTestingSetup::BuildChain(const uint256& root, int height, const unsigned int invalid_rate, const unsigned int branch_rate, const unsigned int max_size, std::vector<std::shared_ptr<const CBlock>>& blocks)
{
if (height <= 0 || blocks.size() >= max_size) return;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 4047ceda3c..82eec6241f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -1294,9 +1294,10 @@ util::Result<std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>>> CTxMemPool::
// direct_conflicts that is at its own fee/size, along with the replacement
// tx/package at its own fee/size
- // old diagram will consist of each element of all_conflicts either at
- // its own feerate (followed by any descendant at its own feerate) or as a
- // single chunk at its descendant's ancestor feerate.
+ // old diagram will consist of the ancestors and descendants of each element of
+ // all_conflicts. every such transaction will either be at its own feerate (followed
+ // by any descendant at its own feerate), or as a single chunk at the descendant's
+ // ancestor feerate.
std::vector<FeeFrac> old_chunks;
// Step 1: build the old diagram.
@@ -1317,7 +1318,7 @@ util::Result<std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>>> CTxMemPool::
// We'll add chunks for either the ancestor by itself and this tx
// by itself, or for a combined package.
FeeFrac package{txiter->GetModFeesWithAncestors(), static_cast<int32_t>(txiter->GetSizeWithAncestors())};
- if (individual > package) {
+ if (individual >> package) {
// The individual feerate is higher than the package, and
// therefore higher than the parent's fee. Chunk these
// together.
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index acbce25741..da12157555 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -18,6 +18,7 @@
#include <utility>
#include <vector>
+// NOLINTNEXTLINE(misc-no-recursion)
class UniValue {
public:
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp
index 4a3cbba20f..4a2219061a 100644
--- a/src/univalue/lib/univalue_write.cpp
+++ b/src/univalue/lib/univalue_write.cpp
@@ -27,6 +27,7 @@ static std::string json_escape(const std::string& inS)
return outS;
}
+// NOLINTNEXTLINE(misc-no-recursion)
std::string UniValue::write(unsigned int prettyIndent,
unsigned int indentLevel) const
{
@@ -66,6 +67,7 @@ static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::
s.append(prettyIndent * indentLevel, ' ');
}
+// NOLINTNEXTLINE(misc-no-recursion)
void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const
{
s += "[";
@@ -88,6 +90,7 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
s += "]";
}
+// NOLINTNEXTLINE(misc-no-recursion)
void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const
{
s += "{";
diff --git a/src/util/feefrac.cpp b/src/util/feefrac.cpp
index a271fe585e..68fb836936 100644
--- a/src/util/feefrac.cpp
+++ b/src/util/feefrac.cpp
@@ -53,7 +53,6 @@ std::partial_ordering CompareFeerateDiagram(Span<const FeeFrac> dia0, Span<const
const FeeFrac& point_p = next_point(unproc_side);
const FeeFrac& point_a = prev_point(!unproc_side);
- // Slope of AP can be negative, unlike AB
const auto slope_ap = point_p - point_a;
Assume(slope_ap.size > 0);
std::weak_ordering cmp = std::weak_ordering::equivalent;
@@ -77,10 +76,12 @@ std::partial_ordering CompareFeerateDiagram(Span<const FeeFrac> dia0, Span<const
if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;
if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;
++next_index[unproc_side];
+
+ // If both diagrams are better somewhere, they are incomparable.
+ if (better_somewhere[0] && better_somewhere[1]) return std::partial_ordering::unordered;
+
} while(true);
- // If both diagrams are better somewhere, they are incomparable.
- if (better_somewhere[0] && better_somewhere[1]) return std::partial_ordering::unordered;
// Otherwise compare the better_somewhere values.
return better_somewhere[0] <=> better_somewhere[1];
}
diff --git a/src/util/feefrac.h b/src/util/feefrac.h
index 48bd287c7c..7102f85f88 100644
--- a/src/util/feefrac.h
+++ b/src/util/feefrac.h
@@ -31,7 +31,7 @@
* A FeeFrac is considered "better" if it sorts after another, by this ordering. All standard
* comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering.
*
- * The CompareFeeFrac, and >> and << operators only compare feerate and treat equal feerate but
+ * The FeeRateCompare, and >> and << operators only compare feerate and treat equal feerate but
* different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any
* other.
*/
diff --git a/src/util/string.h b/src/util/string.h
index 8b69d6ccae..dab92942fb 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -65,6 +65,7 @@ void ReplaceAll(std::string& in_out, const std::string& search, const std::strin
* @param unary_op Apply this operator to each item
*/
template <typename C, typename S, typename UnaryOp>
+// NOLINTNEXTLINE(misc-no-recursion)
auto Join(const C& container, const S& separator, UnaryOp unary_op)
{
decltype(unary_op(*container.begin())) ret;
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 5ca9d21f8d..456662bd84 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -3,70 +3,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
+#include <util/time.h>
#include <compat/compat.h>
#include <tinyformat.h>
-#include <util/time.h>
#include <util/check.h>
#include <atomic>
#include <chrono>
-#include <ctime>
-#include <locale>
-#include <thread>
-#include <sstream>
#include <string>
+#include <thread>
void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread::sleep_for(n); }
static std::atomic<int64_t> nMockTime(0); //!< For testing
-bool ChronoSanityCheck()
-{
- // std::chrono::system_clock.time_since_epoch and time_t(0) are not guaranteed
- // to use the Unix epoch timestamp, prior to C++20, but in practice they almost
- // certainly will. Any differing behavior will be assumed to be an error, unless
- // certain platforms prove to consistently deviate, at which point we'll cope
- // with it by adding offsets.
-
- // Create a new clock from time_t(0) and make sure that it represents 0
- // seconds from the system_clock's time_since_epoch. Then convert that back
- // to a time_t and verify that it's the same as before.
- const time_t time_t_epoch{};
- auto clock = std::chrono::system_clock::from_time_t(time_t_epoch);
- if (std::chrono::duration_cast<std::chrono::seconds>(clock.time_since_epoch()).count() != 0) {
- return false;
- }
-
- time_t time_val = std::chrono::system_clock::to_time_t(clock);
- if (time_val != time_t_epoch) {
- return false;
- }
-
- // Check that the above zero time is actually equal to the known unix timestamp.
- struct tm epoch;
-#ifdef HAVE_GMTIME_R
- if (gmtime_r(&time_val, &epoch) == nullptr) {
-#else
- if (gmtime_s(&epoch, &time_val) != 0) {
-#endif
- return false;
- }
-
- if ((epoch.tm_sec != 0) ||
- (epoch.tm_min != 0) ||
- (epoch.tm_hour != 0) ||
- (epoch.tm_mday != 1) ||
- (epoch.tm_mon != 0) ||
- (epoch.tm_year != 70)) {
- return false;
- }
- return true;
-}
-
NodeClock::time_point NodeClock::now() noexcept
{
const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)};
@@ -96,30 +47,21 @@ std::chrono::seconds GetMockTime()
int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); }
-std::string FormatISO8601DateTime(int64_t nTime) {
- struct tm ts;
- time_t time_val = nTime;
-#ifdef HAVE_GMTIME_R
- if (gmtime_r(&time_val, &ts) == nullptr) {
-#else
- if (gmtime_s(&ts, &time_val) != 0) {
-#endif
- return {};
- }
- return strprintf("%04i-%02i-%02iT%02i:%02i:%02iZ", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
+std::string FormatISO8601DateTime(int64_t nTime)
+{
+ const std::chrono::sys_seconds secs{std::chrono::seconds{nTime}};
+ const auto days{std::chrono::floor<std::chrono::days>(secs)};
+ const std::chrono::year_month_day ymd{days};
+ const std::chrono::hh_mm_ss hms{secs - days};
+ return strprintf("%04i-%02u-%02uT%02i:%02i:%02iZ", signed{ymd.year()}, unsigned{ymd.month()}, unsigned{ymd.day()}, hms.hours().count(), hms.minutes().count(), hms.seconds().count());
}
-std::string FormatISO8601Date(int64_t nTime) {
- struct tm ts;
- time_t time_val = nTime;
-#ifdef HAVE_GMTIME_R
- if (gmtime_r(&time_val, &ts) == nullptr) {
-#else
- if (gmtime_s(&ts, &time_val) != 0) {
-#endif
- return {};
- }
- return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
+std::string FormatISO8601Date(int64_t nTime)
+{
+ const std::chrono::sys_seconds secs{std::chrono::seconds{nTime}};
+ const auto days{std::chrono::floor<std::chrono::days>(secs)};
+ const std::chrono::year_month_day ymd{days};
+ return strprintf("%04i-%02u-%02u", signed{ymd.year()}, unsigned{ymd.month()}, unsigned{ymd.day()});
}
struct timeval MillisToTimeval(int64_t nTimeout)
diff --git a/src/util/time.h b/src/util/time.h
index 6aa776137c..108560e0e0 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -116,7 +116,4 @@ struct timeval MillisToTimeval(int64_t nTimeout);
*/
struct timeval MillisToTimeval(std::chrono::milliseconds ms);
-/** Sanity check epoch match normal Unix epoch */
-bool ChronoSanityCheck();
-
#endif // BITCOIN_UTIL_TIME_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 5c585438d1..8a78f2106d 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -5784,7 +5784,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
CBlockIndex* index = nullptr;
// Don't make any modifications to the genesis block since it shouldn't be
- // neccessary, and since the genesis block doesn't have normal flags like
+ // necessary, and since the genesis block doesn't have normal flags like
// BLOCK_VALID_SCRIPTS set.
constexpr int AFTER_GENESIS_START{1};
diff --git a/src/validation.h b/src/validation.h
index de81058033..e3b2a2d59b 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -275,7 +275,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
* Validate (and maybe submit) a package to the mempool. See doc/policy/packages.md for full details
* on package validation rules.
* @param[in] test_accept When true, run validation checks but don't submit to mempool.
-* @param[in] client_maxfeerate If exceeded by an individual transaction, rest of (sub)package evalution is aborted.
+* @param[in] client_maxfeerate If exceeded by an individual transaction, rest of (sub)package evaluation is aborted.
* Only for sanity checks against local submission of transactions.
* @returns a PackageMempoolAcceptResult which includes a MempoolAcceptResult for each transaction.
* If a transaction fails, validation will exit early and some results may be missing. It is also
@@ -478,7 +478,7 @@ enum class CoinsCacheSizeState
* current best chain.
*
* Eventually, the API here is targeted at being exposed externally as a
- * consumable libconsensus library, so any functions added must only call
+ * consumable library, so any functions added must only call
* other class member functions, pure functions in other parts of the consensus
* library, callbacks via the validation interface, or read/write-to-disk
* functions (eventually this will also be via callbacks).
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index d15273dfc9..d33e6f3873 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -92,7 +92,7 @@ WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
WalletTxStatus result;
result.block_height =
wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height :
- wtx.state<TxStateConflicted>() ? wtx.state<TxStateConflicted>()->conflicting_block_height :
+ wtx.state<TxStateBlockConflicted>() ? wtx.state<TxStateBlockConflicted>()->conflicting_block_height :
std::numeric_limits<int>::max();
result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx);
result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx);
@@ -101,7 +101,7 @@ WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
result.is_trusted = CachedTxIsTrusted(wallet, wtx);
result.is_abandoned = wtx.isAbandoned();
result.is_coinbase = wtx.IsCoinBase();
- result.is_in_main_chain = wallet.IsTxInMainChain(wtx);
+ result.is_in_main_chain = wtx.isConfirmed();
return result;
}
diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp
index b9d8d9abc9..c164266f80 100644
--- a/src/wallet/receive.cpp
+++ b/src/wallet/receive.cpp
@@ -149,7 +149,7 @@ CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, c
{
AssertLockHeld(wallet.cs_wallet);
- if (wallet.IsTxImmatureCoinBase(wtx) && wallet.IsTxInMainChain(wtx)) {
+ if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, filter);
}
@@ -253,12 +253,12 @@ bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminef
return (CachedTxGetDebit(wallet, wtx, filter) > 0);
}
+// NOLINTNEXTLINE(misc-no-recursion)
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents)
{
AssertLockHeld(wallet.cs_wallet);
- int nDepth = wallet.GetTxDepthInMainChain(wtx);
- if (nDepth >= 1) return true;
- if (nDepth < 0) return false;
+ if (wtx.isConfirmed()) return true;
+ if (wtx.isBlockConflicted()) return false;
// using wtx's cached debit
if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false;
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index acaa2d8b15..7f068c05ef 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -395,6 +395,7 @@ class DescribeWalletAddressVisitor
public:
const SigningProvider * const provider;
+ // NOLINTNEXTLINE(misc-no-recursion)
void ProcessSubScript(const CScript& subscript, UniValue& obj) const
{
// Always present: script type and redeemscript
@@ -445,6 +446,7 @@ public:
return obj;
}
+ // NOLINTNEXTLINE(misc-no-recursion)
UniValue operator()(const ScriptHash& scripthash) const
{
UniValue obj(UniValue::VOBJ);
@@ -465,6 +467,7 @@ public:
return obj;
}
+ // NOLINTNEXTLINE(misc-no-recursion)
UniValue operator()(const WitnessV0ScriptHash& id) const
{
UniValue obj(UniValue::VOBJ);
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 5167e986b1..ae2dfe5795 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -854,6 +854,7 @@ enum class ScriptContext
// Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used.
// Returns an error string, or the empty string for success.
+// NOLINTNEXTLINE(misc-no-recursion)
static std::string RecurseImportData(const CScript& script, ImportData& import_data, const ScriptContext script_ctx)
{
// Use Solver to obtain script type and parsed pubkeys or hashes:
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index e6c021d426..05b340995d 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -40,6 +40,10 @@ static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue
for (const uint256& conflict : wallet.GetTxConflicts(wtx))
conflicts.push_back(conflict.GetHex());
entry.pushKV("walletconflicts", conflicts);
+ UniValue mempool_conflicts(UniValue::VARR);
+ for (const Txid& mempool_conflict : wtx.mempool_conflicts)
+ mempool_conflicts.push_back(mempool_conflict.GetHex());
+ entry.pushKV("mempoolconflicts", mempool_conflicts);
entry.pushKV("time", wtx.GetTxTime());
entry.pushKV("timereceived", int64_t{wtx.nTimeReceived});
@@ -417,6 +421,10 @@ static std::vector<RPCResult> TransactionDescriptionString()
}},
{RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx was replaced."},
{RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "Only if 'category' is 'send'. The txid if this tx replaces another."},
+ {RPCResult::Type::ARR, "mempoolconflicts", "Transactions that directly conflict with either this transaction or an ancestor transaction",
+ {
+ {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
+ }},
{RPCResult::Type::STR, "to", /*optional=*/true, "If a comment to is associated with the transaction."},
{RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
{RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 6a8ce954fb..a684d4e191 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -817,6 +817,217 @@ static RPCHelpMan migratewallet()
};
}
+RPCHelpMan gethdkeys()
+{
+ return RPCHelpMan{
+ "gethdkeys",
+ "\nList all BIP 32 HD keys in the wallet and which descriptors use them.\n",
+ {
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", {
+ {"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},
+ {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}
+ }},
+ },
+ RPCResult{RPCResult::Type::ARR, "", "", {
+ {
+ {RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::STR, "xpub", "The extended public key"},
+ {RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},
+ {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
+ {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",
+ {
+ {RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::STR, "desc", "Descriptor string representation"},
+ {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
+ }},
+ }},
+ }},
+ }
+ }},
+ RPCExamples{
+ HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")
+ + HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+ {
+ const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
+ if (!wallet) return UniValue::VNULL;
+
+ if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "gethdkeys is not available for non-descriptor wallets");
+ }
+
+ LOCK(wallet->cs_wallet);
+
+ UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};
+ const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};
+ const bool priv{options.exists("private") ? options["private"].get_bool() : false};
+ if (priv) {
+ EnsureWalletIsUnlocked(*wallet);
+ }
+
+
+ std::set<ScriptPubKeyMan*> spkms;
+ if (active_only) {
+ spkms = wallet->GetActiveScriptPubKeyMans();
+ } else {
+ spkms = wallet->GetAllScriptPubKeyMans();
+ }
+
+ std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
+ std::map<CExtPubKey, CExtKey> wallet_xprvs;
+ for (auto* spkm : spkms) {
+ auto* desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
+ CHECK_NONFATAL(desc_spkm);
+ LOCK(desc_spkm->cs_desc_man);
+ WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();
+
+ // Retrieve the pubkeys from the descriptor
+ std::set<CPubKey> desc_pubkeys;
+ std::set<CExtPubKey> desc_xpubs;
+ w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
+ for (const CExtPubKey& xpub : desc_xpubs) {
+ std::string desc_str;
+ bool ok = desc_spkm->GetDescriptorString(desc_str, false);
+ CHECK_NONFATAL(ok);
+ wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
+ if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
+ wallet_xprvs[xpub] = CExtKey(xpub, *key);
+ }
+ }
+ }
+
+ UniValue response(UniValue::VARR);
+ for (const auto& [xpub, descs] : wallet_xpubs) {
+ bool has_xprv = false;
+ UniValue descriptors(UniValue::VARR);
+ for (const auto& [desc, active, has_priv] : descs) {
+ UniValue d(UniValue::VOBJ);
+ d.pushKV("desc", desc);
+ d.pushKV("active", active);
+ has_xprv |= has_priv;
+
+ descriptors.push_back(std::move(d));
+ }
+ UniValue xpub_info(UniValue::VOBJ);
+ xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));
+ xpub_info.pushKV("has_private", has_xprv);
+ if (priv) {
+ xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));
+ }
+ xpub_info.pushKV("descriptors", std::move(descriptors));
+
+ response.push_back(std::move(xpub_info));
+ }
+
+ return response;
+ },
+ };
+}
+
+static RPCHelpMan createwalletdescriptor()
+{
+ return RPCHelpMan{"createwalletdescriptor",
+ "Creates the wallet's descriptor for the given address type. "
+ "The address type must be one that the wallet does not already have a descriptor for."
+ + HELP_REQUIRING_PASSPHRASE,
+ {
+ {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", {
+ {"internal", RPCArg::Type::BOOL, RPCArg::DefaultHint{"Both external and internal will be generated unless this parameter is specified"}, "Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)"},
+ {"hdkey", RPCArg::Type::STR, RPCArg::DefaultHint{"The HD key used by all other active descriptors"}, "The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for this descriptor's key"},
+ }},
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::ARR, "descs", "The public descriptors that were added to the wallet",
+ {{RPCResult::Type::STR, "", ""}}
+ }
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("createwalletdescriptor", "bech32m")
+ + HelpExampleRpc("createwalletdescriptor", "bech32m")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+ {
+ std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return UniValue::VNULL;
+
+ // Make sure wallet is a descriptor wallet
+ if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "createwalletdescriptor is not available for non-descriptor wallets");
+ }
+
+ std::optional<OutputType> output_type = ParseOutputType(request.params[0].get_str());
+ if (!output_type) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
+ }
+
+ UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
+ UniValue internal_only{options["internal"]};
+ UniValue hdkey{options["hdkey"]};
+
+ std::vector<bool> internals;
+ if (internal_only.isNull()) {
+ internals.push_back(false);
+ internals.push_back(true);
+ } else {
+ internals.push_back(internal_only.get_bool());
+ }
+
+ LOCK(pwallet->cs_wallet);
+ EnsureWalletIsUnlocked(*pwallet);
+
+ CExtPubKey xpub;
+ if (hdkey.isNull()) {
+ std::set<CExtPubKey> active_xpubs = pwallet->GetActiveHDPubKeys();
+ if (active_xpubs.size() != 1) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
+ }
+ xpub = *active_xpubs.begin();
+ } else {
+ xpub = DecodeExtPubKey(hdkey.get_str());
+ if (!xpub.pubkey.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
+ }
+ }
+
+ std::optional<CKey> key = pwallet->GetKey(xpub.pubkey.GetID());
+ if (!key) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
+ }
+ CExtKey active_hdkey(xpub, *key);
+
+ std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
+ WalletBatch batch{pwallet->GetDatabase()};
+ for (bool internal : internals) {
+ WalletDescriptor w_desc = GenerateWalletDescriptor(xpub, *output_type, internal);
+ uint256 w_id = DescriptorID(*w_desc.descriptor);
+ if (!pwallet->GetScriptPubKeyMan(w_id)) {
+ spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type, internal));
+ }
+ }
+ if (spkms.empty()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Descriptor already exists");
+ }
+
+ // Fetch each descspkm from the wallet in order to get the descriptor strings
+ UniValue descs{UniValue::VARR};
+ for (const auto& spkm : spkms) {
+ std::string desc_str;
+ bool ok = spkm.get().GetDescriptorString(desc_str, false);
+ CHECK_NONFATAL(ok);
+ descs.push_back(desc_str);
+ }
+ UniValue out{UniValue::VOBJ};
+ out.pushKV("descs", std::move(descs));
+ return out;
+ }
+ };
+}
+
// addresses
RPCHelpMan getaddressinfo();
RPCHelpMan getnewaddress();
@@ -900,6 +1111,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &bumpfee},
{"wallet", &psbtbumpfee},
{"wallet", &createwallet},
+ {"wallet", &createwalletdescriptor},
{"wallet", &restorewallet},
{"wallet", &dumpprivkey},
{"wallet", &dumpwallet},
@@ -907,6 +1119,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &getaddressesbylabel},
{"wallet", &getaddressinfo},
{"wallet", &getbalance},
+ {"wallet", &gethdkeys},
{"wallet", &getnewaddress},
{"wallet", &getrawchangeaddress},
{"wallet", &getreceivedbyaddress},
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index e10a17f003..b42275fe4b 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -11,6 +11,7 @@
#include <script/sign.h>
#include <script/solver.h>
#include <util/bip32.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
@@ -96,6 +97,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyScriptPubKeyMan&
//! @param recurse_scripthash whether to recurse into nested p2sh and p2wsh
//! scripts or simply treat any script that has been
//! stored in the keystore as spendable
+// NOLINTNEXTLINE(misc-no-recursion)
IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true)
{
IsMineResult ret = IsMineResult::NO;
@@ -2143,6 +2145,36 @@ std::map<CKeyID, CKey> DescriptorScriptPubKeyMan::GetKeys() const
return m_map_keys;
}
+bool DescriptorScriptPubKeyMan::HasPrivKey(const CKeyID& keyid) const
+{
+ AssertLockHeld(cs_desc_man);
+ return m_map_keys.contains(keyid) || m_map_crypted_keys.contains(keyid);
+}
+
+std::optional<CKey> DescriptorScriptPubKeyMan::GetKey(const CKeyID& keyid) const
+{
+ AssertLockHeld(cs_desc_man);
+ if (m_storage.HasEncryptionKeys() && !m_storage.IsLocked()) {
+ const auto& it = m_map_crypted_keys.find(keyid);
+ if (it == m_map_crypted_keys.end()) {
+ return std::nullopt;
+ }
+ const std::vector<unsigned char>& crypted_secret = it->second.second;
+ CKey key;
+ if (!Assume(m_storage.WithEncryptionKey([&](const CKeyingMaterial& encryption_key) {
+ return DecryptKey(encryption_key, crypted_secret, it->second.first, key);
+ }))) {
+ return std::nullopt;
+ }
+ return key;
+ }
+ const auto& it = m_map_keys.find(keyid);
+ if (it == m_map_keys.end()) {
+ return std::nullopt;
+ }
+ return it->second;
+}
+
bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
{
WalletBatch batch(m_storage.GetDatabase());
@@ -2296,55 +2328,7 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(WalletBatch& batch, co
return false;
}
- int64_t creation_time = GetTime();
-
- std::string xpub = EncodeExtPubKey(master_key.Neuter());
-
- // Build descriptor string
- std::string desc_prefix;
- std::string desc_suffix = "/*)";
- switch (addr_type) {
- case OutputType::LEGACY: {
- desc_prefix = "pkh(" + xpub + "/44h";
- break;
- }
- case OutputType::P2SH_SEGWIT: {
- desc_prefix = "sh(wpkh(" + xpub + "/49h";
- desc_suffix += ")";
- break;
- }
- case OutputType::BECH32: {
- desc_prefix = "wpkh(" + xpub + "/84h";
- break;
- }
- case OutputType::BECH32M: {
- desc_prefix = "tr(" + xpub + "/86h";
- break;
- }
- case OutputType::UNKNOWN: {
- // We should never have a DescriptorScriptPubKeyMan for an UNKNOWN OutputType,
- // so if we get to this point something is wrong
- assert(false);
- }
- } // no default case, so the compiler can warn about missing cases
- assert(!desc_prefix.empty());
-
- // Mainnet derives at 0', testnet and regtest derive at 1'
- if (Params().IsTestChain()) {
- desc_prefix += "/1h";
- } else {
- desc_prefix += "/0h";
- }
-
- std::string internal_path = internal ? "/1" : "/0";
- std::string desc_str = desc_prefix + "/0h" + internal_path + desc_suffix;
-
- // Make the descriptor
- FlatSigningProvider keys;
- std::string error;
- std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
- WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
- m_wallet_descriptor = w_desc;
+ m_wallet_descriptor = GenerateWalletDescriptor(master_key.Neuter(), addr_type, internal);
// Store the master private key, and descriptor
if (!AddDescriptorKeyWithDB(batch, master_key.key, master_key.key.GetPubKey())) {
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 2d83ae556f..4575881d96 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -633,6 +633,9 @@ public:
bool SetupDescriptorGeneration(WalletBatch& batch, const CExtKey& master_key, OutputType addr_type, bool internal);
bool HavePrivateKeys() const override;
+ bool HasPrivKey(const CKeyID& keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
+ //! Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet, or if the wallet is locked.
+ std::optional<CKey> GetKey(const CKeyID& keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
std::optional<int64_t> GetOldestKeyPoolTime() const override;
unsigned int GetKeyPoolSize() const override;
@@ -669,7 +672,7 @@ public:
std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys(int32_t minimum_index) const;
int32_t GetEndRange() const;
- bool GetDescriptorString(std::string& out, const bool priv) const;
+ [[nodiscard]] bool GetDescriptorString(std::string& out, const bool priv) const;
void UpgradeDescriptorCache();
};
diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp
index 3dba2231f0..2e43eda582 100644
--- a/src/wallet/test/walletload_tests.cpp
+++ b/src/wallet/test/walletload_tests.cpp
@@ -34,6 +34,7 @@ public:
std::optional<int64_t> ScriptSize() const override { return {}; }
std::optional<int64_t> MaxSatisfactionWeight(bool) const override { return {}; }
std::optional<int64_t> MaxSatisfactionElems() const override { return {}; }
+ void GetPubKeys(std::set<CPubKey>& pubkeys, std::set<CExtPubKey>& ext_pubs) const override {}
};
BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
diff --git a/src/wallet/transaction.cpp b/src/wallet/transaction.cpp
index 6777257e53..561880482f 100644
--- a/src/wallet/transaction.cpp
+++ b/src/wallet/transaction.cpp
@@ -45,7 +45,7 @@ void CWalletTx::updateState(interfaces::Chain& chain)
};
if (auto* conf = state<TxStateConfirmed>()) {
lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, m_state);
- } else if (auto* conf = state<TxStateConflicted>()) {
+ } else if (auto* conf = state<TxStateBlockConflicted>()) {
lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, m_state);
}
}
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index ddeb931112..9c27574103 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -43,12 +43,12 @@ struct TxStateInMempool {
};
//! State of rejected transaction that conflicts with a confirmed block.
-struct TxStateConflicted {
+struct TxStateBlockConflicted {
uint256 conflicting_block_hash;
int conflicting_block_height;
- explicit TxStateConflicted(const uint256& block_hash, int height) : conflicting_block_hash(block_hash), conflicting_block_height(height) {}
- std::string toString() const { return strprintf("Conflicted (block=%s, height=%i)", conflicting_block_hash.ToString(), conflicting_block_height); }
+ explicit TxStateBlockConflicted(const uint256& block_hash, int height) : conflicting_block_hash(block_hash), conflicting_block_height(height) {}
+ std::string toString() const { return strprintf("BlockConflicted (block=%s, height=%i)", conflicting_block_hash.ToString(), conflicting_block_height); }
};
//! State of transaction not confirmed or conflicting with a known block and
@@ -75,7 +75,7 @@ struct TxStateUnrecognized {
};
//! All possible CWalletTx states
-using TxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateConflicted, TxStateInactive, TxStateUnrecognized>;
+using TxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized>;
//! Subset of states transaction sync logic is implemented to handle.
using SyncTxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateInactive>;
@@ -90,7 +90,7 @@ static inline TxState TxStateInterpretSerialized(TxStateUnrecognized data)
} else if (data.index >= 0) {
return TxStateConfirmed{data.block_hash, /*height=*/-1, data.index};
} else if (data.index == -1) {
- return TxStateConflicted{data.block_hash, /*height=*/-1};
+ return TxStateBlockConflicted{data.block_hash, /*height=*/-1};
}
return data;
}
@@ -102,7 +102,7 @@ static inline uint256 TxStateSerializedBlockHash(const TxState& state)
[](const TxStateInactive& inactive) { return inactive.abandoned ? uint256::ONE : uint256::ZERO; },
[](const TxStateInMempool& in_mempool) { return uint256::ZERO; },
[](const TxStateConfirmed& confirmed) { return confirmed.confirmed_block_hash; },
- [](const TxStateConflicted& conflicted) { return conflicted.conflicting_block_hash; },
+ [](const TxStateBlockConflicted& conflicted) { return conflicted.conflicting_block_hash; },
[](const TxStateUnrecognized& unrecognized) { return unrecognized.block_hash; }
}, state);
}
@@ -114,7 +114,7 @@ static inline int TxStateSerializedIndex(const TxState& state)
[](const TxStateInactive& inactive) { return inactive.abandoned ? -1 : 0; },
[](const TxStateInMempool& in_mempool) { return 0; },
[](const TxStateConfirmed& confirmed) { return confirmed.position_in_block; },
- [](const TxStateConflicted& conflicted) { return -1; },
+ [](const TxStateBlockConflicted& conflicted) { return -1; },
[](const TxStateUnrecognized& unrecognized) { return unrecognized.index; }
}, state);
}
@@ -258,6 +258,14 @@ public:
CTransactionRef tx;
TxState m_state;
+ // Set of mempool transactions that conflict
+ // directly with the transaction, or that conflict
+ // with an ancestor transaction. This set will be
+ // empty if state is InMempool or Confirmed, but
+ // can be nonempty if state is Inactive or
+ // BlockConflicted.
+ std::set<Txid> mempool_conflicts;
+
template<typename Stream>
void Serialize(Stream& s) const
{
@@ -335,9 +343,10 @@ public:
void updateState(interfaces::Chain& chain);
bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
- bool isConflicted() const { return state<TxStateConflicted>(); }
+ bool isMempoolConflicted() const { return !mempool_conflicts.empty(); }
+ bool isBlockConflicted() const { return state<TxStateBlockConflicted>(); }
bool isInactive() const { return state<TxStateInactive>(); }
- bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
+ bool isUnconfirmed() const { return !isAbandoned() && !isBlockConflicted() && !isMempoolConflicted() && !isConfirmed(); }
bool isConfirmed() const { return state<TxStateConfirmed>(); }
const Txid& GetHash() const LIFETIMEBOUND { return tx->GetHash(); }
const Wtxid& GetWitnessHash() const LIFETIMEBOUND { return tx->GetWitnessHash(); }
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 9c15c2a827..96c4397504 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -752,8 +752,8 @@ bool CWallet::IsSpent(const COutPoint& outpoint) const
const uint256& wtxid = it->second;
const auto mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) {
- int depth = GetTxDepthInMainChain(mit->second);
- if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
+ const auto& wtx = mit->second;
+ if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted())
return true; // Spent
}
}
@@ -1197,7 +1197,7 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
auto it = mapWallet.find(txin.prevout.hash);
if (it != mapWallet.end()) {
CWalletTx& prevtx = it->second;
- if (auto* prev = prevtx.state<TxStateConflicted>()) {
+ if (auto* prev = prevtx.state<TxStateBlockConflicted>()) {
MarkConflicted(prev->conflicting_block_hash, prev->conflicting_block_height, wtx.GetHash());
}
}
@@ -1309,7 +1309,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
assert(!wtx.isConfirmed());
assert(!wtx.InMempool());
// If already conflicted or abandoned, no need to set abandoned
- if (!wtx.isConflicted() && !wtx.isAbandoned()) {
+ if (!wtx.isBlockConflicted() && !wtx.isAbandoned()) {
wtx.m_state = TxStateInactive{/*abandoned=*/true};
return TxUpdate::NOTIFY_CHANGED;
}
@@ -1346,7 +1346,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
if (conflictconfirms < GetTxDepthInMainChain(wtx)) {
// Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block.
- wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
+ wtx.m_state = TxStateBlockConflicted{hashBlock, conflicting_height};
return TxUpdate::CHANGED;
}
return TxUpdate::UNCHANGED;
@@ -1360,7 +1360,10 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
// Do not flush the wallet here for performance reasons
WalletBatch batch(GetDatabase(), false);
+ RecursiveUpdateTxState(&batch, tx_hash, try_updating_state);
+}
+void CWallet::RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
std::set<uint256> todo;
std::set<uint256> done;
@@ -1377,7 +1380,7 @@ void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingSt
TxUpdate update_state = try_updating_state(wtx);
if (update_state != TxUpdate::UNCHANGED) {
wtx.MarkDirty();
- batch.WriteTx(wtx);
+ if (batch) batch->WriteTx(wtx);
// Iterate over all its outputs, and update those tx states as well (if applicable)
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(Txid::FromUint256(now), i));
@@ -1418,6 +1421,20 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
if (it != mapWallet.end()) {
RefreshMempoolStatus(it->second, chain());
}
+
+ const Txid& txid = tx->GetHash();
+
+ for (const CTxIn& tx_in : tx->vin) {
+ // For each wallet transaction spending this prevout..
+ for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) {
+ const uint256& spent_id = range.first->second;
+ // Skip the recently added tx
+ if (spent_id == txid) continue;
+ RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
+ return wtx.mempool_conflicts.insert(txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED;
+ });
+ }
+ }
}
void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
@@ -1455,6 +1472,21 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
// https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
SyncTransaction(tx, TxStateInactive{});
}
+
+ const Txid& txid = tx->GetHash();
+
+ for (const CTxIn& tx_in : tx->vin) {
+ // Iterate over all wallet transactions spending txin.prev
+ // and recursively mark them as no longer conflicting with
+ // txid
+ for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) {
+ const uint256& spent_id = range.first->second;
+
+ RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
+ return wtx.mempool_conflicts.erase(txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED;
+ });
+ }
+ }
}
void CWallet::blockConnected(ChainstateRole role, const interfaces::BlockInfo& block)
@@ -1506,11 +1538,11 @@ void CWallet::blockDisconnected(const interfaces::BlockInfo& block)
for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
CWalletTx& wtx = mapWallet.find(_it->second)->second;
- if (!wtx.isConflicted()) continue;
+ if (!wtx.isBlockConflicted()) continue;
auto try_updating_state = [&](CWalletTx& tx) {
- if (!tx.isConflicted()) return TxUpdate::UNCHANGED;
- if (tx.state<TxStateConflicted>()->conflicting_block_height >= disconnect_height) {
+ if (!tx.isBlockConflicted()) return TxUpdate::UNCHANGED;
+ if (tx.state<TxStateBlockConflicted>()->conflicting_block_height >= disconnect_height) {
tx.m_state = TxStateInactive{};
return TxUpdate::CHANGED;
}
@@ -2787,7 +2819,7 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old
std::optional<uint256> block_hash;
if (auto* conf = wtx.state<TxStateConfirmed>()) {
block_hash = conf->confirmed_block_hash;
- } else if (auto* conf = wtx.state<TxStateConflicted>()) {
+ } else if (auto* conf = wtx.state<TxStateBlockConflicted>()) {
block_hash = conf->conflicting_block_hash;
}
@@ -3377,7 +3409,7 @@ int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
if (auto* conf = wtx.state<TxStateConfirmed>()) {
assert(conf->confirmed_block_height >= 0);
return GetLastBlockHeight() - conf->confirmed_block_height + 1;
- } else if (auto* conf = wtx.state<TxStateConflicted>()) {
+ } else if (auto* conf = wtx.state<TxStateBlockConflicted>()) {
assert(conf->conflicting_block_height >= 0);
return -1 * (GetLastBlockHeight() - conf->conflicting_block_height + 1);
} else {
@@ -3465,6 +3497,17 @@ std::set<ScriptPubKeyMan*> CWallet::GetActiveScriptPubKeyMans() const
return spk_mans;
}
+bool CWallet::IsActiveScriptPubKeyMan(const ScriptPubKeyMan& spkm) const
+{
+ for (const auto& [_, ext_spkm] : m_external_spk_managers) {
+ if (ext_spkm == &spkm) return true;
+ }
+ for (const auto& [_, int_spkm] : m_internal_spk_managers) {
+ if (int_spkm == &spkm) return true;
+ }
+ return false;
+}
+
std::set<ScriptPubKeyMan*> CWallet::GetAllScriptPubKeyMans() const
{
std::set<ScriptPubKeyMan*> spk_mans;
@@ -3619,6 +3662,26 @@ DescriptorScriptPubKeyMan& CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, Wa
return *spk_manager;
}
+DescriptorScriptPubKeyMan& CWallet::SetupDescriptorScriptPubKeyMan(WalletBatch& batch, const CExtKey& master_key, const OutputType& output_type, bool internal)
+{
+ AssertLockHeld(cs_wallet);
+ auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
+ if (IsCrypted()) {
+ if (IsLocked()) {
+ throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
+ }
+ if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, &batch)) {
+ throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
+ }
+ }
+ spk_manager->SetupDescriptorGeneration(batch, master_key, output_type, internal);
+ DescriptorScriptPubKeyMan* out = spk_manager.get();
+ uint256 id = spk_manager->GetID();
+ AddScriptPubKeyMan(id, std::move(spk_manager));
+ AddActiveScriptPubKeyManWithDb(batch, id, output_type, internal);
+ return *out;
+}
+
void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
{
AssertLockHeld(cs_wallet);
@@ -3629,19 +3692,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
- if (IsCrypted()) {
- if (IsLocked()) {
- throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
- }
- if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, &batch)) {
- throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
- }
- }
- spk_manager->SetupDescriptorGeneration(batch, master_key, t, internal);
- uint256 id = spk_manager->GetID();
- AddScriptPubKeyMan(id, std::move(spk_manager));
- AddActiveScriptPubKeyManWithDb(batch, id, t, internal);
+ SetupDescriptorScriptPubKeyMan(batch, master_key, t, internal);
}
}
@@ -4469,4 +4520,40 @@ void CWallet::TopUpCallback(const std::set<CScript>& spks, ScriptPubKeyMan* spkm
// Update scriptPubKey cache
CacheNewScriptPubKeys(spks, spkm);
}
+
+std::set<CExtPubKey> CWallet::GetActiveHDPubKeys() const
+{
+ AssertLockHeld(cs_wallet);
+
+ Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
+
+ std::set<CExtPubKey> active_xpubs;
+ for (const auto& spkm : GetActiveScriptPubKeyMans()) {
+ const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
+ assert(desc_spkm);
+ LOCK(desc_spkm->cs_desc_man);
+ WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();
+
+ std::set<CPubKey> desc_pubkeys;
+ std::set<CExtPubKey> desc_xpubs;
+ w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
+ active_xpubs.merge(std::move(desc_xpubs));
+ }
+ return active_xpubs;
+}
+
+std::optional<CKey> CWallet::GetKey(const CKeyID& keyid) const
+{
+ Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
+
+ for (const auto& spkm : GetAllScriptPubKeyMans()) {
+ const DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
+ assert(desc_spkm);
+ LOCK(desc_spkm->cs_desc_man);
+ if (std::optional<CKey> key = desc_spkm->GetKey(keyid)) {
+ return key;
+ }
+ }
+ return std::nullopt;
+}
} // namespace wallet
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 8b0ee22276..b49b5a7d0d 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -364,6 +364,7 @@ private:
/** Mark a transaction (and its in-wallet descendants) as a particular tx state. */
void RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -518,11 +519,6 @@ public:
* referenced in transaction, and might cause assert failures.
*/
int GetTxDepthInMainChain(const CWalletTx& wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool IsTxInMainChain(const CWalletTx& wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
- {
- AssertLockHeld(cs_wallet);
- return GetTxDepthInMainChain(wtx) > 0;
- }
/**
* @return number of blocks to maturity for this transaction:
@@ -942,6 +938,7 @@ public:
//! Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers
std::set<ScriptPubKeyMan*> GetActiveScriptPubKeyMans() const;
+ bool IsActiveScriptPubKeyMan(const ScriptPubKeyMan& spkm) const;
//! Returns all unique ScriptPubKeyMans
std::set<ScriptPubKeyMan*> GetAllScriptPubKeyMans() const;
@@ -1017,6 +1014,8 @@ public:
//! @param[in] internal Whether this ScriptPubKeyMan provides change addresses
void DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal);
+ //! Create new DescriptorScriptPubKeyMan and add it to the wallet
+ DescriptorScriptPubKeyMan& SetupDescriptorScriptPubKeyMan(WalletBatch& batch, const CExtKey& master_key, const OutputType& output_type, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Create new DescriptorScriptPubKeyMans and add them to the wallet
void SetupDescriptorScriptPubKeyMans(const CExtKey& master_key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -1053,6 +1052,13 @@ public:
void CacheNewScriptPubKeys(const std::set<CScript>& spks, ScriptPubKeyMan* spkm);
void TopUpCallback(const std::set<CScript>& spks, ScriptPubKeyMan* spkm) override;
+
+ //! Retrieve the xpubs in use by the active descriptors
+ std::set<CExtPubKey> GetActiveHDPubKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Find the private key for the given key id from the wallet's descriptors, if available
+ //! Returns nullopt when no descriptor has the key or if the wallet is locked.
+ std::optional<CKey> GetKey(const CKeyID& keyid) const;
};
/**
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index fdd5bc36d8..0de2617d45 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -4,7 +4,9 @@
#include <wallet/walletutil.h>
+#include <chainparams.h>
#include <common/args.h>
+#include <key_io.h>
#include <logging.h>
namespace wallet {
@@ -43,4 +45,58 @@ WalletFeature GetClosestWalletFeature(int version)
}
return static_cast<WalletFeature>(0);
}
+
+WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const OutputType& addr_type, bool internal)
+{
+ int64_t creation_time = GetTime();
+
+ std::string xpub = EncodeExtPubKey(master_key);
+
+ // Build descriptor string
+ std::string desc_prefix;
+ std::string desc_suffix = "/*)";
+ switch (addr_type) {
+ case OutputType::LEGACY: {
+ desc_prefix = "pkh(" + xpub + "/44h";
+ break;
+ }
+ case OutputType::P2SH_SEGWIT: {
+ desc_prefix = "sh(wpkh(" + xpub + "/49h";
+ desc_suffix += ")";
+ break;
+ }
+ case OutputType::BECH32: {
+ desc_prefix = "wpkh(" + xpub + "/84h";
+ break;
+ }
+ case OutputType::BECH32M: {
+ desc_prefix = "tr(" + xpub + "/86h";
+ break;
+ }
+ case OutputType::UNKNOWN: {
+ // We should never have a DescriptorScriptPubKeyMan for an UNKNOWN OutputType,
+ // so if we get to this point something is wrong
+ assert(false);
+ }
+ } // no default case, so the compiler can warn about missing cases
+ assert(!desc_prefix.empty());
+
+ // Mainnet derives at 0', testnet and regtest derive at 1'
+ if (Params().IsTestChain()) {
+ desc_prefix += "/1h";
+ } else {
+ desc_prefix += "/0h";
+ }
+
+ std::string internal_path = internal ? "/1" : "/0";
+ std::string desc_str = desc_prefix + "/0h" + internal_path + desc_suffix;
+
+ // Make the descriptor
+ FlatSigningProvider keys;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
+ WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
+ return w_desc;
+}
+
} // namespace wallet
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index 7ad3ffe9e4..38926c1eb8 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -114,6 +114,8 @@ public:
WalletDescriptor() {}
WalletDescriptor(std::shared_ptr<Descriptor> descriptor, uint64_t creation_time, int32_t range_start, int32_t range_end, int32_t next_index) : descriptor(descriptor), id(DescriptorID(*descriptor)), creation_time(creation_time), range_start(range_start), range_end(range_end), next_index(next_index) { }
};
+
+WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const OutputType& output_type, bool internal);
} // namespace wallet
#endif // BITCOIN_WALLET_WALLETUTIL_H
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 613d2eab14..982fa79915 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -159,7 +159,7 @@ class AssumeValidTest(BitcoinTestFramework):
for i in range(2202):
p2p1.send_message(msg_block(self.blocks[i]))
# Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
- p2p1.sync_with_ping(960)
+ p2p1.sync_with_ping(timeout=960)
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py
index b3bf35b524..66c0a4f615 100755
--- a/test/functional/feature_index_prune.py
+++ b/test/functional/feature_index_prune.py
@@ -31,7 +31,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
expected_stats = {
'coinstatsindex': {'synced': True, 'best_block_height': height}
}
- self.wait_until(lambda: self.nodes[1].getindexinfo() == expected_stats)
+ self.wait_until(lambda: self.nodes[1].getindexinfo() == expected_stats, timeout=150)
expected = {**expected_filter, **expected_stats}
self.wait_until(lambda: self.nodes[2].getindexinfo() == expected)
diff --git a/test/functional/p2p_block_sync.py b/test/functional/p2p_block_sync.py
index d821edc1b1..6c7f08364e 100755
--- a/test/functional/p2p_block_sync.py
+++ b/test/functional/p2p_block_sync.py
@@ -22,7 +22,7 @@ class BlockSyncTest(BitcoinTestFramework):
# node0 -> node1 -> node2
# So node1 has both an inbound and outbound peer.
# In our test, we will mine a block on node0, and ensure that it makes
- # to to both node1 and node2.
+ # to both node1 and node2.
self.connect_nodes(0, 1)
self.connect_nodes(1, 2)
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index d6c06fdeed..0950579580 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -139,7 +139,7 @@ class TestP2PConn(P2PInterface):
This is used when we want to send a message into the node that we expect
will get us disconnected, eg an invalid block."""
self.send_message(message)
- self.wait_for_disconnect(timeout)
+ self.wait_for_disconnect(timeout=timeout)
class CompactBlocksTest(BitcoinTestFramework):
def set_test_params(self):
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index 467bbad09c..8b63d8ee26 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -92,7 +92,8 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
# Wait until the full_node is headers-wise sync
best_block_hash = pruned_node.getbestblockhash()
- self.wait_until(lambda: next(filter(lambda x: x['hash'] == best_block_hash, full_node.getchaintips()))['status'] == "headers-only")
+ default_value = {'status': ''} # No status
+ self.wait_until(lambda: next(filter(lambda x: x['hash'] == best_block_hash, full_node.getchaintips()), default_value)['status'] == "headers-only")
# Now, since the node aims to download a window of 1024 blocks,
# ensure it requests the blocks below the threshold only (with a
@@ -137,7 +138,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.log.info("Requesting block at height 2 (tip-289) must fail (ignored).")
node.send_getdata_for_block(blocks[0]) # first block outside of the 288+2 limit
- node.wait_for_disconnect(5)
+ node.wait_for_disconnect(timeout=5)
self.nodes[0].disconnect_p2ps()
# connect unsynced node 2 with pruned NODE_NETWORK_LIMITED peer
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 1c0c11d74c..af47c6d9f0 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -198,15 +198,15 @@ class TestP2PConn(P2PInterface):
self.send_message(msg)
else:
self.send_message(msg_inv(inv=[CInv(MSG_BLOCK, block.sha256)]))
- self.wait_for_getheaders()
+ self.wait_for_getheaders(timeout=timeout)
self.send_message(msg)
- self.wait_for_getdata([block.sha256])
+ self.wait_for_getdata([block.sha256], timeout=timeout)
def request_block(self, blockhash, inv_type, timeout=60):
with p2p_lock:
self.last_message.pop("block", None)
self.send_message(msg_getdata(inv=[CInv(inv_type, blockhash)]))
- self.wait_for_block(blockhash, timeout)
+ self.wait_for_block(blockhash, timeout=timeout)
return self.last_message["block"].block
class SegWitTest(BitcoinTestFramework):
@@ -2056,7 +2056,7 @@ class SegWitTest(BitcoinTestFramework):
test_transaction_acceptance(self.nodes[0], self.wtx_node, tx2, with_witness=True, accepted=False)
# Expect a request for parent (tx) by txid despite use of WTX peer
- self.wtx_node.wait_for_getdata([tx.sha256], 60)
+ self.wtx_node.wait_for_getdata([tx.sha256], timeout=60)
with p2p_lock:
lgd = self.wtx_node.lastgetdata[:]
assert_equal(lgd, [CInv(MSG_WITNESS_TX, tx.sha256)])
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index dc04696114..ce76008c46 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -585,22 +585,22 @@ class P2PInterface(P2PConnection):
wait_until_helper_internal(test_function, timeout=timeout, lock=p2p_lock, timeout_factor=self.timeout_factor)
- def wait_for_connect(self, timeout=60):
+ def wait_for_connect(self, *, timeout=60):
test_function = lambda: self.is_connected
self.wait_until(test_function, timeout=timeout, check_connected=False)
- def wait_for_disconnect(self, timeout=60):
+ def wait_for_disconnect(self, *, timeout=60):
test_function = lambda: not self.is_connected
self.wait_until(test_function, timeout=timeout, check_connected=False)
- def wait_for_reconnect(self, timeout=60):
+ def wait_for_reconnect(self, *, timeout=60):
def test_function():
return self.is_connected and self.last_message.get('version') and not self.supports_v2_p2p
self.wait_until(test_function, timeout=timeout, check_connected=False)
# Message receiving helper methods
- def wait_for_tx(self, txid, timeout=60):
+ def wait_for_tx(self, txid, *, timeout=60):
def test_function():
if not self.last_message.get('tx'):
return False
@@ -608,13 +608,13 @@ class P2PInterface(P2PConnection):
self.wait_until(test_function, timeout=timeout)
- def wait_for_block(self, blockhash, timeout=60):
+ def wait_for_block(self, blockhash, *, timeout=60):
def test_function():
return self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
self.wait_until(test_function, timeout=timeout)
- def wait_for_header(self, blockhash, timeout=60):
+ def wait_for_header(self, blockhash, *, timeout=60):
def test_function():
last_headers = self.last_message.get('headers')
if not last_headers:
@@ -623,7 +623,7 @@ class P2PInterface(P2PConnection):
self.wait_until(test_function, timeout=timeout)
- def wait_for_merkleblock(self, blockhash, timeout=60):
+ def wait_for_merkleblock(self, blockhash, *, timeout=60):
def test_function():
last_filtered_block = self.last_message.get('merkleblock')
if not last_filtered_block:
@@ -632,7 +632,7 @@ class P2PInterface(P2PConnection):
self.wait_until(test_function, timeout=timeout)
- def wait_for_getdata(self, hash_list, timeout=60):
+ def wait_for_getdata(self, hash_list, *, timeout=60):
"""Waits for a getdata message.
The object hashes in the inventory vector must match the provided hash_list."""
@@ -644,7 +644,7 @@ class P2PInterface(P2PConnection):
self.wait_until(test_function, timeout=timeout)
- def wait_for_getheaders(self, timeout=60):
+ def wait_for_getheaders(self, *, timeout=60):
"""Waits for a getheaders message.
Receiving any getheaders message will satisfy the predicate. the last_message["getheaders"]
@@ -656,7 +656,7 @@ class P2PInterface(P2PConnection):
self.wait_until(test_function, timeout=timeout)
- def wait_for_inv(self, expected_inv, timeout=60):
+ def wait_for_inv(self, expected_inv, *, timeout=60):
"""Waits for an INV message and checks that the first inv object in the message was as expected."""
if len(expected_inv) > 1:
raise NotImplementedError("wait_for_inv() will only verify the first inv object")
@@ -668,7 +668,7 @@ class P2PInterface(P2PConnection):
self.wait_until(test_function, timeout=timeout)
- def wait_for_verack(self, timeout=60):
+ def wait_for_verack(self, *, timeout=60):
def test_function():
return "verack" in self.last_message
@@ -681,11 +681,11 @@ class P2PInterface(P2PConnection):
self.send_message(self.on_connection_send_msg)
self.on_connection_send_msg = None # Never used again
- def send_and_ping(self, message, timeout=60):
+ def send_and_ping(self, message, *, timeout=60):
self.send_message(message)
self.sync_with_ping(timeout=timeout)
- def sync_with_ping(self, timeout=60):
+ def sync_with_ping(self, *, timeout=60):
"""Ensure ProcessMessages and SendMessages is called on this connection"""
# Sending two pings back-to-back, requires that the node calls
# `ProcessMessage` twice, and thus ensures `SendMessages` must have
@@ -726,7 +726,7 @@ class NetworkThread(threading.Thread):
"""Start the network thread."""
self.network_event_loop.run_forever()
- def close(self, timeout=10):
+ def close(self, *, timeout=10):
"""Close the connections and network event loop."""
self.network_event_loop.call_soon_threadsafe(self.network_event_loop.stop)
wait_until_helper_internal(lambda: not self.network_event_loop.is_running(), timeout=timeout)
@@ -933,7 +933,7 @@ class P2PTxInvStore(P2PInterface):
with p2p_lock:
return list(self.tx_invs_received.keys())
- def wait_for_broadcast(self, txns, timeout=60):
+ def wait_for_broadcast(self, txns, *, timeout=60):
"""Waits for the txns (list of txids) to complete initial broadcast.
The mempool should mark unbroadcast=False for these transactions.
"""
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index c3884270da..a2f767cc98 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -164,7 +164,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
help="Don't stop bitcoinds after the test execution")
parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../cache"),
help="Directory for caching pregenerated datadirs (default: %(default)s)")
- parser.add_argument("--tmpdir", dest="tmpdir", help="Root directory for datadirs")
+ parser.add_argument("--tmpdir", dest="tmpdir", help="Root directory for datadirs (must not exist)")
parser.add_argument("-l", "--loglevel", dest="loglevel", default="INFO",
help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.")
parser.add_argument("--tracerpc", dest="trace_rpc", default=False, action="store_true",
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1408854e02..3f6e47d410 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -181,6 +181,8 @@ BASE_SCRIPTS = [
'wallet_keypool_topup.py --legacy-wallet',
'wallet_keypool_topup.py --descriptors',
'wallet_fast_rescan.py --descriptors',
+ 'wallet_gethdkeys.py --descriptors',
+ 'wallet_createwalletdescriptor.py --descriptors',
'interface_zmq.py',
'rpc_invalid_address_message.py',
'rpc_validateaddress.py',
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index e69546bb82..dda48aae1b 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -231,7 +231,11 @@ class AbandonConflictTest(BitcoinTestFramework):
balance = newbalance
# Invalidate the block with the double spend. B & C's 10 BTC outputs should no longer be available
- self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
+ blk = self.nodes[0].getbestblockhash()
+ # mine 10 blocks so that when the blk is invalidated, the transactions are not
+ # returned to the mempool
+ self.generate(self.nodes[1], 10)
+ self.nodes[0].invalidateblock(blk)
assert_equal(alice.gettransaction(txAB1)["confirmations"], 0)
newbalance = alice.getbalance()
assert_equal(newbalance, balance - Decimal("20"))
diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py
index 4d6e6024c5..ab008a40cd 100755
--- a/test/functional/wallet_backwards_compatibility.py
+++ b/test/functional/wallet_backwards_compatibility.py
@@ -355,6 +355,25 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
down_wallet_name = f"re_down_{node.version}"
down_backup_path = os.path.join(self.options.tmpdir, f"{down_wallet_name}.dat")
wallet.backupwallet(down_backup_path)
+
+ # Check that taproot descriptors can be added to 0.21 wallets
+ # This must be done after the backup is created so that 0.21 can still load
+ # the backup
+ if self.options.descriptors and self.major_version_equals(node, 21):
+ assert_raises_rpc_error(-12, "No bech32m addresses available", wallet.getnewaddress, address_type="bech32m")
+ xpubs = wallet.gethdkeys(active_only=True)
+ assert_equal(len(xpubs), 1)
+ assert_equal(len(xpubs[0]["descriptors"]), 6)
+ wallet.createwalletdescriptor("bech32m")
+ xpubs = wallet.gethdkeys(active_only=True)
+ assert_equal(len(xpubs), 1)
+ assert_equal(len(xpubs[0]["descriptors"]), 8)
+ tr_descs = [desc["desc"] for desc in xpubs[0]["descriptors"] if desc["desc"].startswith("tr(")]
+ assert_equal(len(tr_descs), 2)
+ for desc in tr_descs:
+ assert info["hdmasterfingerprint"] in desc
+ wallet.getnewaddress(address_type="bech32m")
+
wallet.unloadwallet()
# Check that no automatic upgrade broke the downgrading the wallet
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 31d3c14e55..56228d2bad 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -681,7 +681,7 @@ class WalletTest(BitcoinTestFramework):
"category": baz["category"],
"vout": baz["vout"]}
expected_fields = frozenset({'amount', 'bip125-replaceable', 'confirmations', 'details', 'fee',
- 'hex', 'lastprocessedblock', 'time', 'timereceived', 'trusted', 'txid', 'wtxid', 'walletconflicts'})
+ 'hex', 'lastprocessedblock', 'time', 'timereceived', 'trusted', 'txid', 'wtxid', 'walletconflicts', 'mempoolconflicts'})
verbose_field = "decoded"
expected_verbose_fields = expected_fields | {verbose_field}
diff --git a/test/functional/wallet_conflicts.py b/test/functional/wallet_conflicts.py
index 802b718cd5..e5739a6a59 100755
--- a/test/functional/wallet_conflicts.py
+++ b/test/functional/wallet_conflicts.py
@@ -9,6 +9,7 @@ Test that wallet correctly tracks transactions that have been conflicted by bloc
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -28,6 +29,20 @@ class TxConflicts(BitcoinTestFramework):
return next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(from_tx_id)["details"] if tx_out["amount"] == Decimal(f"{search_value}"))
def run_test(self):
+ """
+ The following tests check the behavior of the wallet when
+ transaction conflicts are created. These conflicts are created
+ using raw transaction RPCs that double-spend UTXOs and have more
+ fees, replacing the original transaction.
+ """
+
+ self.test_block_conflicts()
+ self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 7, self.nodes[2].getnewaddress())
+ self.test_mempool_conflict()
+ self.test_mempool_and_block_conflicts()
+ self.test_descendants_with_mempool_conflicts()
+
+ def test_block_conflicts(self):
self.log.info("Send tx from which to conflict outputs later")
txid_conflict_from_1 = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
txid_conflict_from_2 = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
@@ -123,5 +138,291 @@ class TxConflicts(BitcoinTestFramework):
assert_equal(former_conflicted["confirmations"], 1)
assert_equal(former_conflicted["blockheight"], 217)
+ def test_mempool_conflict(self):
+ self.nodes[0].createwallet("alice")
+ alice = self.nodes[0].get_wallet_rpc("alice")
+
+ bob = self.nodes[1]
+
+ self.nodes[2].send(outputs=[{alice.getnewaddress() : 25} for _ in range(3)])
+ self.generate(self.nodes[2], 1)
+
+ self.log.info("Test a scenario where a transaction has a mempool conflict")
+
+ unspents = alice.listunspent()
+ assert_equal(len(unspents), 3)
+ assert all([tx["amount"] == 25 for tx in unspents])
+
+ # tx1 spends unspent[0] and unspent[1]
+ raw_tx = alice.createrawtransaction(inputs=[unspents[0], unspents[1]], outputs=[{bob.getnewaddress() : 49.9999}])
+ tx1 = alice.signrawtransactionwithwallet(raw_tx)['hex']
+
+ # tx2 spends unspent[1] and unspent[2], conflicts with tx1
+ raw_tx = alice.createrawtransaction(inputs=[unspents[1], unspents[2]], outputs=[{bob.getnewaddress() : 49.99}])
+ tx2 = alice.signrawtransactionwithwallet(raw_tx)['hex']
+
+ # tx3 spends unspent[2], conflicts with tx2
+ raw_tx = alice.createrawtransaction(inputs=[unspents[2]], outputs=[{bob.getnewaddress() : 24.9899}])
+ tx3 = alice.signrawtransactionwithwallet(raw_tx)['hex']
+
+ # broadcast tx1
+ tx1_txid = alice.sendrawtransaction(tx1)
+
+ assert_equal(alice.listunspent(), [unspents[2]])
+ assert_equal(alice.getbalance(), 25)
+
+ # broadcast tx2, replaces tx1 in mempool
+ tx2_txid = alice.sendrawtransaction(tx2)
+
+ # Check that unspent[0] is now available because the transaction spending it has been replaced in the mempool
+ assert_equal(alice.listunspent(), [unspents[0]])
+ assert_equal(alice.getbalance(), 25)
+
+ assert_equal(alice.gettransaction(tx1_txid)["mempoolconflicts"], [tx2_txid])
+
+ self.log.info("Test scenario where a mempool conflict is removed")
+
+ # broadcast tx3, replaces tx2 in mempool
+ # Now that tx1's conflict has been removed, tx1 is now
+ # not conflicted, and instead is inactive until it is
+ # rebroadcasted. Now unspent[0] is not available, because
+ # tx1 is no longer conflicted.
+ alice.sendrawtransaction(tx3)
+
+ assert_equal(alice.gettransaction(tx1_txid)["mempoolconflicts"], [])
+ assert tx1_txid not in self.nodes[0].getrawmempool()
+
+ # now all of alice's outputs should be considered spent
+ # unspent[0]: spent by inactive tx1
+ # unspent[1]: spent by inactive tx1
+ # unspent[2]: spent by active tx3
+ assert_equal(alice.listunspent(), [])
+ assert_equal(alice.getbalance(), 0)
+
+ # Clean up for next test
+ bob.sendall([self.nodes[2].getnewaddress()])
+ self.generate(self.nodes[2], 1)
+
+ alice.unloadwallet()
+
+ def test_mempool_and_block_conflicts(self):
+ self.nodes[0].createwallet("alice_2")
+ alice = self.nodes[0].get_wallet_rpc("alice_2")
+ bob = self.nodes[1]
+
+ self.nodes[2].send(outputs=[{alice.getnewaddress() : 25} for _ in range(3)])
+ self.generate(self.nodes[2], 1)
+
+ self.log.info("Test a scenario where a transaction has both a block conflict and a mempool conflict")
+ unspents = [{"txid" : element["txid"], "vout" : element["vout"]} for element in alice.listunspent()]
+
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+
+ # alice and bob nodes are disconnected so that transactions can be
+ # created by alice, but broadcasted from bob so that alice's wallet
+ # doesn't know about them
+ self.disconnect_nodes(0, 1)
+
+ # Sends funds to bob
+ raw_tx = alice.createrawtransaction(inputs=[unspents[0]], outputs=[{bob.getnewaddress() : 24.99999}])
+ raw_tx1 = alice.signrawtransactionwithwallet(raw_tx)['hex']
+ tx1_txid = bob.sendrawtransaction(raw_tx1) # broadcast original tx spending unspents[0] only to bob
+
+ # create a conflict to previous tx (also spends unspents[0]), but don't broadcast, sends funds back to alice
+ raw_tx = alice.createrawtransaction(inputs=[unspents[0], unspents[2]], outputs=[{alice.getnewaddress() : 49.999}])
+ tx1_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']
+
+ # Sends funds to bob
+ raw_tx = alice.createrawtransaction(inputs=[unspents[1]], outputs=[{bob.getnewaddress() : 24.9999}])
+ raw_tx2 = alice.signrawtransactionwithwallet(raw_tx)['hex']
+ tx2_txid = bob.sendrawtransaction(raw_tx2) # broadcast another original tx spending unspents[1] only to bob
+
+ # create a conflict to previous tx (also spends unspents[1]), but don't broadcast, sends funds to alice
+ raw_tx = alice.createrawtransaction(inputs=[unspents[1]], outputs=[{alice.getnewaddress() : 24.9999}])
+ tx2_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']
+
+ bob_unspents = [{"txid" : element, "vout" : 0} for element in [tx1_txid, tx2_txid]]
+
+ # tx1 and tx2 are now in bob's mempool, and they are unconflicted, so bob has these funds
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("49.99989000"))
+
+ # spend both of bob's unspents, child tx of tx1 and tx2
+ raw_tx = bob.createrawtransaction(inputs=[bob_unspents[0], bob_unspents[1]], outputs=[{bob.getnewaddress() : 49.999}])
+ raw_tx3 = bob.signrawtransactionwithwallet(raw_tx)['hex']
+ tx3_txid = bob.sendrawtransaction(raw_tx3) # broadcast tx only to bob
+
+ # alice knows about 0 txs, bob knows about 3
+ assert_equal(len(alice.getrawmempool()), 0)
+ assert_equal(len(bob.getrawmempool()), 3)
+
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("49.99900000"))
+
+ # bob broadcasts tx_1 conflict
+ tx1_conflict_txid = bob.sendrawtransaction(tx1_conflict)
+ assert_equal(len(alice.getrawmempool()), 0)
+ assert_equal(len(bob.getrawmempool()), 2) # tx1_conflict kicks out both tx1, and its child tx3
+
+ assert tx2_txid in bob.getrawmempool()
+ assert tx1_conflict_txid in bob.getrawmempool()
+
+ assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [tx1_conflict_txid])
+ assert_equal(bob.gettransaction(tx2_txid)["mempoolconflicts"], [])
+ assert_equal(bob.gettransaction(tx3_txid)["mempoolconflicts"], [tx1_conflict_txid])
+
+ # check that tx3 is now conflicted, so the output from tx2 can now be spent
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("24.99990000"))
+
+ # we will be disconnecting this block in the future
+ alice.sendrawtransaction(tx2_conflict)
+ assert_equal(len(alice.getrawmempool()), 1) # currently alice's mempool is only aware of tx2_conflict
+ # 11 blocks are mined so that when they are invalidated, tx_2
+ # does not get put back into the mempool
+ blk = self.generate(self.nodes[0], 11, sync_fun=self.no_op)[0]
+ assert_equal(len(alice.getrawmempool()), 0) # tx2_conflict is now mined
+
+ self.connect_nodes(0, 1)
+ self.sync_blocks()
+ assert_equal(alice.getbestblockhash(), bob.getbestblockhash())
+
+ # now that tx2 has a block conflict, tx1_conflict should be the only tx in bob's mempool
+ assert tx1_conflict_txid in bob.getrawmempool()
+ assert_equal(len(bob.getrawmempool()), 1)
+
+ # tx3 should now also be block-conflicted by tx2_conflict
+ assert_equal(bob.gettransaction(tx3_txid)["confirmations"], -11)
+ # bob has no pending funds, since tx1, tx2, and tx3 are all conflicted
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+ bob.invalidateblock(blk) # remove tx2_conflict
+ # bob should still have no pending funds because tx1 and tx3 are still conflicted, and tx2 has not been re-broadcast
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+ assert_equal(len(bob.getrawmempool()), 1)
+ # check that tx3 is no longer block-conflicted
+ assert_equal(bob.gettransaction(tx3_txid)["confirmations"], 0)
+
+ bob.sendrawtransaction(raw_tx2)
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("24.99990000"))
+
+ # create a conflict to previous tx (also spends unspents[2]), but don't broadcast, sends funds back to alice
+ raw_tx = alice.createrawtransaction(inputs=[unspents[2]], outputs=[{alice.getnewaddress() : 24.99}])
+ tx1_conflict_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']
+
+ bob.sendrawtransaction(tx1_conflict_conflict) # kick tx1_conflict out of the mempool
+ bob.sendrawtransaction(raw_tx1) #re-broadcast tx1 because it is no longer conflicted
+
+ # Now bob has no pending funds because tx1 and tx2 are spent by tx3, which hasn't been re-broadcast yet
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+
+ bob.sendrawtransaction(raw_tx3)
+ assert_equal(len(bob.getrawmempool()), 4) # The mempool contains: tx1, tx2, tx1_conflict_conflict, tx3
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("49.99900000"))
+
+ # Clean up for next test
+ bob.reconsiderblock(blk)
+ assert_equal(alice.getbestblockhash(), bob.getbestblockhash())
+ self.sync_mempools()
+ self.generate(self.nodes[2], 1)
+
+ alice.unloadwallet()
+
+ def test_descendants_with_mempool_conflicts(self):
+ self.nodes[0].createwallet("alice_3")
+ alice = self.nodes[0].get_wallet_rpc("alice_3")
+
+ self.nodes[2].send(outputs=[{alice.getnewaddress() : 25} for _ in range(2)])
+ self.generate(self.nodes[2], 1)
+
+ self.nodes[1].createwallet("bob_1")
+ bob = self.nodes[1].get_wallet_rpc("bob_1")
+
+ self.nodes[2].createwallet("carol")
+ carol = self.nodes[2].get_wallet_rpc("carol")
+
+ self.log.info("Test a scenario where a transaction's parent has a mempool conflict")
+
+ unspents = alice.listunspent()
+ assert_equal(len(unspents), 2)
+ assert all([tx["amount"] == 25 for tx in unspents])
+
+ assert_equal(alice.getrawmempool(), [])
+
+ # Alice spends first utxo to bob in tx1
+ raw_tx = alice.createrawtransaction(inputs=[unspents[0]], outputs=[{bob.getnewaddress() : 24.9999}])
+ tx1 = alice.signrawtransactionwithwallet(raw_tx)['hex']
+ tx1_txid = alice.sendrawtransaction(tx1)
+
+ self.sync_mempools()
+
+ assert_equal(alice.getbalance(), 25)
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("24.99990000"))
+
+ assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [])
+
+ raw_tx = bob.createrawtransaction(inputs=[bob.listunspent(minconf=0)[0]], outputs=[{carol.getnewaddress() : 24.999}])
+ # Bob creates a child to tx1
+ tx1_child = bob.signrawtransactionwithwallet(raw_tx)['hex']
+ tx1_child_txid = bob.sendrawtransaction(tx1_child)
+
+ self.sync_mempools()
+
+ # Currently neither tx1 nor tx1_child should have any conflicts
+ assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [])
+ assert_equal(bob.gettransaction(tx1_child_txid)["mempoolconflicts"], [])
+ assert tx1_txid in bob.getrawmempool()
+ assert tx1_child_txid in bob.getrawmempool()
+ assert_equal(len(bob.getrawmempool()), 2)
+
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+ assert_equal(carol.getbalances()["mine"]["untrusted_pending"], Decimal("24.99900000"))
+
+ # Alice spends first unspent again, conflicting with tx1
+ raw_tx = alice.createrawtransaction(inputs=[unspents[0], unspents[1]], outputs=[{carol.getnewaddress() : 49.99}])
+ tx1_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']
+ tx1_conflict_txid = alice.sendrawtransaction(tx1_conflict)
+
+ self.sync_mempools()
+
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+ assert_equal(carol.getbalances()["mine"]["untrusted_pending"], Decimal("49.99000000"))
+
+ assert tx1_txid not in bob.getrawmempool()
+ assert tx1_child_txid not in bob.getrawmempool()
+ assert tx1_conflict_txid in bob.getrawmempool()
+ assert_equal(len(bob.getrawmempool()), 1)
+
+ # Now both tx1 and tx1_child are conflicted by tx1_conflict
+ assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [tx1_conflict_txid])
+ assert_equal(bob.gettransaction(tx1_child_txid)["mempoolconflicts"], [tx1_conflict_txid])
+
+ # Now create a conflict to tx1_conflict, so that it gets kicked out of the mempool
+ raw_tx = alice.createrawtransaction(inputs=[unspents[1]], outputs=[{carol.getnewaddress() : 24.9895}])
+ tx1_conflict_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']
+ tx1_conflict_conflict_txid = alice.sendrawtransaction(tx1_conflict_conflict)
+
+ self.sync_mempools()
+
+ # Now that tx1_conflict has been removed, both tx1 and tx1_child
+ assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [])
+ assert_equal(bob.gettransaction(tx1_child_txid)["mempoolconflicts"], [])
+
+ # Both tx1 and tx1_child are still not in the mempool because they have not be re-broadcasted
+ assert tx1_txid not in bob.getrawmempool()
+ assert tx1_child_txid not in bob.getrawmempool()
+ assert tx1_conflict_txid not in bob.getrawmempool()
+ assert tx1_conflict_conflict_txid in bob.getrawmempool()
+ assert_equal(len(bob.getrawmempool()), 1)
+
+ assert_equal(alice.getbalance(), 0)
+ assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)
+ assert_equal(carol.getbalances()["mine"]["untrusted_pending"], Decimal("24.98950000"))
+
+ # Both tx1 and tx1_child can now be re-broadcasted
+ bob.sendrawtransaction(tx1)
+ bob.sendrawtransaction(tx1_child)
+ assert_equal(len(bob.getrawmempool()), 3)
+
+ alice.unloadwallet()
+ bob.unloadwallet()
+ carol.unloadwallet()
+
if __name__ == '__main__':
TxConflicts().main()
diff --git a/test/functional/wallet_createwalletdescriptor.py b/test/functional/wallet_createwalletdescriptor.py
new file mode 100755
index 0000000000..18e1703da3
--- /dev/null
+++ b/test/functional/wallet_createwalletdescriptor.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 wallet createwalletdescriptor RPC."""
+
+from test_framework.descriptors import descsum_create
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+from test_framework.wallet_util import WalletUnlock
+
+
+class WalletCreateDescriptorTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=True, legacy=False)
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ self.test_basic()
+ self.test_imported_other_keys()
+ self.test_encrypted()
+
+ def test_basic(self):
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].createwallet("blank", blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("blank")
+
+ xpub_info = def_wallet.gethdkeys(private=True)
+ xpub = xpub_info[0]["xpub"]
+ xprv = xpub_info[0]["xprv"]
+ expected_descs = []
+ for desc in def_wallet.listdescriptors()["descriptors"]:
+ if desc["desc"].startswith("wpkh("):
+ expected_descs.append(desc["desc"])
+
+ assert_raises_rpc_error(-5, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'", wallet.createwalletdescriptor, "bech32")
+ assert_raises_rpc_error(-5, f"Private key for {xpub} is not known", wallet.createwalletdescriptor, type="bech32", hdkey=xpub)
+
+ self.log.info("Test createwalletdescriptor after importing active descriptor to blank wallet")
+ # Import one active descriptor
+ assert_equal(wallet.importdescriptors([{"desc": descsum_create(f"pkh({xprv}/44h/2h/0h/0/0/*)"), "timestamp": "now", "active": True}])[0]["success"], True)
+ assert_equal(len(wallet.listdescriptors()["descriptors"]), 1)
+ assert_equal(len(wallet.gethdkeys()), 1)
+
+ new_descs = wallet.createwalletdescriptor("bech32")["descs"]
+ assert_equal(len(new_descs), 2)
+ assert_equal(len(wallet.gethdkeys()), 1)
+ assert_equal(new_descs, expected_descs)
+
+ self.log.info("Test descriptor creation options")
+ old_descs = set([(d["desc"], d["active"], d["internal"]) for d in wallet.listdescriptors(private=True)["descriptors"]])
+ wallet.createwalletdescriptor(type="bech32m", internal=False)
+ curr_descs = set([(d["desc"], d["active"], d["internal"]) for d in wallet.listdescriptors(private=True)["descriptors"]])
+ new_descs = list(curr_descs - old_descs)
+ assert_equal(len(new_descs), 1)
+ assert_equal(len(wallet.gethdkeys()), 1)
+ assert_equal(new_descs[0][0], descsum_create(f"tr({xprv}/86h/1h/0h/0/*)"))
+ assert_equal(new_descs[0][1], True)
+ assert_equal(new_descs[0][2], False)
+
+ old_descs = curr_descs
+ wallet.createwalletdescriptor(type="bech32m", internal=True)
+ curr_descs = set([(d["desc"], d["active"], d["internal"]) for d in wallet.listdescriptors(private=True)["descriptors"]])
+ new_descs = list(curr_descs - old_descs)
+ assert_equal(len(new_descs), 1)
+ assert_equal(len(wallet.gethdkeys()), 1)
+ assert_equal(new_descs[0][0], descsum_create(f"tr({xprv}/86h/1h/0h/1/*)"))
+ assert_equal(new_descs[0][1], True)
+ assert_equal(new_descs[0][2], True)
+
+ def test_imported_other_keys(self):
+ self.log.info("Test createwalletdescriptor with multiple keys in active descriptors")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].createwallet("multiple_keys")
+ wallet = self.nodes[0].get_wallet_rpc("multiple_keys")
+
+ wallet_xpub = wallet.gethdkeys()[0]["xpub"]
+
+ xpub_info = def_wallet.gethdkeys(private=True)
+ xpub = xpub_info[0]["xpub"]
+ xprv = xpub_info[0]["xprv"]
+
+ assert_equal(wallet.importdescriptors([{"desc": descsum_create(f"wpkh({xprv}/0/0/*)"), "timestamp": "now", "active": True}])[0]["success"], True)
+ assert_equal(len(wallet.gethdkeys()), 2)
+
+ assert_raises_rpc_error(-5, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'", wallet.createwalletdescriptor, "bech32")
+ assert_raises_rpc_error(-4, "Descriptor already exists", wallet.createwalletdescriptor, type="bech32m", hdkey=wallet_xpub)
+ assert_raises_rpc_error(-5, "Unable to parse HD key. Please provide a valid xpub", wallet.createwalletdescriptor, type="bech32m", hdkey=xprv)
+
+ # Able to replace tr() descriptor with other hd key
+ wallet.createwalletdescriptor(type="bech32m", hdkey=xpub)
+
+ def test_encrypted(self):
+ self.log.info("Test createwalletdescriptor with encrypted wallets")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].createwallet("encrypted", blank=True, passphrase="pass")
+ wallet = self.nodes[0].get_wallet_rpc("encrypted")
+
+ xpub_info = def_wallet.gethdkeys(private=True)
+ xprv = xpub_info[0]["xprv"]
+
+ with WalletUnlock(wallet, "pass"):
+ assert_equal(wallet.importdescriptors([{"desc": descsum_create(f"wpkh({xprv}/0/0/*)"), "timestamp": "now", "active": True}])[0]["success"], True)
+ assert_equal(len(wallet.gethdkeys()), 1)
+
+ assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wallet.createwalletdescriptor, type="bech32m")
+
+ with WalletUnlock(wallet, "pass"):
+ wallet.createwalletdescriptor(type="bech32m")
+
+
+
+if __name__ == '__main__':
+ WalletCreateDescriptorTest().main()
diff --git a/test/functional/wallet_gethdkeys.py b/test/functional/wallet_gethdkeys.py
new file mode 100755
index 0000000000..f09b8c875a
--- /dev/null
+++ b/test/functional/wallet_gethdkeys.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 wallet gethdkeys RPC."""
+
+from test_framework.descriptors import descsum_create
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+from test_framework.wallet_util import WalletUnlock
+
+
+class WalletGetHDKeyTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser, descriptors=True, legacy=False)
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ self.test_basic_gethdkeys()
+ self.test_ranged_imports()
+ self.test_lone_key_imports()
+ self.test_ranged_multisig()
+ self.test_mixed_multisig()
+
+ def test_basic_gethdkeys(self):
+ self.log.info("Test gethdkeys basics")
+ self.nodes[0].createwallet("basic")
+ wallet = self.nodes[0].get_wallet_rpc("basic")
+ xpub_info = wallet.gethdkeys()
+ assert_equal(len(xpub_info), 1)
+ assert_equal(xpub_info[0]["has_private"], True)
+
+ assert "xprv" not in xpub_info[0]
+ xpub = xpub_info[0]["xpub"]
+
+ xpub_info = wallet.gethdkeys(private=True)
+ xprv = xpub_info[0]["xprv"]
+ assert_equal(xpub_info[0]["xpub"], xpub)
+ assert_equal(xpub_info[0]["has_private"], True)
+
+ descs = wallet.listdescriptors(True)
+ for desc in descs["descriptors"]:
+ assert xprv in desc["desc"]
+
+ self.log.info("HD pubkey can be retrieved from encrypted wallets")
+ prev_xprv = xprv
+ wallet.encryptwallet("pass")
+ # HD key is rotated on encryption, there should now be 2 HD keys
+ assert_equal(len(wallet.gethdkeys()), 2)
+ # New key is active, should be able to get only that one and its descriptors
+ xpub_info = wallet.gethdkeys(active_only=True)
+ assert_equal(len(xpub_info), 1)
+ assert xpub_info[0]["xpub"] != xpub
+ assert "xprv" not in xpub_info[0]
+ assert_equal(xpub_info[0]["has_private"], True)
+
+ self.log.info("HD privkey can be retrieved from encrypted wallets")
+ assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first", wallet.gethdkeys, private=True)
+ with WalletUnlock(wallet, "pass"):
+ xpub_info = wallet.gethdkeys(active_only=True, private=True)[0]
+ assert xpub_info["xprv"] != xprv
+ for desc in wallet.listdescriptors(True)["descriptors"]:
+ if desc["active"]:
+ # After encrypting, HD key was rotated and should appear in all active descriptors
+ assert xpub_info["xprv"] in desc["desc"]
+ else:
+ # Inactive descriptors should have the previous HD key
+ assert prev_xprv in desc["desc"]
+
+ def test_ranged_imports(self):
+ self.log.info("Keys of imported ranged descriptors appear in gethdkeys")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].createwallet("imports")
+ wallet = self.nodes[0].get_wallet_rpc("imports")
+
+ xpub_info = wallet.gethdkeys()
+ assert_equal(len(xpub_info), 1)
+ active_xpub = xpub_info[0]["xpub"]
+
+ import_xpub = def_wallet.gethdkeys(active_only=True)[0]["xpub"]
+ desc_import = def_wallet.listdescriptors(True)["descriptors"]
+ for desc in desc_import:
+ desc["active"] = False
+ wallet.importdescriptors(desc_import)
+ assert_equal(wallet.gethdkeys(active_only=True), xpub_info)
+
+ xpub_info = wallet.gethdkeys()
+ assert_equal(len(xpub_info), 2)
+ for x in xpub_info:
+ if x["xpub"] == active_xpub:
+ for desc in x["descriptors"]:
+ assert_equal(desc["active"], True)
+ elif x["xpub"] == import_xpub:
+ for desc in x["descriptors"]:
+ assert_equal(desc["active"], False)
+ else:
+ assert False
+
+
+ def test_lone_key_imports(self):
+ self.log.info("Non-HD keys do not appear in gethdkeys")
+ self.nodes[0].createwallet("lonekey", blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("lonekey")
+
+ assert_equal(wallet.gethdkeys(), [])
+ wallet.importdescriptors([{"desc": descsum_create("wpkh(cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh)"), "timestamp": "now"}])
+ assert_equal(wallet.gethdkeys(), [])
+
+ self.log.info("HD keys of non-ranged descriptors should appear in gethdkeys")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ xpub_info = def_wallet.gethdkeys(private=True)
+ xpub = xpub_info[0]["xpub"]
+ xprv = xpub_info[0]["xprv"]
+ prv_desc = descsum_create(f"wpkh({xprv})")
+ pub_desc = descsum_create(f"wpkh({xpub})")
+ assert_equal(wallet.importdescriptors([{"desc": prv_desc, "timestamp": "now"}])[0]["success"], True)
+ xpub_info = wallet.gethdkeys()
+ assert_equal(len(xpub_info), 1)
+ assert_equal(xpub_info[0]["xpub"], xpub)
+ assert_equal(len(xpub_info[0]["descriptors"]), 1)
+ assert_equal(xpub_info[0]["descriptors"][0]["desc"], pub_desc)
+ assert_equal(xpub_info[0]["descriptors"][0]["active"], False)
+
+ def test_ranged_multisig(self):
+ self.log.info("HD keys of a multisig appear in gethdkeys")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].createwallet("ranged_multisig")
+ wallet = self.nodes[0].get_wallet_rpc("ranged_multisig")
+
+ xpub1 = wallet.gethdkeys()[0]["xpub"]
+ xprv1 = wallet.gethdkeys(private=True)[0]["xprv"]
+ xpub2 = def_wallet.gethdkeys()[0]["xpub"]
+
+ prv_multi_desc = descsum_create(f"wsh(multi(2,{xprv1}/*,{xpub2}/*))")
+ pub_multi_desc = descsum_create(f"wsh(multi(2,{xpub1}/*,{xpub2}/*))")
+ assert_equal(wallet.importdescriptors([{"desc": prv_multi_desc, "timestamp": "now"}])[0]["success"], True)
+
+ xpub_info = wallet.gethdkeys()
+ assert_equal(len(xpub_info), 2)
+ for x in xpub_info:
+ if x["xpub"] == xpub1:
+ found_desc = next((d for d in xpub_info[0]["descriptors"] if d["desc"] == pub_multi_desc), None)
+ assert found_desc is not None
+ assert_equal(found_desc["active"], False)
+ elif x["xpub"] == xpub2:
+ assert_equal(len(x["descriptors"]), 1)
+ assert_equal(x["descriptors"][0]["desc"], pub_multi_desc)
+ assert_equal(x["descriptors"][0]["active"], False)
+ else:
+ assert False
+
+ def test_mixed_multisig(self):
+ self.log.info("Non-HD keys of a multisig do not appear in gethdkeys")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ self.nodes[0].createwallet("single_multisig")
+ wallet = self.nodes[0].get_wallet_rpc("single_multisig")
+
+ xpub = wallet.gethdkeys()[0]["xpub"]
+ xprv = wallet.gethdkeys(private=True)[0]["xprv"]
+ pub = def_wallet.getaddressinfo(def_wallet.getnewaddress())["pubkey"]
+
+ prv_multi_desc = descsum_create(f"wsh(multi(2,{xprv},{pub}))")
+ pub_multi_desc = descsum_create(f"wsh(multi(2,{xpub},{pub}))")
+ import_res = wallet.importdescriptors([{"desc": prv_multi_desc, "timestamp": "now"}])
+ assert_equal(import_res[0]["success"], True)
+
+ xpub_info = wallet.gethdkeys()
+ assert_equal(len(xpub_info), 1)
+ assert_equal(xpub_info[0]["xpub"], xpub)
+ found_desc = next((d for d in xpub_info[0]["descriptors"] if d["desc"] == pub_multi_desc), None)
+ assert found_desc is not None
+ assert_equal(found_desc["active"], False)
+
+
+if __name__ == '__main__':
+ WalletGetHDKeyTest().main()
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index 3b407c285d..26477131cf 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -42,11 +42,6 @@ class WalletGroupTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Setting up")
- # To take full use of immediate tx relay, all nodes need to be reachable
- # via inbound peers, i.e. connect first to last to close the circle
- # (the default test network topology looks like this:
- # node0 <-- node1 <-- node2 <-- node3 <-- node4 <-- node5)
- self.connect_nodes(0, self.num_nodes - 1)
# Mine some coins
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index 420bdffc49..f9d05a2fe4 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -688,7 +688,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
encrypted_wallet.walletpassphrase("passphrase", 99999)
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as thread:
- with self.nodes[0].assert_debug_log(expected_msgs=["Rescan started from block 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206... (slow variant inspecting all blocks)"], timeout=5):
+ with self.nodes[0].assert_debug_log(expected_msgs=["Rescan started from block 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206... (slow variant inspecting all blocks)"], timeout=10):
importing = thread.submit(encrypted_wallet.importdescriptors, requests=[descriptor])
# Set the passphrase timeout to 1 to test that the wallet remains unlocked during the rescan
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index b3edb0e253..558d63e85c 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -104,9 +104,11 @@ def main():
logging.error("Must have fuzz executable built")
sys.exit(1)
+ fuzz_bin=os.getenv("BITCOINFUZZ", default=os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz'))
+
# Build list of tests
test_list_all = parse_test_list(
- fuzz_bin=os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz'),
+ fuzz_bin=fuzz_bin,
source_dir=config['environment']['SRCDIR'],
)
@@ -151,7 +153,7 @@ def main():
try:
help_output = subprocess.run(
args=[
- os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz'),
+ fuzz_bin,
'-help=1',
],
env=get_fuzz_env(target=test_list_selection[0], source_dir=config['environment']['SRCDIR']),
@@ -173,7 +175,7 @@ def main():
return generate_corpus(
fuzz_pool=fuzz_pool,
src_dir=config['environment']['SRCDIR'],
- build_dir=config["environment"]["BUILDDIR"],
+ fuzz_bin=fuzz_bin,
corpus_dir=args.corpus_dir,
targets=test_list_selection,
)
@@ -184,7 +186,7 @@ def main():
corpus=args.corpus_dir,
test_list=test_list_selection,
src_dir=config['environment']['SRCDIR'],
- build_dir=config["environment"]["BUILDDIR"],
+ fuzz_bin=fuzz_bin,
merge_dirs=[Path(m_dir) for m_dir in args.m_dir],
)
return
@@ -194,7 +196,7 @@ def main():
corpus=args.corpus_dir,
test_list=test_list_selection,
src_dir=config['environment']['SRCDIR'],
- build_dir=config["environment"]["BUILDDIR"],
+ fuzz_bin=fuzz_bin,
using_libfuzzer=using_libfuzzer,
use_valgrind=args.valgrind,
empty_min_time=args.empty_min_time,
@@ -237,7 +239,7 @@ def transform_rpc_target(targets, src_dir):
return targets
-def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
+def generate_corpus(*, fuzz_pool, src_dir, fuzz_bin, corpus_dir, targets):
"""Generates new corpus.
Run {targets} without input, and outputs the generated corpus to
@@ -270,7 +272,7 @@ def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
os.makedirs(target_corpus_dir, exist_ok=True)
use_value_profile = int(random.random() < .3)
command = [
- os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
+ fuzz_bin,
"-rss_limit_mb=8000",
"-max_total_time=6000",
"-reload=0",
@@ -283,12 +285,12 @@ def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
future.result()
-def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dirs):
+def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, fuzz_bin, merge_dirs):
logging.info(f"Merge the inputs from the passed dir into the corpus_dir. Passed dirs {merge_dirs}")
jobs = []
for t in test_list:
args = [
- os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
+ fuzz_bin,
'-rss_limit_mb=8000',
'-set_cover_merge=1',
# set_cover_merge is used instead of -merge=1 to reduce the overall
@@ -325,13 +327,13 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dirs
future.result()
-def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, using_libfuzzer, use_valgrind, empty_min_time):
+def run_once(*, fuzz_pool, corpus, test_list, src_dir, fuzz_bin, using_libfuzzer, use_valgrind, empty_min_time):
jobs = []
for t in test_list:
corpus_path = corpus / t
os.makedirs(corpus_path, exist_ok=True)
args = [
- os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
+ fuzz_bin,
]
empty_dir = not any(corpus_path.iterdir())
if using_libfuzzer: