fuzz: Block connection and chain reorganization fuzzing harnesses #34651

pull RobinDavid wants to merge 1 commits into bitcoin:master from RobinDavid:new-fuzz-harness-block-connection changing 3 files +943 −1
  1. RobinDavid commented at 3:25 pm on February 22, 2026: contributor

    Hi Bitcoin Core maintainers.

    This PR is a remastered version of fuzzing harnesses developed during a Bitcoin Core audit. It includes three different fuzzing harnesses which motivation was the following:

    • connect_block: Test the ConnectBlock() function responsible of validating the block and all its transaction with consensus rules. Thanks to justCheck parameter no side effect is performed on the internal state enabling relatively fast fuzzing.
    • activate_best_chain_step: Test the ActivateBestChainStep() function responsible of activating the most worked-chain (not selecting it). The harness is written in a way that enable the fuzzer triggering a chain reorganization if it generates two valid branches.
    • activate_best_chain: Test the ActivateBestChain() function responsible of selecting and activating the most worked-chain.

    In the two later harnesses, some internal state cleaning is required to avoid non-reproducibility issues. Also they might produce file artifacts on disk by means of writing blocks.

    Besides pre-mining blocks, the harness initialization intends to bring a bit more of diversity by introducing additional transactions in blocks (otherwise only coinbases), and put some transactions in the mempool so that they can be ‘picked’ and put in a block by means of input mutation.

    These harnesses enables improving function coverage on ActivateBestChainStep, removeForBlock and to cover function uncovered by fuzzing at the time of fuzzing harness development (mid-2025). Functions newly covered include DisconnectTip, DisconnectBlock, ApplyTxInUndo, MaybeUpdateMempoolForReorg, removeForReorg etc. The attached figure shows in red function previously uncovered. (This might have slightly changed since then).

    We tried to make the implementation as lean as possible but we are eager of any improvement feedbacks.

    Authored by @RobinDavid and @nsurbay

  2. DrahtBot added the label Fuzzing on Feb 22, 2026
  3. DrahtBot commented at 3:26 pm on February 22, 2026: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • +/** Vector of blocks to keep a references on blocks (to enable fuzzing input to pick one to build upon) */ -> “Vector of blocks to keep references to (to enable fuzzing input to pick one to build upon)” [“a references on blocks” is ungrammatical and unclear]
    • +/** Spending script for all UTXOs (excluding OP_RETURN) including not mature CoinBase and already spend one */ -> “Spending script for all UTXOs (excluding OP_RETURN), including not-mature coinbase and already-spent ones” [“not mature CoinBase and already spend one” is ungrammatical]
    • +/** Initialize TAPROOT_OP_TRUE and TAPROOT_OP_TRUE_WITNESS static variable */ -> “Initialize TAPROOT_OP_TRUE and TAPROOT_OP_TRUE_WITNESS static variables” [singular “variable” should be plural]
    • +/** Iterate all transactions outputs */ -> “Iterate all transaction outputs” [word order/possessive is incorrect]
    • +/** Some harnesses want to explicitely read coinbase transactions in input */ -> “Some harnesses want to explicitly read coinbase transactions from the input” [“explicitely” misspelled; “in input” → “from the input”]
    • +/** The content of the CTxIn content is not read from the input per-se */ -> “The content of the CTxIn is not read from the input per se” [duplicated “content”, “per-se” should be “per se”]
    • +/** Enable fuzzer to mutate every CTxIn fields after it being taken from existing UTXOs */ -> “Enable the fuzzer to mutate each CTxIn field after it is taken from existing UTXOs” [grammar: “every … fields” and “after it being taken” are incorrect]
    • +/** For all CTxOut created, create the associated spending script to enable\n * to be spent in later transactions. */ -> “For all CTxOut created, create the associated spending script to enable them to be spent in later transactions” [“enable to be spent” missing object]
    • +/** Read one transaction from the fuzzing input through the FuzzedDataProvider.\n+ * It intend to leave more space to craft complex transactions and especially\n+ * with various scripts types (P2SH, P2WSH, TAPROOT, NOSCRIPT).\n+ * It is exclusively used by ConsumeBlock to read transaction inside a block. */ -> “It intends to leave more space to craft complex transactions, especially with various script types (P2SH, P2WSH, TAPROOT, NOSCRIPT). It is exclusively used by ConsumeBlock to read transactions inside a block.” [“It intend”, “scripts types”, and “read transaction inside a block” are ungrammatical]
    • +/** Create additional transaction in the mempool that are spending\n+ * coins from mature blocks. Otherwise the mined chain only contains\n+ * coinbase transactions. */ -> “Create additional transactions in the mempool that spend coins from mature blocks. Otherwise the mined chain only contains coinbase transactions.” [“transaction” singular and “that are spending” awkward/grammatically off]
    • +/** Search if the block hash already exists, (which the fuzzer duplicated it) */ -> “Search if the block hash already exists (which the fuzzer may have duplicated)” [phrase “which the fuzzer duplicated it” is ungrammatical]
    • +/** If it does not exists write it into the ChainstateManager. */ -> “If it does not exist, write it into the ChainstateManager.” [“does not exists” → “does not exist”]
    • +/** Mark environment as dirty as Block cannot be removed from BlockManager.\n+ * Thus reproducibility purposes make sure the same input will follow same path. */ -> “Mark environment as dirty as the block cannot be removed from the BlockManager. Thus, for reproducibility purposes, ensure the same input will follow the same path.” [second sentence is ungrammatical as written]
    • +/** If it does not exists, write and activate it through AcceptBlock */ -> “If it does not exist, write and activate it through AcceptBlock” [“does not exists” → “does not exist”]

    No other added comment/documentation lines contain typographic errors that render the English invalid or incomprehensible.

    Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):

    • ConnectBlock(block, state, &new_index, active_coins, /* justCheck*/ true) in src/test/fuzz/connect_block.cpp
    • csm.AcceptBlock(std::make_shared(block), state, &blockIndex, true, nullptr, &isNewBlock, true) in src/test/fuzz/connect_block.cpp
    • ConsumeBlock(fuzzed_data_provider, *currentBlock, active_tip->nHeight + 1 + i, additionalUTXO, true) in src/test/fuzz/connect_block.cpp
    • ConsumeBlock(fuzzed_data_provider, *currentBlock, originTip->nHeight + 1 + i, additionalUTXO, true) in src/test/fuzz/connect_block.cpp
    • ConsumeBlock(fuzzed_data_provider, *currentBlock, originTip->nHeight + 1 + i, additionalUTXO, true) in src/test/fuzz/connect_block.cpp

    2026-02-23 22:23:08

  4. DrahtBot added the label CI failed on Feb 22, 2026
  5. DrahtBot commented at 4:12 pm on February 22, 2026: contributor

    🚧 At least one of the CI tasks failed. Task 32 bit ARM: https://github.com/bitcoin/bitcoin/actions/runs/22279929273/job/64448849605 LLM reason (✨ experimental): Compilation failed due to missing system header sys/sdt.h (not found).

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  6. Implement connect_block, activate_best_chain_step and activate_best_chain fuzzing harnesses 28afc49ca0
  7. in src/test/fuzz/connect_block.cpp:1 in 98ad4d8063
    0@@ -0,0 +1,941 @@
    1+// Copyright (c) 2019-2021 The Bitcoin Core developers
    


    brunoerg commented at 7:55 pm on February 23, 2026:
    2021?
  8. RobinDavid force-pushed on Feb 23, 2026
  9. in ci/test/00_setup_env_arm.sh:11 in 28afc49ca0
     7@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
     8 
     9 export HOST=arm-linux-gnueabihf
    10 export DPKG_ADD_ARCH="armhf"
    11-export PACKAGES="python3-zmq g++-arm-linux-gnueabihf libc6:armhf libstdc++6:armhf libfontconfig1:armhf libxcb1:armhf"
    12+export PACKAGES="systemtap-sdt-dev python3-zmq g++-arm-linux-gnueabihf libc6:armhf libstdc++6:armhf libfontconfig1:armhf libxcb1:armhf"
    


    maflcko commented at 10:29 am on February 24, 2026:

    This won’t fix the ci failure. The CI fails because the build system does not add the usdt headers to the fuzz binary. So possible fixes are:

    • Add the headers in the build system to the fuzz binary
    • Copy-paste the connect-trace struct manually into the fuzz target code
    • Something else?
  10. DrahtBot commented at 4:12 pm on March 2, 2026: contributor
    Could turn into draft while CI is red?
  11. RobinDavid marked this as a draft on Mar 2, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-03-03 00:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me