From f8c77960a35081786b3202cba774666e3a1f8600 Mon Sep 17 00:00:00 2001 From: Alexander Wiederin Date: Tue, 14 Jul 2026 13:36:00 +0200 Subject: [PATCH 1/6] Squashed 'libbitcoinkernel-sys/bitcoin/' changes from 81405fc7abb..114e48e968a 114e48e968a kernel: Add script tracer 54e1a95a12e Merge bitcoin/bitcoin#35719: ci: disable Qt build in OpenBSD cross job b0e09511586 ci: disable Qt build in OpenBSD cross job 734c34bafda Merge bitcoin/bitcoin#35427: depends: Build `qt` and `qrencode` packages on OpenBSD ee61b11a9e7 Merge bitcoin/bitcoin#35200: node: smooth oversized `dbcache` warnings e3554bf361f Merge bitcoin/bitcoin#35579: wallet: reserve walletrescan before checking wallet is at the tip 11ae4265522 Merge bitcoin/bitcoin#35715: cmake: Fix WITH_EXTERNAL_LIBMULTIPROCESS + BUILD_FUZZ_BINARY e544413c0de Merge bitcoin/bitcoin#32763: wallet: Replace CWalletTx::mapValue and vOrderForm with explicit class members fe1cb6e40d7 Merge bitcoin/bitcoin#35690: wallet: Introduce WalletError with machine-readable error code 441f3114f57 Merge bitcoin/bitcoin#35659: Clarify supported *BSD releases and drop outdated workarounds 0399df827c6 Merge bitcoin/bitcoin#35708: depends: capnp 1.5.0 1ab1fdd4696 Merge bitcoin/bitcoin#35705: bench: replace CreateMockableWalletDatabase with MakeInMemoryWalletDatabase db35b9238fc ipc # build: Fix fuzz target CMakeLists.txt for external libmultiprocess d18fec892e2 Merge bitcoin/bitcoin#35698: doc: Update enum class constant naming style guide a2e4cd7ad2a depends: capnp 1.5.0 7508ac319d9 bench: replace CreateMockableWalletDatabase with MakeInMemoryWalletDatabase 907e284e303 Merge bitcoin/bitcoin#35701: test: Remove `mock_process.cpp` c8459b6bdcd Merge bitcoin/bitcoin#35568: txospenderindex: disable bloom filters to optimize disk usage 63c5f9d22c0 test: Remove `mock_process.cpp` ef101b04a8d Merge bitcoin/bitcoin#35655: wallet: Use in-memory SQLite for temporary wallet in exportwatchonlywallet b6becf3534c Merge bitcoin/bitcoin#35684: Update libmultiprocess subtree to add `max_connections` option 930f25050f7 Merge bitcoin/bitcoin#35700: doc: archive release notes for v29.4 9b2b3f4ec6f doc: archive release notes for v29.4 297fd1489bb Merge bitcoin/bitcoin#35412: ci: add NetBSD Clang cross job e314869066b Merge bitcoin/bitcoin#35695: Remove myself as security contact e3d67a5eae5 Merge bitcoin/bitcoin#35691: chainparams: delete my DNS seed a8223bb4e62 wallet: Introduce WalletError with machine-readable error code fad5809cb92 doc: Update enum class constant naming style guide 7d8137c1417 Merge bitcoin/bitcoin#34897: indexes: Don't commit ahead of the flushed chainstate 629df81e4c6 Remove myself as security contact d164a043426 node: smooth oversized `-dbcache` warnings d9080639804 chainparams: delete my DNS seed e9ed898a0da validation: Don't use m_chain.Tip() in FlushStateToDisk 3679f1ecf5e index: Don't commit ahead of the flushed chainstate 65735728a5a index: Remove return value from Commit() 09c06960c6a validation: track last flushed block 13c02b5466d test: add test for index commits ahead of the last flushed block c43b7a1115f ci: add netBSD cross CI job 699c21aea47 depends: add netbsd_LDFLAGS 777d23f25c7 test: add regression test for in-memory SQLiteDatabase reopen d1e7f8c986f wallet: use in-memory SQLite for temporary wallet in exportwatchonlywallet ee43743f126 wallet: store m_additional_flags in SQLiteDatabase to fix reopen path a9d1b652f32 Merge commit '707d0ded84563386f770ec17970834c65f8fa938' into pr/subtree-12 707d0ded845 Squashed 'src/ipc/libmultiprocess/' changes from 16bf05dea02..28e056576a3 2bab6bc73f2 refactor: Drop support for FreeBSD < 14 91b5c8a07c6 refactor: Remove FreeBSD-specific workaround 56701ff6d5c doc: Clarify supported *BSD releases 6d0ea4cf5bd doc: add release notes a2b1c86903a txospenderindex: disable bloom filters to optimize disk usage fed3cf6f0ed wallet: Replace CWalletTx's vOrderForm with specific fields 4f8823e8e11 wallet: Drop vOrderForm from CommitTransaction 9e62e4b1f34 test: slow down rescaning process a2b0bfcd854 wallet: Drop mapValue from CWalletTx cb99864c91c wallet: Throw if unknown entry is found in mapValue 98d5cdae663 wallet: Make CWalletTx "replaces_txid" and "replaced_by_txid" member variables 7ef8a6efc2a wallet: Make CWalletTx "comment" and "to" member variables 2155e913d3e wallet: Make CWalletTx "from" and "message" member variables c6ba98dcc8a wallet: Drop mapValue from CommitTransaction 00abb174a80 wallet: Pass comment and comment_to to CommitTransaction 1a219a37a21 wallet: Pass replaces_txid to CommitTransaction outside of mapValue 336f5a738b3 wallet: reserve walletrescan before checking wallet is at the tip a54ec373a69 depends: Build `qt` and `qrencode` packages for OpenBSD hosts git-subtree-dir: libbitcoinkernel-sys/bitcoin git-subtree-split: 114e48e968a087f74c1ab611ac2a31a9266812e1 --- .github/workflows/ci.yml | 6 + SECURITY.md | 1 - ci/test/00_setup_env_netbsd_cross.sh | 35 +++ ci/test/00_setup_env_openbsd_cross.sh | 2 +- ci/test/01_base_install.sh | 11 + contrib/seeds/README.md | 3 +- depends/README.md | 4 + depends/hosts/netbsd.mk | 1 + depends/packages/freetype.mk | 4 +- depends/packages/native_capnp.mk | 4 +- depends/packages/packages.mk | 2 + depends/packages/qt.mk | 10 +- .../patches/freetype/openbsd_versioning.patch | 31 ++ .../qt/fix_openbsd_network_kernel.patch | 31 ++ .../qt/fix_openbsd_plugin_qelfparser.patch | 20 ++ depends/toolchain.cmake.in | 2 +- doc/build-freebsd.md | 4 +- doc/build-netbsd.md | 4 +- doc/build-openbsd.md | 4 +- doc/developer-notes.md | 6 +- doc/release-notes-35634.md | 9 +- doc/release-notes/release-notes-29.4.md | 107 +++++++ src/bench/coin_selection.cpp | 4 +- src/bench/wallet_balance.cpp | 3 +- src/bench/wallet_create_tx.cpp | 7 +- src/bench/wallet_encrypt.cpp | 3 +- src/bench/wallet_ismine.cpp | 3 +- src/common/netif.cpp | 11 +- src/dbwrapper.cpp | 6 +- src/dbwrapper.h | 2 + src/index/base.cpp | 18 +- src/index/base.h | 14 +- src/index/txospenderindex.cpp | 2 +- src/interfaces/wallet.h | 15 +- src/ipc/libmultiprocess/doc/usage.md | 2 +- src/ipc/libmultiprocess/doc/versions.md | 18 +- src/ipc/libmultiprocess/include/mp/proxy-io.h | 68 +++- src/ipc/libmultiprocess/include/mp/version.h | 2 +- src/ipc/libmultiprocess/test/CMakeLists.txt | 1 + .../test/mp/test/listen_tests.cpp | 294 ++++++++++++++++++ src/ipc/test/fuzz/CMakeLists.txt | 2 +- src/kernel/CMakeLists.txt | 6 + src/kernel/bitcoinkernel.cpp | 71 ++++- src/kernel/bitcoinkernel.h | 82 +++++ src/kernel/bitcoinkernel_wrapper.h | 79 +++++ src/kernel/chainparams.cpp | 1 - src/node/caches.h | 6 +- src/qt/CMakeLists.txt | 2 +- src/qt/transactiondesc.cpp | 60 ++-- src/qt/transactionrecord.cpp | 5 +- src/qt/walletmodel.cpp | 9 +- src/script/interpreter.cpp | 9 +- src/script/trace.cpp | 40 +++ src/script/trace.h | 119 +++++++ src/test/CMakeLists.txt | 4 +- src/test/baseindex_tests.cpp | 62 ++++ src/test/caches_tests.cpp | 46 ++- src/test/chainstate_write_tests.cpp | 2 + src/test/fuzz/dbwrapper.cpp | 1 + src/test/kernel/CMakeLists.txt | 4 + src/test/kernel/test_kernel.cpp | 50 +++ src/test/mock_process.cpp | 40 --- src/test/system_tests.cpp | 64 +++- src/validation.cpp | 5 +- src/validation.h | 4 + src/wallet/export.cpp | 32 +- src/wallet/feebumper.cpp | 9 +- src/wallet/interfaces.cpp | 19 +- src/wallet/rpc/backup.cpp | 8 +- src/wallet/rpc/spend.cpp | 21 +- src/wallet/rpc/transactions.cpp | 6 +- src/wallet/spend.cpp | 4 +- src/wallet/sqlite.cpp | 21 +- src/wallet/sqlite.h | 15 + src/wallet/test/db_tests.cpp | 9 + src/wallet/test/util.cpp | 2 +- src/wallet/test/util.h | 3 +- src/wallet/test/wallet_tests.cpp | 2 +- src/wallet/transaction.h | 106 ++++--- src/wallet/types.h | 28 ++ src/wallet/wallet.cpp | 32 +- src/wallet/wallet.h | 15 +- test/functional/wallet_importdescriptors.py | 3 + test/lint/lint-includes.py | 1 - 84 files changed, 1537 insertions(+), 346 deletions(-) create mode 100755 ci/test/00_setup_env_netbsd_cross.sh create mode 100644 depends/patches/freetype/openbsd_versioning.patch create mode 100644 depends/patches/qt/fix_openbsd_network_kernel.patch create mode 100644 depends/patches/qt/fix_openbsd_plugin_qelfparser.patch create mode 100644 doc/release-notes/release-notes-29.4.md create mode 100644 src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp create mode 100644 src/script/trace.cpp create mode 100644 src/script/trace.h create mode 100644 src/test/baseindex_tests.cpp delete mode 100644 src/test/mock_process.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34dd688e..bce9c603 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -463,6 +463,12 @@ jobs: timeout-minutes: 120 file-env: './ci/test/00_setup_env_mac_cross_intel.sh' + - name: 'NetBSD Cross' + warp-runner: 'warp-ubuntu-latest-x64-8x' + fallback-runner: 'ubuntu-latest' + timeout-minutes: 120 + file-env: './ci/test/00_setup_env_netbsd_cross.sh' + - name: 'FreeBSD Cross' warp-runner: 'warp-ubuntu-latest-x64-8x' fallback-runner: 'ubuntu-latest' diff --git a/SECURITY.md b/SECURITY.md index 5a63a762..17dedcd7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,7 +13,6 @@ The following keys may be used to communicate sensitive information to developer | Name | Fingerprint | |------|-------------| -| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | | Michael Ford | E777 299F C265 DD04 7930 70EB 944D 35F9 AC3D B76A | | Ava Chow | 1528 1230 0785 C964 44D3 334D 1756 5732 E08E 5E41 | | Niklas Gögge | 2CBB F208 E594 BF43 9B5F 276C 7465 CFFF 6793 242E | diff --git a/ci/test/00_setup_env_netbsd_cross.sh b/ci/test/00_setup_env_netbsd_cross.sh new file mode 100755 index 00000000..9fb4c18a --- /dev/null +++ b/ci/test/00_setup_env_netbsd_cross.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# +# Copyright (c) The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit. + +export LC_ALL=C.UTF-8 + +export CONTAINER_NAME=ci_netbsd_cross +export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:26.04" +export APT_LLVM_V="22" +export HOST=x86_64-unknown-netbsd +export NETBSD_VERSION=11.0_RC6 +export NETBSD_SDK_BASENAME="netbsd-${HOST}-${NETBSD_VERSION}" +export PACKAGES="clang-${APT_LLVM_V} llvm-${APT_LLVM_V} lld-${APT_LLVM_V}" +export SYSROOT="--sysroot=${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" +export DEP_OPTS="build_CC=clang build_CXX=clang++ \ + CC='clang --target=${HOST} ${SYSROOT}' \ + CXX='clang++ --target=${HOST} ${SYSROOT} -stdlib=libstdc++' \ + LDFLAGS='-fuse-ld=lld -lgcc_s' \ + AR=llvm-ar-${APT_LLVM_V} \ + NM=llvm-nm-${APT_LLVM_V} \ + OBJCOPY=llvm-objcopy-${APT_LLVM_V} \ + OBJDUMP=llvm-objdump-${APT_LLVM_V} \ + RANLIB=llvm-ranlib-${APT_LLVM_V} \ + STRIP=llvm-strip-${APT_LLVM_V}" +export GOAL="install" +export BITCOIN_CONFIG="\ + --preset=dev-mode \ + -DBUILD_GUI=OFF \ + -DREDUCE_EXPORTS=ON \ + -DWITH_USDT=OFF \ +" +export RUN_UNIT_TESTS=false +export RUN_FUNCTIONAL_TESTS=false diff --git a/ci/test/00_setup_env_openbsd_cross.sh b/ci/test/00_setup_env_openbsd_cross.sh index 30d36213..1732aef3 100755 --- a/ci/test/00_setup_env_openbsd_cross.sh +++ b/ci/test/00_setup_env_openbsd_cross.sh @@ -14,7 +14,7 @@ export OPENBSD_VERSION=7.9 export OPENBSD_SDK_BASENAME="openbsd-${HOST}-${OPENBSD_VERSION}" export PACKAGES="clang-${APT_LLVM_V} llvm-${APT_LLVM_V} lld-${APT_LLVM_V}" export SYSROOT="--sysroot=${DEPENDS_DIR}/SDKs/${OPENBSD_SDK_BASENAME}" -export DEP_OPTS="build_CC=clang build_CXX=clang++ \ +export DEP_OPTS="NO_QT=1 build_CC=clang build_CXX=clang++ \ CC='clang --target=${HOST} ${SYSROOT}' \ CXX='clang++ --target=${HOST} ${SYSROOT} -stdlib=libc++' \ LDFLAGS='-fuse-ld=lld' \ diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh index 652416b9..f619a088 100755 --- a/ci/test/01_base_install.sh +++ b/ci/test/01_base_install.sh @@ -118,6 +118,17 @@ if [ -n "$XCODE_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${OSX_SDK_BASENAME}" ] tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH" fi +if [ -n "$NETBSD_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" ]; then + mkdir -p "${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" + for NETBSD_SDK_FILENAME in base.tar.xz comp.tar.xz; do + NETBSD_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${NETBSD_SDK_FILENAME}" + if [ ! -f "$NETBSD_SDK_PATH" ]; then + ${CI_RETRY_EXE} curl --location --fail "https://cdn.netbsd.org/pub/NetBSD/NetBSD-${NETBSD_VERSION}/amd64/binary/sets/${NETBSD_SDK_FILENAME}" -o "$NETBSD_SDK_PATH" + fi + tar -C "${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" -xf "$NETBSD_SDK_PATH" + done +fi + if [ -n "$FREEBSD_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${FREEBSD_SDK_BASENAME}" ]; then FREEBSD_SDK_FILENAME="base-${FREEBSD_VERSION}.txz" FREEBSD_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${FREEBSD_SDK_FILENAME}" diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md index 2eb68467..388ddd54 100644 --- a/contrib/seeds/README.md +++ b/contrib/seeds/README.md @@ -15,8 +15,7 @@ DNS seed, virtu's crawler, and asmap community AS map data. Run the following co from the `/contrib/seeds` directory: ``` -curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt -curl https://21.ninja/seeds.txt.gz | gzip -dc >> seeds_main.txt +curl https://21.ninja/seeds.txt.gz | gzip -dc > seeds_main.txt curl https://mainnet.achownodes.xyz/seeds.txt.gz | gzip -dc >> seeds_main.txt curl https://signet.achownodes.xyz/seeds.txt.gz | gzip -dc > seeds_signet.txt curl https://testnet.achownodes.xyz/seeds.txt.gz | gzip -dc > seeds_test.txt diff --git a/depends/README.md b/depends/README.md index b7d7d226..83ebf8e2 100644 --- a/depends/README.md +++ b/depends/README.md @@ -53,6 +53,10 @@ To build dependencies for the current arch+OS: pkg_add bash cmake curl gmake gtar +Skip the following packages if you don't intend to use the GUI and will build with [`NO_QT=1`](#dependency-options): + + pkg_add bison ninja + To build dependencies for the current arch+OS: gmake diff --git a/depends/hosts/netbsd.mk b/depends/hosts/netbsd.mk index 0e1256c3..df7a5ea9 100644 --- a/depends/hosts/netbsd.mk +++ b/depends/hosts/netbsd.mk @@ -1,5 +1,6 @@ netbsd_CFLAGS= netbsd_CXXFLAGS= +netbsd_LDFLAGS= ifneq ($(LTO),) netbsd_AR = $(host_toolchain)gcc-ar diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index b34edc60..74d5e42a 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -5,6 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=f8db94d307e9c54961b39a1cc799a67d46681480696ed72ecf78d4473770f09b $(package)_build_subdir=build $(package)_patches += cmake_minimum.patch +$(package)_patches += openbsd_versioning.patch define $(package)_set_vars $(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DBUILD_SHARED_LIBS=TRUE @@ -14,7 +15,8 @@ define $(package)_set_vars endef define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch + patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch && \ + patch -p1 < $($(package)_patch_dir)/openbsd_versioning.patch endef define $(package)_config_cmds diff --git a/depends/packages/native_capnp.mk b/depends/packages/native_capnp.mk index d65a8b97..f207421d 100644 --- a/depends/packages/native_capnp.mk +++ b/depends/packages/native_capnp.mk @@ -1,9 +1,9 @@ package=native_capnp -$(package)_version=1.4.0 +$(package)_version=1.5.0 $(package)_download_path=https://capnproto.org/ $(package)_download_file=capnproto-c++-$($(package)_version).tar.gz $(package)_file_name=capnproto-cxx-$($(package)_version).tar.gz -$(package)_sha256_hash=fa02378ad522b318916b9ad928d1372fc9abd43dd1f4f0392e50450f5c87828f +$(package)_sha256_hash=77dbc13ca82d9c87ddb4581dd49559d45b63096433d3dadea08b7f31b360a5ba define $(package)_set_vars $(package)_config_opts := -DBUILD_TESTING=OFF diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index a5384331..f50b45d0 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -4,11 +4,13 @@ boost_packages = boost qrencode_linux_packages = qrencode qrencode_freebsd_packages = qrencode +qrencode_openbsd_packages = qrencode qrencode_darwin_packages = qrencode qrencode_mingw32_packages = qrencode qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon libxcb_util libxcb_util_cursor libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm qt_freebsd_packages:=$(qt_linux_packages) +qt_openbsd_packages:=$(qt_linux_packages) qt_darwin_packages=qt qt_mingw32_packages=qt ifneq ($(host),$(build)) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 9b7cec34..500a2729 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -9,6 +9,7 @@ $(package)_dependencies := native_$(package) endif $(package)_linux_dependencies := freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_cursor libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm $(package)_freebsd_dependencies := $($(package)_linux_dependencies) +$(package)_openbsd_dependencies := $($(package)_linux_dependencies) $(package)_patches_path := $(qt_details_patches_path) $(package)_patches := cocoa_compat.patch $(package)_patches += dont_hardcode_pwd.patch @@ -26,6 +27,8 @@ $(package)_patches += fix-gcc16-sfinae-qbitarray.patch $(package)_patches += fix-gcc16-sfinae-qanystringview.patch $(package)_patches += fix-macos26-qyield.patch $(package)_patches += fix-qbytearray-include.patch +$(package)_patches += fix_openbsd_network_kernel.patch +$(package)_patches += fix_openbsd_plugin_qelfparser.patch $(package)_qttranslations_file_name=$(qt_details_qttranslations_file_name) $(package)_qttranslations_sha256_hash=$(qt_details_qttranslations_sha256_hash) @@ -158,6 +161,7 @@ $(package)_config_opts_linux += -ltcg endif $(package)_config_opts_freebsd := $$($(package)_config_opts_linux) $(package)_config_opts_freebsd += -no-feature-inotify +$(package)_config_opts_openbsd := $$($(package)_config_opts_linux) $(package)_config_opts_mingw32 := -no-dbus $(package)_config_opts_mingw32 += -no-feature-freetype @@ -208,7 +212,7 @@ $(package)_cmake_opts += -DCMAKE_DISABLE_FIND_PACKAGE_WrapSystemDoubleConversion $(package)_cmake_opts += -DCMAKE_DISABLE_FIND_PACKAGE_WrapSystemMd4c=TRUE $(package)_cmake_opts += -DCMAKE_DISABLE_FIND_PACKAGE_WrapZSTD=TRUE endif -ifeq ($(host_os),linux) +ifneq (,$(filter linux openbsd,$(host_os))) # The `-dbus-runtime` configure option does not work # https://qt-project.atlassian.net/browse/QTBUG-144864 $(package)_cmake_opts += -DINPUT_dbus=runtime @@ -284,7 +288,9 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix-gcc16-sfinae-qbitarray.patch && \ patch -p1 -i $($(package)_patch_dir)/fix-gcc16-sfinae-qanystringview.patch && \ patch -p1 -i $($(package)_patch_dir)/fix-macos26-qyield.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix-qbytearray-include.patch + patch -p1 -i $($(package)_patch_dir)/fix-qbytearray-include.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_openbsd_network_kernel.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_openbsd_plugin_qelfparser.patch endef ifeq ($(host),$(build)) $(package)_preprocess_cmds += && patch -p1 -i $($(package)_patch_dir)/qttools_skip_dependencies.patch diff --git a/depends/patches/freetype/openbsd_versioning.patch b/depends/patches/freetype/openbsd_versioning.patch new file mode 100644 index 00000000..ea5cffef --- /dev/null +++ b/depends/patches/freetype/openbsd_versioning.patch @@ -0,0 +1,31 @@ +[cmake] Fix shared library versioning on OpenBSD. + +This emulates Libtool to make sure Libtool and CMake agree on the ABI +version. Specifically, for OpenBSD, `builds/unix/configure` defines +`version_type=sunos` and skips defining `soname_spec`. + +See upstream MR: https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/433. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -458,9 +458,17 @@ if (WIN32) + endif () + + if (BUILD_SHARED_LIBS) +- set_target_properties(freetype PROPERTIES +- VERSION ${LIBRARY_VERSION} +- SOVERSION ${LIBRARY_SOVERSION}) ++ if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") ++ # For OpenBSD, libtool follows `sunos` version type. ++ set_target_properties(freetype PROPERTIES ++ # libtool does not define its internal `soname_spec` variable ++ # for OpenBSD. So skipping the SOVERSION option. ++ VERSION ${LIBTOOL_CURRENT}.${LIBTOOL_REVISION}) ++ else () ++ set_target_properties(freetype PROPERTIES ++ VERSION ${LIBRARY_VERSION} ++ SOVERSION ${LIBRARY_SOVERSION}) ++ endif () + endif () + + # Pick up ftconfig.h and ftoption.h generated above, first. diff --git a/depends/patches/qt/fix_openbsd_network_kernel.patch b/depends/patches/qt/fix_openbsd_network_kernel.patch new file mode 100644 index 00000000..2a5a4ac2 --- /dev/null +++ b/depends/patches/qt/fix_openbsd_network_kernel.patch @@ -0,0 +1,31 @@ +Fix compiling on OpenBSD + +1. The `net/if_types.h` header does not define the `IFT_STF` symbol. +2. The `netinet6/in6_var.h` header defines some of the used symbols. + +For the reference, see: + - https://codeberg.org/OpenBSD/ports/src/commit/f8f1aedbe8aff550c69930b5d92b9c392e298382/x11/qt6/qtbase/patches/patch-src_network_kernel_qnetworkinterface_unix_cpp + + +--- a/qtbase/src/network/kernel/qnetworkinterface_unix.cpp ++++ b/qtbase/src/network/kernel/qnetworkinterface_unix.cpp +@@ -392,6 +392,9 @@ QT_BEGIN_INCLUDE_NAMESPACE + # include + # include + # include ++# ifdef Q_OS_OPENBSD ++# include ++# endif + #endif // QT_PLATFORM_UIKIT + QT_END_INCLUDE_NAMESPACE + +@@ -419,7 +422,9 @@ static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, stru + return QNetworkInterface::Ieee1394; + + case IFT_GIF: ++#ifndef Q_OS_OPENBSD + case IFT_STF: ++#endif + return QNetworkInterface::Virtual; + } + diff --git a/depends/patches/qt/fix_openbsd_plugin_qelfparser.patch b/depends/patches/qt/fix_openbsd_plugin_qelfparser.patch new file mode 100644 index 00000000..1b32e45f --- /dev/null +++ b/depends/patches/qt/fix_openbsd_plugin_qelfparser.patch @@ -0,0 +1,20 @@ +Fix compiling on OpenBSD + +Avoid use of undeclared identifier `ELFOSABI_AIX`. + +For the reference, see: + - https://codeberg.org/OpenBSD/ports/src/commit/c5e4088b89277b96d840492f9961b1593182b99c/x11/qt6/qtbase/patches/patch-src_corelib_plugin_qelfparser_p_cpp + + +--- a/qtbase/src/corelib/plugin/qelfparser_p.cpp ++++ b/qtbase/src/corelib/plugin/qelfparser_p.cpp +@@ -341,7 +341,9 @@ Q_DECL_UNUSED Q_DECL_COLD_FUNCTION static QDebug &operator<<(QDebug &d, ElfHeade + case ELFOSABI_NETBSD: d << " (NetBSD"; break; + case ELFOSABI_LINUX: d << " (GNU/Linux"; break; + case ELFOSABI_SOLARIS: d << " (Solaris"; break; ++#ifndef Q_OS_OPENBSD + case ELFOSABI_AIX: d << " (AIX"; break; ++#endif + case ELFOSABI_IRIX: d << " (IRIX"; break; + case ELFOSABI_FREEBSD: d << " (FreeBSD"; break; + case ELFOSABI_OPENBSD: d << " (OpenBSD"; break; diff --git a/depends/toolchain.cmake.in b/depends/toolchain.cmake.in index 87189efa..9d9f9e49 100644 --- a/depends/toolchain.cmake.in +++ b/depends/toolchain.cmake.in @@ -117,7 +117,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_HOST_APPLE) endif() -if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$") +if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD|OpenBSD)$") # Customize pkg-config behavior for finding dependencies # of the xcb QPA platform plugin: # 1. Restrict search paths to the depends. diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index 436b57c9..ffb8ecfe 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -1,8 +1,8 @@ # FreeBSD Build Guide -**Updated for FreeBSD [15.0](https://www.freebsd.org/releases/15.0R/announce/)** +Bitcoin Core is supported on all [supported FreeBSD releases](https://www.freebsd.org/security/#sup). -This guide describes how to build bitcoind, command-line utilities, and GUI on FreeBSD. +This guide describes how to build bitcoind, command-line utilities, and GUI on the most recent production release. ## Preparation diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index c269d2a1..d4d031d3 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -1,8 +1,8 @@ # NetBSD Build Guide -**Updated for NetBSD [10.1](https://netbsd.org/releases/formal-10/NetBSD-10.1.html)** +Bitcoin Core is supported on all [supported NetBSD releases](https://www.netbsd.org/releases/). -This guide describes how to build bitcoind, command-line utilities, and GUI on NetBSD. +This guide describes how to build bitcoind, command-line utilities, and GUI on the latest release. ## Preparation diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index d64fd909..bcc2eba6 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -1,8 +1,8 @@ # OpenBSD Build Guide -**Updated for OpenBSD [7.8](https://www.openbsd.org/78.html)** +Bitcoin Core is supported on [the two most recent OpenBSD releases](https://www.openbsd.org/faq/faq5.html#Flavors). -This guide describes how to build bitcoind, command-line utilities, and GUI on OpenBSD. +This guide describes how to build bitcoind, command-line utilities, and GUI on the latest release. ## Preparation diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 3edf5d34..0bc1bd25 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -40,10 +40,10 @@ code. - Class member variables have a `m_` prefix. - Global variables have a `g_` prefix. - Constant names are all uppercase, and use `_` to separate words. - - Enumerator constants may be `snake_case`, `PascalCase` or `ALL_CAPS`. - This is a more tolerant policy than the [C++ Core + - Enumerator constants may be `snake_case`, or `PascalCase`. They should not + be `ALL_CAPS`, according to the [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#renum-caps), - which recommend using `snake_case`. Please use what seems appropriate. + to avoid clashing with macros. - Class names, function names, and method names are UpperCamelCase (PascalCase). Do not prefix class names with `C`. See [Internal interface naming style](#internal-interface-naming-style) for an exception to this diff --git a/doc/release-notes-35634.md b/doc/release-notes-35634.md index ccbd7fd7..2398305b 100644 --- a/doc/release-notes-35634.md +++ b/doc/release-notes-35634.md @@ -1,9 +1,8 @@ Indexes ------- -- The transaction output spender index (`-txospenderindex`) now stores one byte - less per spender entry for newly indexed blocks. Existing indexes remain - compatible and no action is required. To apply the same saving to entries - indexed before upgrading, stop the node, delete the +- The transaction output spender index (`-txospenderindex`) now uses less disk + space. Existing indexes remain compatible and no action is required. To reclaim + the space for data indexed before upgrading, stop the node, delete the `/indexes/txospenderindex/` directory, and restart with - `-txospenderindex` enabled to rebuild it. + `-txospenderindex` enabled to rebuild it. (#35634, #35568) diff --git a/doc/release-notes/release-notes-29.4.md b/doc/release-notes/release-notes-29.4.md new file mode 100644 index 00000000..3ff905db --- /dev/null +++ b/doc/release-notes/release-notes-29.4.md @@ -0,0 +1,107 @@ +Bitcoin Core version 29.4 is now available from: + + + +This release includes various bug fixes and performance +improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + + +To receive security and update notifications, please subscribe to: + + + +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 tested on operating systems using the +Linux Kernel 3.17+, macOS 13+, and Windows 10+. 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 +=============== + +This release fixes an issue where the chainstate database would repeatedly +rewrite large portions of itself, causing excessive disk reads and writes +during normal operation. + +### Validation + +- #35209 validation: correct lifetime of precomputed tx data +- #35465 coins: compact chainstate regularly + +### Leveldb + +- #61(bitcoin-core/leveldb): Disable seek compaction + +### Net + +- #34093 netif: fix compilation warning in QueryDefaultGatewayImpl() + +### Wallet + +- #35228 wallet: use outpoint when estimating input size + +### Build + +- #34228 depends: Unset SOURCE_DATE_EPOCH in gen_id script +- #34848 cmake: Migrate away from deprecated SQLite3 target + +### Test + +- #34918 fuzz: [refactor] Remove unused g_setup pointers + +### Doc + +- #34510 doc: fix broken bpftrace installation link +- #34561 wallet: rpc: manpage: fix example missing `fee_rate` argument +- #34671 doc: Update Guix install for Debian/Ubuntu +- #35283 doc: mention -DWITH_ZMQ=ON in BSD build guides + +### CI + +- #35202 ci: restore sockets in i686, no IPC job +- #35378 ci: switch runners from cirrus to warpbuild +- #35408 ci: 35378 followups + +### Misc + +- #35175 multi_index: fix compilation failure with boost >= 1.91 + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- andrewtoth +- Cory Fields +- Daniel Pfeifer +- darosior +- fanquake +- Hennadii Stepanov +- jayvaliya +- junbyjun1238 +- Lőrinc +- MarcoFalke +- SomberNight +- ToRyVand +- willcl-ark + +As well as to everyone that helped with translations on +[Transifex](https://explore.transifex.com/bitcoin/bitcoin/). diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 4f203fe8..5c54cafc 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -50,7 +50,7 @@ static void addCoin(const CAmount& nValue, std::vector(); - CWallet wallet(test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()); + CWallet wallet(test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()); std::vector> wtxs; LOCK(wallet.cs_wallet); diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp index 958044e2..76d0fd39 100644 --- a/src/bench/wallet_balance.cpp +++ b/src/bench/wallet_balance.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process. // The reason is 'generatetoaddress', which creates a chain with deterministic timestamps in the past. FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()}; - CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()}; + CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()}; { LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp index 394f21ce..b0140910 100644 --- a/src/bench/wallet_create_tx.cpp +++ b/src/bench/wallet_create_tx.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ using kernel::ChainstateRole; using wallet::CWallet; -using wallet::CreateMockableWalletDatabase; +using wallet::MakeInMemoryWalletDatabase; using wallet::WALLET_FLAG_DESCRIPTORS; struct TipBlock @@ -120,7 +121,7 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process. FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()}; - CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()}; + CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()}; { LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); @@ -175,7 +176,7 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector(); // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process. FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()}; - CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()}; + CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()}; { LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); diff --git a/src/bench/wallet_encrypt.cpp b/src/bench/wallet_encrypt.cpp index 81e64a28..7f6ff3af 100644 --- a/src/bench/wallet_encrypt.cpp +++ b/src/bench/wallet_encrypt.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ static void WalletEncrypt(benchmark::Bench& bench, unsigned int key_count) TestUnloadWallet(std::move(wallet)); } - std::unique_ptr database = CreateMockableWalletDatabase(); + std::unique_ptr database = MakeInMemoryWalletDatabase(); wallet = TestCreateWallet(std::move(database), context, create_flags); { diff --git a/src/bench/wallet_ismine.cpp b/src/bench/wallet_ismine.cpp index 572a2717..4b059b34 100644 --- a/src/bench/wallet_ismine.cpp +++ b/src/bench/wallet_ismine.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ static void WalletIsMine(benchmark::Bench& bench, int num_combo = 0) // Setup the wallet // Loading the wallet will also create it uint64_t create_flags = WALLET_FLAG_DESCRIPTORS; - auto database = CreateMockableWalletDatabase(); + auto database = MakeInMemoryWalletDatabase(); auto wallet = TestCreateWallet(std::move(database), context, create_flags); // For a descriptor wallet, fill with num_combo combo descriptors with random keys diff --git a/src/common/netif.cpp b/src/common/netif.cpp index a30046c7..997db7d5 100644 --- a/src/common/netif.cpp +++ b/src/common/netif.cpp @@ -14,13 +14,8 @@ #if defined(__linux__) #include #elif defined(__FreeBSD__) -#include -#if __FreeBSD_version >= 1400000 -// Workaround https://github.com/freebsd/freebsd-src/pull/1070. -#define typeof __typeof #include #include -#endif #elif defined(WIN32) #include #elif defined(__APPLE__) @@ -60,10 +55,8 @@ std::optional FromSockAddr(const struct sockaddr* addr, std::optional< return std::nullopt; } -// Linux and FreeBSD 14.0+. For FreeBSD 13.2 the code can be compiled but -// running it requires loading a special kernel module, otherwise socket(AF_NETLINK,...) -// will fail, so we skip that. -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1400000) +// Linux and FreeBSD. +#if defined(__linux__) || defined(__FreeBSD__) // Good for responses containing ~ 10,000-15,000 routes. static constexpr ssize_t NETLINK_MAX_RESPONSE_SIZE{1'048'576}; diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index ffe6f267..ed914273 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -136,12 +136,12 @@ static void SetMaxOpenFiles(leveldb::Options *options) { options->max_open_files, default_open_files); } -static leveldb::Options GetOptions(size_t nCacheSize) +static leveldb::Options GetOptions(size_t nCacheSize, bool bloom_filter) { leveldb::Options options; options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously - options.filter_policy = leveldb::NewBloomFilterPolicy(10); + options.filter_policy = bloom_filter ? leveldb::NewBloomFilterPolicy(10) : nullptr; options.compression = leveldb::kNoCompression; options.info_log = new CBitcoinLevelDBLogger(); if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { @@ -225,7 +225,7 @@ CDBWrapper::CDBWrapper(const DBParams& params) DBContext().iteroptions.verify_checksums = true; DBContext().iteroptions.fill_cache = false; DBContext().syncoptions.sync = true; - DBContext().options = GetOptions(params.cache_bytes); + DBContext().options = GetOptions(params.cache_bytes, params.bloom_filter); DBContext().options.create_if_missing = true; DBContext().options.max_file_size = params.max_file_size; assert(!(params.testing_env && params.memory_only)); diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 2c1f8039..1eb68a3b 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -50,6 +50,8 @@ struct DBParams { //! If true, store data obfuscated via simple XOR. If false, XOR with a //! zero'd byte array. bool obfuscate = false; + //! If true, build a LevelDB bloom filter to accelerate point lookups. + bool bloom_filter = true; //! Passed-through options. DBOptions options{}; //! If non-null, use this as the leveldb::Env instead of the default. diff --git a/src/index/base.cpp b/src/index/base.cpp index 906ed265..5820448b 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -65,13 +65,14 @@ CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash) return locator; } -BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) : +BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate, bool f_bloom) : CDBWrapper{DBParams{ .path = path, .cache_bytes = n_cache_size, .memory_only = f_memory, .wipe_data = f_wipe, .obfuscate = f_obfuscate, + .bloom_filter = f_bloom, .options = [] { DBOptions options; node::ReadDatabaseArgs(gArgs, options); return options; }()}} {} @@ -273,12 +274,23 @@ void BaseIndex::Sync() } } -bool BaseIndex::Commit() +void BaseIndex::Commit() { // Don't commit anything if we haven't indexed any block yet // (this could happen if init is interrupted). bool ok = m_best_block_index != nullptr; if (ok) { + // Don't commit if the index best block is not an ancestor of the chainstate's last flushed + // block. Otherwise, after an unclean shutdown, the index could be + // persisted ahead of a chainstate it can no longer roll back to, which + // would corrupt indexes with state (e.g. coinstatsindex). + const CBlockIndex* index_tip = m_best_block_index.load(); + const CBlockIndex* last_flushed = WITH_LOCK(::cs_main, return m_chainstate->GetLastFlushedBlock()); + if (!last_flushed || last_flushed->GetAncestor(index_tip->nHeight) != index_tip) { + LogDebug(BCLog::COINDB, "Skipping commit, index is ahead of flushed chainstate (index height %d, last flush at height %d)", + index_tip->nHeight, last_flushed ? last_flushed->nHeight : -1); + return; + } CDBBatch batch(GetDB()); ok = CustomCommit(batch); if (ok) { @@ -288,9 +300,7 @@ bool BaseIndex::Commit() } if (!ok) { LogError("Failed to commit latest %s state", GetName()); - return false; } - return true; } bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) diff --git a/src/index/base.h b/src/index/base.h index 6d7e86ec..73282a96 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -65,7 +65,7 @@ class BaseIndex : public CValidationInterface { public: DB(const fs::path& path, size_t n_cache_size, - bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false); + bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false, bool f_bloom = true); /// Read block locator of the chain that the index is in sync with. /// Note, the returned locator will be empty if no record exists. @@ -94,14 +94,10 @@ class BaseIndex : public CValidationInterface CThreadInterrupt m_interrupt; /// Write the current index state (eg. chain block locator and subclass-specific items) to disk. - /// - /// Recommendations for error handling: - /// If called on a successor of the previous committed best block in the index, the index can - /// continue processing without risk of corruption, though the index state will need to catch up - /// from further behind on reboot. If the new state is not a successor of the previous state (due - /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up - /// getting corrupted. - bool Commit(); + /// Will skip the commit if no block has been indexed yet or if the index's best block is + /// ahead of the chainstate's last flushed block. This avoids persisting state an unclean shutdown + /// could not roll back from. A later call commits when the chainstate has flushed far enough. + void Commit(); /// Loop over disconnected blocks and call CustomRemove. bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip); diff --git a/src/index/txospenderindex.cpp b/src/index/txospenderindex.cpp index 50b9bfeb..304104df 100644 --- a/src/index/txospenderindex.cpp +++ b/src/index/txospenderindex.cpp @@ -62,7 +62,7 @@ struct DBKey { }; TxoSpenderIndex::TxoSpenderIndex(std::unique_ptr chain, size_t n_cache_size, bool f_memory, bool f_wipe) - : BaseIndex(std::move(chain), "txospenderindex", "txospenderidx"), m_db{std::make_unique(gArgs.GetDataDirNet() / "indexes" / "txospenderindex" / "db", n_cache_size, f_memory, f_wipe)} + : BaseIndex(std::move(chain), "txospenderindex", "txospenderidx"), m_db{std::make_unique(gArgs.GetDataDirNet() / "indexes" / "txospenderindex" / "db", n_cache_size, f_memory, f_wipe, /*f_obfuscate=*/false, /*f_bloom=*/false)} { if (!m_db->Read("siphash_key", m_siphash_key)) { FastRandomContext rng(false); diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index d2116317..326361aa 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -59,9 +59,6 @@ struct WalletTxOut; struct WalletTxStatus; struct WalletMigrationResult; -using WalletOrderForm = std::vector>; -using WalletValueMap = std::map; - //! Interface for accessing a wallet. class Wallet { @@ -150,9 +147,7 @@ class Wallet std::optional change_pos) = 0; //! Commit transaction. - virtual void commitTransaction(CTransactionRef tx, - WalletValueMap value_map, - WalletOrderForm order_form) = 0; + virtual void commitTransaction(CTransactionRef tx, const std::vector& messages) = 0; //! Return whether transaction can be abandoned. virtual bool transactionCanBeAbandoned(const Txid& txid) = 0; @@ -198,7 +193,8 @@ class Wallet //! Get transaction details. virtual WalletTx getWalletTxDetails(const Txid& txid, WalletTxStatus& tx_status, - WalletOrderForm& order_form, + std::vector& messages, + std::vector& payment_requests, bool& in_mempool, int& num_blocks) = 0; @@ -392,7 +388,10 @@ struct WalletTx CAmount debit; CAmount change; int64_t time; - std::map value_map; + std::optional from; // Deprecated + std::optional message; // Deprecated + std::optional comment; + std::optional comment_to; bool is_coinbase; bool operator<(const WalletTx& a) const { return tx->GetHash() < a.tx->GetHash(); } diff --git a/src/ipc/libmultiprocess/doc/usage.md b/src/ipc/libmultiprocess/doc/usage.md index f387db4d..df103e9f 100644 --- a/src/ipc/libmultiprocess/doc/usage.md +++ b/src/ipc/libmultiprocess/doc/usage.md @@ -10,7 +10,7 @@ _libmultiprocess_ is a library and code generator that allows calling C++ class The `*.capnp` data definition files are consumed by the _libmultiprocess_ code generator and each `X.capnp` file generates `X.capnp.c++`, `X.capnp.h`, `X.capnp.proxy-client.c++`, `X.capnp.proxy-server.c++`, `X.capnp.proxy-types.c++`, `X.capnp.proxy-types.h`, and `X.capnp.proxy.h` output files. The generated files include `mp::ProxyClient` and `mp::ProxyServer` class specializations for all the interfaces in the `.capnp` files. These allow methods on C++ objects in one process to be called from other processes over IPC sockets. -The `ProxyServer` objects help translate IPC requests from a socket to method calls on a local object. The `ProxyServer` objects are just used internally by the `mp::ServeStream(loop, socket, wrapped_object)` and `mp::ListenConnections(loop, socket, wrapped_object)` functions, and aren't exposed externally. The `ProxyClient` classes are exposed, and returned from the `mp::ConnectStream(loop, socket)` function and meant to be used directly. The classes implement methods described in `.capnp` definitions, and whenever any method is called, a request with the method arguments is sent over the associated IPC connection, and the corresponding `wrapped_object` method on the other end of the connection is called, with the `ProxyClient` method blocking until it returns and forwarding back any return value to the `ProxyClient` method caller. +The `ProxyServer` objects help translate IPC requests from a socket to method calls on a local object. The `ProxyServer` objects are just used internally by the `mp::ServeStream(loop, socket, wrapped_object)` and `mp::ListenConnections(loop, socket, wrapped_object[, max_connections])` functions, and aren't exposed externally. The `ProxyClient` classes are exposed, and returned from the `mp::ConnectStream(loop, socket)` function and meant to be used directly. The classes implement methods described in `.capnp` definitions, and whenever any method is called, a request with the method arguments is sent over the associated IPC connection, and the corresponding `wrapped_object` method on the other end of the connection is called, with the `ProxyClient` method blocking until it returns and forwarding back any return value to the `ProxyClient` method caller. ## Example diff --git a/src/ipc/libmultiprocess/doc/versions.md b/src/ipc/libmultiprocess/doc/versions.md index 3cfa28e3..83b5cf53 100644 --- a/src/ipc/libmultiprocess/doc/versions.md +++ b/src/ipc/libmultiprocess/doc/versions.md @@ -7,8 +7,24 @@ Library versions are tracked with simple Versioning policy is described in the [version.h](../include/mp/version.h) include. -## v11 +## v12 - Current unstable version. +- Adds an optional per-listener `max_connections` parameter to `ListenConnections()` + so servers can stop accepting new connections when a local connection cap is reached, + and resume accepting after existing connections disconnect. + +## [v11.0](https://github.com/bitcoin-core/libmultiprocess/commits/v11.0) +- Adds `makePool` method on `ThreadMap` to support thread pool routing, allowing requests without a specific client thread to be dispatched to a pool using a shortest-queue strategy ([#283](https://github.com/bitcoin-core/libmultiprocess/pull/283)). +- Adds `std::unordered_set` support, a `BuildList` helper, and a `ReadList` helper to reduce duplication in list build and read handlers ([#277](https://github.com/bitcoin-core/libmultiprocess/pull/277), [#285](https://github.com/bitcoin-core/libmultiprocess/pull/285)). +- Adds support for translating C++ `std::optional` struct fields to pairs of `T` + `hasT :Bool` Cap'n Proto struct fields, allowing unset optional primitive fields to be represented ([#243](https://github.com/bitcoin-core/libmultiprocess/pull/243)). +- Produces more readable log output for Proxy object lifecycle events and IPC server-side failures ([#218](https://github.com/bitcoin-core/libmultiprocess/pull/218)). +- Handles exceptions thrown by `destroy` methods by logging instead of aborting ([#273](https://github.com/bitcoin-core/libmultiprocess/pull/273)). This can prevent server crashes when non-libmultiprocess clients disconnect without destroying objects, in the case where a server object owns client objects and the server destructor tries to call the disconnected client to free them ([#219](https://github.com/bitcoin-core/libmultiprocess/issues/219)). +- Handles unexpected exceptions thrown by callbacks (that should never happen) by logging errors instead of deadlocking ([#260](https://github.com/bitcoin-core/libmultiprocess/pull/260)). +- Fixes a rare mptest hang on musl builds caused by a lost wakeup bug in `Waiter` ([#295](https://github.com/bitcoin-core/libmultiprocess/pull/295)). +- Fixes a race condition in a log print detected by TSan ([#286](https://github.com/bitcoin-core/libmultiprocess/pull/286)). +- Build improvements: makes `target_capnp_sources` work correctly when libmultiprocess is used as a CMake subproject ([#289](https://github.com/bitcoin-core/libmultiprocess/pull/289)), adds `mp_headers` target for better lint tool support ([#291](https://github.com/bitcoin-core/libmultiprocess/pull/291)), and fixes compatibility with recent Nix and CMake 4.0 ([#238](https://github.com/bitcoin-core/libmultiprocess/pull/238)). +- Test, CI, documentation, and minor code improvements: design document corrections ([#278](https://github.com/bitcoin-core/libmultiprocess/pull/278)), field constant comments ([#279](https://github.com/bitcoin-core/libmultiprocess/pull/279)), clang-tidy fix ([#292](https://github.com/bitcoin-core/libmultiprocess/pull/292)), new smoke test for double-precision float values ([#294](https://github.com/bitcoin-core/libmultiprocess/pull/294)), new test for recursive async IPC calls ([#301](https://github.com/bitcoin-core/libmultiprocess/pull/301)), removal of libevent from Core CI builds ([#299](https://github.com/bitcoin-core/libmultiprocess/pull/299)), and rename of `EventLoop::m_num_clients` to `m_num_refs` ([#302](https://github.com/bitcoin-core/libmultiprocess/pull/302)). +- Used in Bitcoin Core master branch, pulled in by [#35661](https://github.com/bitcoin/bitcoin/pull/35661). ## [v10.0](https://github.com/bitcoin-core/libmultiprocess/commits/v10.0) - Increases spawn test timeout to avoid spurious failures. diff --git a/src/ipc/libmultiprocess/include/mp/proxy-io.h b/src/ipc/libmultiprocess/include/mp/proxy-io.h index 259696a0..ec9a1539 100644 --- a/src/ipc/libmultiprocess/include/mp/proxy-io.h +++ b/src/ipc/libmultiprocess/include/mp/proxy-io.h @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include #include @@ -25,6 +27,7 @@ namespace mp { struct ThreadContext; +struct Listener; struct InvokeContext { @@ -360,6 +363,12 @@ class EventLoop //! Hook called on the worker thread just before returning results. std::function testing_hook_async_request_done; + + //! Hook called on the event loop thread when a client has connected. + std::function testing_hook_connected; + + //! Hook called on the event loop thread when a client has disconnected. + std::function testing_hook_disconnected; }; //! Single element task queue used to handle recursive capnp calls. (If the @@ -842,8 +851,8 @@ std::unique_ptr> ConnectStream(EventLoop& loop, int f //! handles requests from the stream by calling the init object. Embed the //! ProxyServer in a Connection object that is stored and erased if //! disconnected. This should be called from the event loop thread. -template -void _Serve(EventLoop& loop, kj::Own&& stream, InitImpl& init) +template +void _Serve(EventLoop& loop, kj::Own&& stream, InitImpl& init, OnDisconnect&& on_disconnect) { loop.m_incoming_connections.emplace_front(loop, kj::mv(stream), [&](Connection& connection) { // Disable deleter so proxy server object doesn't attempt to delete the @@ -853,23 +862,46 @@ void _Serve(EventLoop& loop, kj::Own&& stream, InitImpl& init }); auto it = loop.m_incoming_connections.begin(); MP_LOG(loop, Log::Info) << "IPC server: socket connected."; - it->onDisconnect([&loop, it] { + if (loop.testing_hook_connected) loop.testing_hook_connected(); + it->onDisconnect([&loop, it, on_disconnect = std::forward(on_disconnect)]() mutable { MP_LOG(loop, Log::Info) << "IPC server: socket disconnected."; loop.m_incoming_connections.erase(it); + on_disconnect(); + if (loop.testing_hook_disconnected) loop.testing_hook_disconnected(); }); } -//! Given connection receiver and an init object, handle incoming connections by -//! calling _Serve, to create ProxyServer objects and forward requests to the -//! init object. +struct Listener +{ + explicit Listener(kj::Own&& receiver, std::optional max_connections) + : m_receiver(kj::mv(receiver)), m_max_connections(max_connections) {} + + bool atCapacity() const + { + return m_max_connections && m_active_connections >= *m_max_connections; + } + + kj::Own m_receiver; + std::optional m_max_connections; + size_t m_active_connections{0}; +}; + template -void _Listen(EventLoop& loop, kj::Own&& listener, InitImpl& init) +void _Listen(const std::shared_ptr& listener, EventLoop& loop, InitImpl& init) { - auto* ptr = listener.get(); - loop.m_task_set->add(ptr->accept().then( - [&loop, &init, listener = kj::mv(listener)](kj::Own&& stream) mutable { - _Serve(loop, kj::mv(stream), init); - _Listen(loop, kj::mv(listener), init); + if (listener->atCapacity()) return; + + auto* receiver = listener->m_receiver.get(); + loop.m_task_set->add(receiver->accept().then( + [&loop, &init, listener](kj::Own&& stream) { + ++listener->m_active_connections; + _Serve(loop, kj::mv(stream), init, [&loop, &init, listener] { + const bool resume_accept{listener->atCapacity()}; + assert(listener->m_active_connections > 0); + --listener->m_active_connections; + if (resume_accept) _Listen(listener, loop, init); + }); + _Listen(listener, loop, init); })); } @@ -879,18 +911,22 @@ template void ServeStream(EventLoop& loop, int fd, InitImpl& init) { _Serve( - loop, loop.m_io_context.lowLevelProvider->wrapSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP), init); + loop, + loop.m_io_context.lowLevelProvider->wrapSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP), + init, + [] {}); } //! Given listening socket file descriptor and an init object, handle incoming //! connections and requests by calling methods on the Init object. template -void ListenConnections(EventLoop& loop, int fd, InitImpl& init) +void ListenConnections(EventLoop& loop, int fd, InitImpl& init, std::optional max_connections = std::nullopt) { loop.sync([&]() { - _Listen(loop, + auto listener{std::make_shared( loop.m_io_context.lowLevelProvider->wrapListenSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP), - init); + max_connections)}; + _Listen(listener, loop, init); }); } diff --git a/src/ipc/libmultiprocess/include/mp/version.h b/src/ipc/libmultiprocess/include/mp/version.h index 423ed460..4587a288 100644 --- a/src/ipc/libmultiprocess/include/mp/version.h +++ b/src/ipc/libmultiprocess/include/mp/version.h @@ -24,7 +24,7 @@ //! pointing at the prior merge commit. The /doc/versions.md file should also be //! updated, noting any significant or incompatible changes made since the //! previous version. -#define MP_MAJOR_VERSION 11 +#define MP_MAJOR_VERSION 12 //! Minor version number. Should be incremented in stable branches after //! backporting changes. The /doc/versions.md file should also be updated to diff --git a/src/ipc/libmultiprocess/test/CMakeLists.txt b/src/ipc/libmultiprocess/test/CMakeLists.txt index 1f21ba44..13246293 100644 --- a/src/ipc/libmultiprocess/test/CMakeLists.txt +++ b/src/ipc/libmultiprocess/test/CMakeLists.txt @@ -26,6 +26,7 @@ if(BUILD_TESTING AND TARGET CapnProto::kj-test) ${MP_PROXY_HDRS} mp/test/foo-types.h mp/test/foo.h + mp/test/listen_tests.cpp mp/test/spawn_tests.cpp mp/test/test.cpp ) diff --git a/src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp b/src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp new file mode 100644 index 00000000..4e579d99 --- /dev/null +++ b/src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp @@ -0,0 +1,294 @@ +// Copyright (c) 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include + +namespace mp { +namespace test { +namespace { + +constexpr auto FAILURE_TIMEOUT = std::chrono::seconds{30}; + +//! Owns a temporary Unix-domain listening socket used by ListenSetup. Tests call +//! Connect() to create client socket FDs and release() to transfer the listening +//! FD to ListenConnections(). +class UnixListener +{ +public: + UnixListener() + { + std::string dir_template = (std::filesystem::temp_directory_path() / "mptest-listener-XXXXXX").string(); + char* dir = mkdtemp(dir_template.data()); + KJ_REQUIRE(dir != nullptr); + m_dir = dir; + m_path = m_dir + "/socket"; + + m_fd = socket(AF_UNIX, SOCK_STREAM, 0); + KJ_REQUIRE(m_fd >= 0); + + sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + KJ_REQUIRE(m_path.size() < sizeof(addr.sun_path)); + std::strncpy(addr.sun_path, m_path.c_str(), sizeof(addr.sun_path) - 1); + KJ_REQUIRE(bind(m_fd, reinterpret_cast(&addr), sizeof(addr)) == 0); + KJ_REQUIRE(listen(m_fd, SOMAXCONN) == 0); + } + + ~UnixListener() + { + if (m_fd >= 0) close(m_fd); + if (!m_path.empty()) unlink(m_path.c_str()); + if (!m_dir.empty()) rmdir(m_dir.c_str()); + } + + int release() + { + assert(m_fd >= 0); + int fd = m_fd; + m_fd = -1; + return fd; + } + + int MakeConnectedSocket() const + { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + KJ_REQUIRE(fd >= 0); + + sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + KJ_REQUIRE(m_path.size() < sizeof(addr.sun_path)); + std::strncpy(addr.sun_path, m_path.c_str(), sizeof(addr.sun_path) - 1); + KJ_REQUIRE(connect(fd, reinterpret_cast(&addr), sizeof(addr)) == 0); + return fd; + } + +private: + int m_fd{-1}; + std::string m_dir; + std::string m_path; +}; + +//! Runs a client EventLoop on its own thread and connects one socket FD to the +//! server. The constructed ProxyClient can be used by the test thread to make +//! calls over that connection. +class ClientSetup +{ +public: + explicit ClientSetup(int fd) + : thread([this, fd] { + EventLoop loop("mptest-client", [](mp::LogMessage log) { + KJ_LOG(INFO, log.level, log.message); + if (log.level == mp::Log::Raise) throw std::runtime_error(log.message); + }); + client_promise.set_value(ConnectStream(loop, fd)); + loop.loop(); + }) + { + client = client_promise.get_future().get(); + } + + ~ClientSetup() + { + client.reset(); + thread.join(); + } + + std::promise>> client_promise; + std::unique_ptr> client; + + //! Thread variable should be after other struct members so the thread does + //! not start until the other members are initialized. + std::thread thread; +}; + +//! Runs a server EventLoop on its own thread, starts ListenConnections() on a +//! UnixListener socket, and records connection/disconnection counts through +//! EventLoop test hooks +class ListenSetup +{ +public: + explicit ListenSetup(std::optional max_connections = std::nullopt) + : thread([this, max_connections] { + EventLoop loop("mptest-server", [](mp::LogMessage log) { + KJ_LOG(INFO, log.level, log.message); + if (log.level == mp::Log::Raise) throw std::runtime_error(log.message); + }); + loop.testing_hook_disconnected = [&] { + Lock lock(counter_mutex); + ++disconnected_count; + counter_cv.notify_all(); + }; + loop.testing_hook_connected = [&] { + Lock lock(counter_mutex); + ++connected_count; + counter_cv.notify_all(); + }; + m_loop_ref.emplace(loop); + FooImplementation foo; + ListenConnections(loop, listener.release(), foo, max_connections); + ready_promise.set_value(); + loop.loop(); + }) + { + ready_promise.get_future().get(); + } + + ~ListenSetup() + { + m_loop_ref.reset(); + thread.join(); + } + + size_t ConnectedCount() + { + Lock lock(counter_mutex); + return connected_count; + } + + size_t DisconnectedCount() + { + Lock lock(counter_mutex); + return disconnected_count; + } + + void WaitForConnectedCount(size_t expected_count) + { + Lock lock(counter_mutex); + const auto deadline = std::chrono::steady_clock::now() + FAILURE_TIMEOUT; + const bool matched = counter_cv.wait_until(lock.m_lock, deadline, [&]() MP_REQUIRES(counter_mutex) { + return connected_count >= expected_count; + }); + KJ_REQUIRE(matched); + } + + void WaitForDisconnectedCount(size_t expected_count) + { + Lock lock(counter_mutex); + const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); + const bool matched = counter_cv.wait_until(lock.m_lock, deadline, [&]() MP_REQUIRES(counter_mutex) { + return disconnected_count >= expected_count; + }); + KJ_REQUIRE(matched); + } + + UnixListener listener; + std::promise ready_promise; + std::optional m_loop_ref; + Mutex counter_mutex; + std::condition_variable counter_cv; + size_t connected_count MP_GUARDED_BY(counter_mutex) {0}; + size_t disconnected_count MP_GUARDED_BY(counter_mutex) {0}; + //! Thread variable should be after other struct members so the thread does + //! not start until the other members are initialized. + std::thread thread; +}; + +KJ_TEST("ListenConnections accepts incoming connections") +{ + ListenSetup server; + KJ_EXPECT(server.ConnectedCount() == 0) + auto client = std::make_unique(server.listener.MakeConnectedSocket()); + + server.WaitForConnectedCount(1); + KJ_EXPECT(client->client->add(1, 2) == 3); +} + +KJ_TEST("ListenConnections enforces a local connection limit") +{ + // With max-connections=1, the second socket can connect to the kernel + // backlog, but ListenConnections should not accept or serve it until the + // first accepts clients disconnects. + + ListenSetup server(/*max_connections=*/1); + + KJ_EXPECT(server.ConnectedCount() == 0) + auto client1 = std::make_unique(server.listener.MakeConnectedSocket()); + server.WaitForConnectedCount(1); + + KJ_EXPECT(client1->client->add(1, 2) == 3); + + auto client2 = std::make_unique(server.listener.MakeConnectedSocket()); + // Without this sync, ConnectedCount() == 1 might pass even if + // max_connections was not enforced because the event loop has not accepted + // client2 yet. + (**server.m_loop_ref).sync([] {}); + + KJ_EXPECT(server.ConnectedCount() == 1); + KJ_EXPECT(server.DisconnectedCount() == 0); + client1.reset(); + server.WaitForDisconnectedCount(1); + server.WaitForConnectedCount(2); + + KJ_EXPECT(client2->client->add(2, 3) == 5); + + KJ_EXPECT(server.DisconnectedCount() == 1); + client2.reset(); + server.WaitForDisconnectedCount(2); + + KJ_EXPECT(server.DisconnectedCount() == 2); + auto client3 = std::make_unique(server.listener.MakeConnectedSocket()); + server.WaitForConnectedCount(3); + KJ_EXPECT(client3->client->add(3, 4) == 7); +} + +KJ_TEST("ListenConnections accepts multiple connections") +{ + // With max-connections=2, two clients should be accepted and usable at the + // same time, while a third waits until one active client disconnects. + + ListenSetup server(/*max_connections=*/2); + + KJ_EXPECT(server.ConnectedCount() == 0); + auto client1 = std::make_unique(server.listener.MakeConnectedSocket()); + auto client2 = std::make_unique(server.listener.MakeConnectedSocket()); + server.WaitForConnectedCount(2); + + KJ_EXPECT(client1->client->add(1, 2) == 3); + KJ_EXPECT(client2->client->add(2, 3) == 5); + + auto client3 = std::make_unique(server.listener.MakeConnectedSocket()); + // Without this sync, ConnectedCount() == 2 might pass even if + // max_connections was not enforced because the event loop has not accepted + // client3 yet. + (**server.m_loop_ref).sync([] {}); + + KJ_EXPECT(server.ConnectedCount() == 2); + KJ_EXPECT(server.DisconnectedCount() == 0); + client1.reset(); + server.WaitForDisconnectedCount(1); + server.WaitForConnectedCount(3); + + KJ_EXPECT(client3->client->add(3, 4) == 7); +} + +} // namespace +} // namespace test +} // namespace mp diff --git a/src/ipc/test/fuzz/CMakeLists.txt b/src/ipc/test/fuzz/CMakeLists.txt index 7af1477a..deefa801 100644 --- a/src/ipc/test/fuzz/CMakeLists.txt +++ b/src/ipc/test/fuzz/CMakeLists.txt @@ -3,4 +3,4 @@ # file COPYING or https://opensource.org/license/mit/. target_sources(fuzz PRIVATE ${PROJECT_SOURCE_DIR}/src/ipc/test/fuzz/ipc.cpp) -target_link_libraries(fuzz bitcoin_ipc_fuzz multiprocess) +target_link_libraries(fuzz bitcoin_ipc_fuzz Libmultiprocess::multiprocess) diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index d2a467f6..8b562aa7 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -119,6 +119,12 @@ if(bitcoinkernel_type STREQUAL "STATIC_LIBRARY") target_compile_definitions(bitcoinkernel PUBLIC BITCOINKERNEL_STATIC) endif() +option(ENABLE_SCRIPT_TRACE "Enable script execution trace hooks" OFF) +if(ENABLE_SCRIPT_TRACE) + target_sources(bitcoinkernel PRIVATE ../script/trace.cpp) + target_compile_definitions(bitcoinkernel PRIVATE ENABLE_SCRIPT_TRACE) +endif() + configure_file(${PROJECT_SOURCE_DIR}/libbitcoinkernel.pc.in ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc @ONLY) install(FILES ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT libbitcoinkernel) diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp index 152f778b..acfb6884 100644 --- a/src/kernel/bitcoinkernel.cpp +++ b/src/kernel/bitcoinkernel.cpp @@ -24,6 +24,10 @@ #include #include