75f64e50c6 test: exercise node abort on UTXO deserialization failure (furszy)
4652cd0d82 txdb: detect UTXO deserialization errors via CDBWrapper::TryRead() (furszy)
5dfbb91b6c dbwrapper: add TryRead() to distinguish errors from valid outcomes (furszy)
f78834fac9 test: add missing coverage for CDBWrapper::Read() errors (furszy)
Pull request description:
Early note: the majority of this PR consists of test coverage. The changes per se are small.
If a UTXO entry on disk can't be deserialized, the node currently treats it as if the coin
wouldn't exist instead of aborting with an error. A non-existing coin has a very specific
meaning for consensus: any block that spends it would be permanently rejected as invalid
(`BLOCK_FAILED_VALID`), silently forking the node from the rest of the network. This can't
currently be triggered in practice (details below), but it's still the wrong behavior.
The root cause is that `CDBWrapper::Read()` returns `false` for both missing entries and
deserialization failures, so `CCoinsViewDB::GetCoin()` has no way to tell them apart.
`CCoinsViewErrorCatcher` was built to catch database read errors and abort, but it never
fires during deserialization errors because `CDBWrapper::Read()` swallows the exception
before it can propagate. This [comment](8a8edc8d88/src/coins.cpp (L398-L411)) in `ExecuteBackedWrapper()` spells out the code
intent very clearly.
As mentioned initially, this can't happen in practice today. It would require either a bug
in the coin serialization path, or a memory corruption before the data reaches LevelDB
(at which point we have bigger problems). Random disk-level bit flips are caught earlier
by LevelDB's verification (`verify_checksums=true`, enabled by default), which already
propagates correctly as `DB_INTERNAL_ERROR`. Regardless, a db read issue should
never be silently misinterpreted as a consensus violation.
This PR adds `CDBWrapper::TryRead()`, which returns a `ReadStatus` that lets callers
discriminate between all possible outcomes. `CCoinsViewDB::GetCoin()` switches on the
result and throws on any error, letting `ExecuteBackedWrapper()` do what it was designed
to do. `CDBWrapper::Read()` becomes a thin wrapper over `TryRead()`, preserving backward
compatibility for all other callers (so we don't have to change non-consensus code here).
`PeekCoin()` is also covered, as it delegates to `CCoinsViewDB::GetCoin()` at the database
level.
The idea of the PR is to go slowly over the code changes, first commit locks-in the current
`CDBWrapper::Read()` behavior . The second adds `TryRead()` with tests for all four
status codes. The third is the `CCoinsViewDB::GetCoin()` fix. The fourth is a functional
that ensures the node aborts correctly instead of silently diverging.
Testing Notes:
Cherry-picking the functional test commit on master demonstrates the consensus split
when the coin entry fails to deserialize.
Extra Note:
`CDBIterator::GetValue()` has the same silent-swallow pattern. Not consensus-critical.
Should be addressed in a follow-up.
ACKs for top commit:
ajtowns:
reACK 75f64e50c6
sedited:
ACK 75f64e50c6
mzumsande:
Code Review ACK [75f64e5](75f64e50c6)
Tree-SHA512: 51b0114ea443544a2f1fbb8e63be6e1dff94d6f287221d566dbc98d666784a2b4c486acfb87eea5392bc1d092fb6d6dc0ff6782bcdccdcf15939281c895e384d
This ensures that UTXO unserialization errors abort the node, and does
not cause a consensus divergence.
A valid UTXO is created and shared between two nodes. The raw database
entry is then deliberately modified on one node so it can no longer be
deserialized. When the other node spends that UTXO and mines a block,
the node with the unserializable entry must abort during block connection
rather than silently treating the coin as absent and marking the block
BLOCK_FAILED_VALID, which would cause it to permanently diverge from the
network's best chain.
b3ff9c4d68 iwyu: Fix warnings in `src/interfaces` and treat them as errors (Hennadii Stepanov)
d564b0255f iwyu: Add temporary mapping to work around upstream bug (Hennadii Stepanov)
Pull request description:
This PR continues the ongoing effort to enforce IWYU warnings.
See [Developer Notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#using-iwyu).
ACKs for top commit:
maflcko:
review ACK b3ff9c4d68 🖋
Tree-SHA512: 9359854c7b6e6ec93022947e78ef57fc68728326df874371028997a550fd1b6ef08e4b09271163b9d5c921c9e01deadf92b0eb5ae3f620d797e4f9bdea8f4727
de9b436ba3 depends: Switch from multilib to platform-specific toolchains (Hennadii Stepanov)
Pull request description:
Using the multilib GCC toolchain, as currently documented in [`depends/README.md`](4c1906a500/depends/README.md), has several issues, such as:
1. The [`g++-multilib`](https://packages.ubuntu.com/noble/g++-multilib) package conflicts with platform-specific cross-compiler packages. This means it is not possible to cross compile for `i686` and other platforms using the same set of installed packages.
2. The [`g++-multilib`](https://packages.ubuntu.com/noble/g++-multilib) package is not available for `arm64`:
```sh
$ sudo apt install g++-multilib
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package g++-multilib
```
3. Managing the multilib GCC toolchain requires additional code in both depends and Guix scripts.
This PR addresses all the issues mentioned above by switching from multilib to platform-specific toolchains.
Also see https://github.com/bitcoin/bitcoin/pull/22456.
---
Here are examples of building for different scenarions:
- Linux, `x86_64` or `arm64`, building with depends natively:
```sh
$ gmake -C depends -j $(nproc)
$ cmake -B build --toolchain depends/$(./depends/config.sub $(./depends/config.guess))/toolchain.cmake
$ cmake --build build -j $(nproc)
```
- Linux, `x86_64` or `arm64`, cross compiling for `i686-pc-linux-gnu`:
```sh
$ sudo apt install g++-i686-linux-gnu binutils-i686-linux-gnu
$ export HOST=i686-linux-gnu
$ gmake -C depends -j $(nproc)
$ cmake -B build-${HOST} --toolchain depends/${HOST}/toolchain.cmake
$ cmake --build build-${HOST} -j $(nproc)
```
- Linux, `x86_64`, cross compiling for `arm64`:
```sh
$ sudo apt install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu
$ export HOST=aarch64-linux-gnu
$ gmake -C depends -j $(nproc)
$ cmake -B build-${HOST} --toolchain depends/${HOST}/toolchain.cmake
$ cmake --build build-${HOST} -j $(nproc)
```
- Linux, `arm64`, cross compiling for `x86_64`:
```sh
$ sudo apt install g++-x86-64-linux-gnu binutils-x86-64-linux-gnu
$ export HOST=x86_64-linux-gnu
$ gmake -C depends -j $(nproc)
$ cmake -B build-${HOST} --toolchain depends/${HOST}/toolchain.cmake
$ cmake --build build-${HOST} -j $(nproc)
```
ACKs for top commit:
fanquake:
ACK de9b436ba3
BrandonOdiwuor:
ACK de9b436ba3
Tree-SHA512: 453b4744974cdf56d6edfdbe93bb11e3bae3f9bc9cd99b9c57aee74e65fcdd3ac011a1dcc19f485ea3be427f4e9c6c6b0d704881369f719620f0cb299123e561
The print_suppressions=0 is required to avoid a CI failure when the
suppressions were used. E.g:
```
$ LSAN_OPTIONS="suppressions=$(pwd)/test/sanitizer_suppressions/lsan:print_suppressions=1" ./bld-cmake/test/functional/interface_gui.py
2026-08-08T10:53:45.864160Z TestFramework (INFO): PRNG seed is: 8358096631255493262
2026-08-08T10:53:45.914748Z TestFramework (INFO): Initializing test directory /tmp/bitcoin_func_test_5zx5343v
2026-08-08T10:53:47.029997Z TestFramework (INFO): Test that bitcoin-gui starts up and can be stopped via RPC
2026-08-08T10:53:47.431761Z TestFramework (ERROR): Unexpected exception:
File "./test/functional/test_framework/test_node.py", line 534, in is_node_stopped
raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr))
AssertionError: Unexpected stderr -----------------------------------------------------
Suppressions used:
count bytes template
2 181 bitcoin-qt
----------------------------------------------------- !=
```
The general suppression of the qt executables is required to avoid CI
failures for i386 builds. E.g:
```
test 2026-08-05T08:54:08.370427Z TestFramework (ERROR): Unexpected exception:
Traceback (most recent call last):
File "/ci_container_base/ci/scratch_ ₿🧪_/build-i686-pc-linux-gnu/test/functional/interface_gui.py", line 34, in run_test
self.stop_node(0)
~~~~~~~~~~~~~~^^^
File "/ci_container_base/test/functional/test_framework/test_node.py", line 525, in is_node_stopped
assert return_code in expected_ret_code, self._node_msg(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: [node 0] Node returned unexpected exit code (1) vs ((0,)) when stopping
node0 stderr =================================================================
==73449==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 386 byte(s) in 17 object(s) allocated from:
#0 0x5df28a2d in malloc (/ci_container_base/ci/scratch_ ₿🧪_/build-i686-pc-linux-gnu/bin/bitcoin-qt+0x1d0da2d) (BuildId: 496a5df531df278fe395724ae917f266331b3f81)
#1 0xee03c1d1 (<unknown module>)
Indirect leak of 12 byte(s) in 1 object(s) allocated from:
#0 0x5df28a2d in malloc (/ci_container_base/ci/scratch_ ₿🧪_/build-i686-pc-linux-gnu/bin/bitcoin-qt+0x1d0da2d) (BuildId: 496a5df531df278fe395724ae917f266331b3f81)
#1 0xee03c1d1 (<unknown module>)
SUMMARY: AddressSanitizer: 398 byte(s) leaked in 18 allocation(s).
```
81fcecfe45 Revert "ci: Temporarily remove riscv32 config from GHA matrix" (will)
b283e1751c ci: use mirror for riscv submodules (will)
Pull request description:
The https transport is rate-limited to block AI scrapers.
Switch to a live mirror on fish.foo to re-enable the riscv job.
ACKs for top commit:
maflcko:
lgtm ACK 81fcecfe45
sedited:
ACK 81fcecfe45
Tree-SHA512: 1891046d9847b904a3e4be25b7f313fc2413ad1cc0b2c09b2300f81a2f1f691dad816fa5fcfeeae263f8d5f868d229aca5a7ab3f227ce650d359068488bc1e21
sourceware is blocking/rate-limiting http(s) git requests to combat AI
scrapers.
Switch to a live mirror hosted at fish.foo
Use exported GIT_CONFIG_* to avoid setting `git config --global` which
could clobber a user running on bare host, but still propagate to child
git processes spawned by `make`.
The macOS and BSD cross-build jobs extract SDK archives fetched at runtime without checking their content.
Keep each expected digest beside the corresponding SDK version and verify every archive before extraction.
Create the OpenBSD library symlinks once after both archives are extracted, when all link targets are present.
Fix all IWYU warnings in `src/common` and treat them as errors in CI.
Additionally, ensure that our drop-in header replacements are used
instead of system headers:
- `<util/check.h>` instead of `<cassert>`
- `<util/time.h>` instead of `<chrono>`
b36730a3ef Add CI job for riscv bare metal (TheCharlatan)
bfdbf513f6 Add CI job for producing a static bare metal binary (TheCharlatan)
a9a1d92a1d build: Add option for building for bare metal envs (TheCharlatan)
Pull request description:
This adds a CI job for building the static consensus library and linking it to an executable. It uses newlib-cygwin as a C library for the final linking step. This ensure compatibility with this target going forward and can serve as a starting point for enabling bare metal builds for the entire kernel library. This would have also caught the error fixed in #31365.
ACKs for top commit:
fanquake:
ACK b36730a3ef
willcl-ark:
reACK b36730a3ef
Tree-SHA512: c199260f243e20df7f6a537e6c1eaf3d32e23f8fc78b9a8e2b75d9feff3830ef61279e93093dacdceb99e8eb010321b4c1c644e2ad9e266f0ca1ae736baa20ae
d64ea15824 ci: add openBSD cross CI job (fanquake)
5404b62074 depends: add openbsd_LDFLAGS (fanquake)
Pull request description:
This adds a Linux cross job for OpenBSD; similar to https://github.com/bitcoin/bitcoin/pull/34491 (FreeBSD).
ACKs for top commit:
hebasto:
ACK d64ea15824.
willcl-ark:
ACK d64ea15824
Tree-SHA512: 0353c0ae8dd49c861a9100ebd5044fc39227c29859ca68e6454ebdf469c90ff5471e29733613606ee8ba72037f7fca5086275f794e90864a6456ffee73d9113b
fa98d44951 ci: Rewrite broken wrap-valgrind.sh to .py (MarcoFalke)
faf7e38973 ci: refactor: Avoid warning: INSTALL_BCC_TRACING_TOOLS: unbound variable (MarcoFalke)
Pull request description:
The first commit fixes an error about `INSTALL_BCC_TRACING_TOOLS` being unbound.
The second commit rewrites the wrap-valgrind Bash script to Python to fix the shellcheck SC2044 violation.
Without this, the script would fail in CI when a path with spaces was used:
```
...
+ /ci_container_base/ci/test/wrap-valgrind.sh
Wrap /ci_container_base/ci/scratch_ ...
mv: cannot stat '/ci_container_base/ci/scratch_': No such file or directory
Wrap ₿🧪_/out/bin/bitcoin ...
mv: cannot stat '₿🧪_/out/bin/bitcoin': No such file or directory
/ci_container_base/ci/test/wrap-valgrind.sh: line 14: ₿🧪_/out/bin/bitcoin: No such file or directory
/ci_container_base/ci/test/wrap-valgrind.sh: line 15: ₿🧪_/out/bin/bitcoin: No such file or directory
chmod: cannot access '₿🧪_/out/bin/bitcoin': No such file or directory
ACKs for top commit:
fanquake:
ACK fa98d44951 - tested both on x86_64
hebasto:
ACK fa98d44951, tested on Ubuntu 26.04. I also verified the actual content of the created wrappers.
Tree-SHA512: fd9ccdd08a3af3aa9431eef29e17da0d785c7fe57fd0bfc9a6afdd979dc8860f4f9f0153ba3bb4b516cdec7ef0e071b846fddc1f2d28395cbe9356d2e9c55fb7
6751a323c0 iwyu: Fix warnings in `src/bench` and treat them as error (Hennadii Stepanov)
a6ed29d6c2 bench, refactor: Use `std::string_view` for `BenchRunner` ctor parameter (Hennadii Stepanov)
Pull request description:
This PR addresses [this](https://github.com/bitcoin/bitcoin/pull/35011#discussion_r3323359707) comment:
> I had the impression I already fixed bench in https://github.com/bitcoin/bitcoin/pull/30716 two years ago, but I guess it isn't yet enforced.
>
> Could do that as a next step?
The first two commits act as prerequisites. See the commit messages for details.
The third commit additionally ensures that our drop-in header replacements are used instead of system headers:
- `util/check.h`:10dfdd4b9f/src/util/check.h (L11-L13)
- `util/time.h`:10dfdd4b9f/src/util/time.h (L9-L10)
ACKs for top commit:
maflcko:
re-ACK 6751a323c0📃
BrandonOdiwuor:
ACK 6751a323c0
Tree-SHA512: 159ee734a83dcba3c914682be4b119549e1e4269a43d34c52903e76056d537a2ae02c2f5f4e3adff1b4230082b8ed267c04164abc83b16f717b34fba6e03e359
fab52281f7 refactor: Drop unused includes after iwyu CI bump (MarcoFalke)
fa4774d032 ci: Bump APT_LLVM_V-based task configs to Ubuntu 26.04 (MarcoFalke)
fa1414a36a ci: Debian Trixie -> Ubuntu 26.04 (MarcoFalke)
Pull request description:
This is for the upcoming 32.x, because I presume users and devs are more likely using a later distro. This comes with tool bumps, such as:
* GCC 14 -> 15 (https://packages.debian.org/trixie/g++ -> https://packages.ubuntu.com/resolute/g++)
* Clang 19 -> 21
* Cmake 3.31 -> 4.2
* Valgrind 3.24 -> 3.26
ACKs for top commit:
l0rinc:
code review ACK fab52281f7
hebasto:
re-ACK fab52281f7.
Tree-SHA512: 9d5be2f5b15cf7904c50687ce5e8cceeb2f740c7d5180190d6a10e751998ce2c2156098f89352eac49f24c8cd9ab55b78321e310240ac829dcbe48b576b6240c