p2p: add DifferenceFormatter fuzz target and invariant check #33252

pull frankomosh wants to merge 2 commits into bitcoin:master from frankomosh:fuzz-differenceFormatter changing 3 files +38 −0
  1. frankomosh commented at 3:58 am on August 25, 2025: none

    Adds a fuzz test for the DifferenceFormatter (used in BlockTransactionsRequest, BIP 152). The DifferenceFormatter class implements differential encoding for compact block transactions (BIP 152). This PR ensures that its strictly-monotonic property is maintained. It complements the tests in blocktransactionsrequest_deserialize.

    Additionally, there’s an added invariant check after GETBLOCKTXN deserialization in net_processing.cpp.

  2. DrahtBot added the label Tests on Aug 25, 2025
  3. DrahtBot commented at 3:58 am on August 25, 2025: contributor

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

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33252.

    Reviews

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

  4. frankomosh marked this as a draft on Aug 25, 2025
  5. DrahtBot added the label CI failed on Aug 25, 2025
  6. DrahtBot commented at 4:58 am on August 25, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/runs/48785229557 LLM reason (✨ experimental): The CI failure is caused by a lint check error related to missing a trailing newline in ‘src/test/fuzz/difference_formatter.cpp’.

    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.

  7. maflcko commented at 5:32 am on August 25, 2025: member

    @frankomosh Is this LLM generated?

    edit: I assumed yes, based on #33038 (comment)

  8. maflcko commented at 6:32 am on August 25, 2025: member

    Thanks, but the value of purely LLM generated “vibe” pull requests is limited, because:

    • The “author” does not understand the changes and can not reply to code review feedback.
    • There are more than 300 pull requests (most written by real humans) waiting for review.
    • Incentive to review purely LLM generated changes is limited, because the feedback likely does not help to train a real human planning to contribute in the future, but is likely only passed on to an LLM api.

    Also, specifically here:

    • The added P2P assert is not fuzz-only related (it will be run in production as well)
    • src/test/fuzz/CMakeLists.txt isn’t sorted
    • src/test/fuzz/difference_formatter.cpp is missing the copyright header (I guess the llm was trained on removing copyright headers)
    • The fuzz target FUZZ_TARGET(difference_formatter) doesn’t add any new code coverage (this point was also already explained to you in your previous attempt at adding a fuzz target)
    • For a trivial serialization roundrip, you can just use the existing ./src/test/fuzz/deserialize.cpp framework.
    • The CI (lint) doesn’t pass.

    So I’ll close this for now. My recommendation for the future would be to create your first pull request fully by yourself. This will hopefully ensure that you understand the changes yourself and can reply to feedback.

    ( Generally, I think it is fine to use LLMs, if the author would have written the same code almost exactly the same way without the LLM, and also fully understands it, and also can claim copyright on it. But this is probably a meta discussion. )

  9. maflcko closed this on Aug 25, 2025

  10. maflcko commented at 7:14 am on August 25, 2025: member
    Re-opening, based on request by @dergoegge
  11. maflcko reopened this on Aug 25, 2025

  12. in src/net_processing.cpp:4142 in 358ad3f7df outdated
    4134@@ -4135,6 +4135,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
    4135     if (msg_type == NetMsgType::GETBLOCKTXN) {
    4136         BlockTransactionsRequest req;
    4137         vRecv >> req;
    4138+        // Verify differential encoding invariant: indexes must be strictly increasing
    4139+        // DifferenceFormatter should guarantee this property during deserialization
    4140+        for (size_t i = 1; i < req.indexes.size(); ++i) {
    4141+            assert(req.indexes[i] > req.indexes[i-1]);
    4142+        }
    


    maflcko commented at 7:16 am on August 25, 2025:
    in 358ad3f7df44e2715b69e80fc973e4f55517a67c: This is not around “validation”, the commit title should start with “p2p” and the pull request title as well. (This code is run in production, not only during fuzz tests)

    frankomosh commented at 9:45 am on August 25, 2025:
    Ok. I’ll change this

    brunoerg commented at 4:35 pm on August 26, 2025:
    Stiil needs to update the PR title.

    frankomosh commented at 6:06 pm on August 26, 2025:
    @brunoerg changed. Please let me know if you’d still like to see any wording tweaks?
  13. in src/test/fuzz/CMakeLists.txt:136 in 358ad3f7df outdated
    132@@ -133,6 +133,7 @@ add_executable(fuzz
    133   validation_load_mempool.cpp
    134   vecdeque.cpp
    135   versionbits.cpp
    136+  difference_formatter.cpp
    


    maflcko commented at 7:16 am on August 25, 2025:
    nit: pls sort
  14. in src/test/fuzz/difference_formatter.cpp:15 in 358ad3f7df outdated
    0@@ -0,0 +1,57 @@
    1+#include <blockencodings.h>
    2+#include <streams.h>
    3+#include <test/fuzz/FuzzedDataProvider.h>
    4+#include <test/fuzz/fuzz.h>
    5+
    6+#include <vector>
    7+
    8+namespace {
    9+struct TestDifferenceFormatterType {
    


    maflcko commented at 7:17 am on August 25, 2025:
    nit: should have a comment to be based on BlockTransactionsRequest?

    maflcko commented at 7:19 am on August 25, 2025:
    an alternative would be to directly use BlockTransactionsRequest and provide a dummy uint256 in fuzz code (filled into the bytes)

    frankomosh commented at 10:04 am on August 25, 2025:
    thought it better to use this format because it is more focused toward testing the differential encoding logic. perhaps a comment(as you suggested) would do?

    maflcko commented at 6:31 am on August 29, 2025:

    It is less code this way:

     0diff --git a/src/test/fuzz/difference_formatter.cpp b/src/test/fuzz/difference_formatter.cpp
     1index 49e859ffdc..38b54352c1 100644
     2--- a/src/test/fuzz/difference_formatter.cpp
     3+++ b/src/test/fuzz/difference_formatter.cpp
     4@@ -4,25 +4,13 @@
     5 
     6 #include <blockencodings.h>
     7 #include <streams.h>
     8-#include <test/fuzz/FuzzedDataProvider.h>
     9+#include <random.h>
    10 #include <test/fuzz/fuzz.h>
    11 
    12 #include <vector>
    13 
    14 namespace {
    15-// Test struct for VectorFormatter<DifferenceFormatter>
    16-// Used in BlockTransactionsRequest
    17-struct TestDifferenceFormatterType {
    18-    std::vector<uint16_t> indexes;
    19-
    20-    SERIALIZE_METHODS(TestDifferenceFormatterType, obj) {
    21-        READWRITE(Using<VectorFormatter<DifferenceFormatter>>(obj.indexes));
    22-    }
    23-};
    24-
    25 void VerifyDifferenceFormatterInvariants(const std::vector<uint16_t>& indexes) {
    26-    if (indexes.empty()) return;
    27-
    28     // Core invariant: strictly monotonic increasing (no duplicates allowed)
    29     for (size_t i = 1; i < indexes.size(); ++i) {
    30         assert(indexes[i] > indexes[i-1]); // Must be STRICTLY greater
    31@@ -32,15 +20,15 @@ void VerifyDifferenceFormatterInvariants(const std::vector<uint16_t>& indexes) {
    32 
    33 FUZZ_TARGET(difference_formatter)
    34 {
    35-    FuzzedDataProvider fdp{buffer.data(), buffer.size()};
    36-
    37-    auto random_bytes = fdp.ConsumeRemainingBytes<uint8_t>();
    38-    DataStream ss{random_bytes};
    39+    const auto block_hash = InsecureRandomContext{{}}.rand256();
    40+    DataStream ss{};
    41+    ss << block_hash << std::span{buffer};
    42 
    43     // Test deserialization
    44     try {
    45-        TestDifferenceFormatterType test_container;
    46+        BlockTransactionsRequest test_container;
    47         ss >> test_container;
    48+        assert(test_container.blockhash==block_hash);
    49 
    50         // If deserialization succeeded, verify the DifferenceFormatter invariants
    51         VerifyDifferenceFormatterInvariants(test_container.indexes);
    52@@ -48,5 +36,4 @@ FUZZ_TARGET(difference_formatter)
    53     } catch (const std::ios_base::failure&) {
    54         // Expected for malformed input
    55     }
    56-
    57 }
    

    Other changes include:

    • No need to copy the full buffer twice (FuzzedDataProvider and DataStream)
    • Remove not needed indexes.empty() check

    frankomosh commented at 7:22 am on August 29, 2025:
    I think this is more cleaner and simpler to follow. thanks
  15. in src/test/fuzz/difference_formatter.cpp:36 in 358ad3f7df outdated
    31+    // Arbitrary stream data
    32+    DataStream ss{};
    33+    auto random_bytes = fdp.ConsumeRemainingBytes<uint8_t>();
    34+    for (uint8_t byte : random_bytes) {
    35+        ss << byte;
    36+    }
    


    maflcko commented at 7:18 am on August 25, 2025:
    nit: There is no need to serialize single bytes. You can just pass the vector into the DataStream constructor
  16. maflcko commented at 7:20 am on August 25, 2025: member
    (left my previous comment as in-line review comments)
  17. frankomosh closed this on Aug 25, 2025

  18. frankomosh reopened this on Aug 25, 2025

  19. frankomosh commented at 9:15 am on August 25, 2025: none
    @maflcko sorry for not being able to reply soon, that was because I was away from my computer. And no, it is not LLM generated code, I have been working on it for a while now.
  20. frankomosh commented at 9:16 am on August 25, 2025: none

    Thanks, but the value of purely LLM generated “vibe” pull requests is limited, because:

    • The “author” does not understand the changes and can not reply to code review feedback.
    • There are more than 300 pull requests (most written by real humans) waiting for review.
    • Incentive to review purely LLM generated changes is limited, because the feedback likely does not help to train a real human planning to contribute in the future, but is likely only passed on to an LLM api.

    Also, specifically here:

    • The added P2P assert is not fuzz-only related (it will be run in production as well)
    • src/test/fuzz/CMakeLists.txt isn’t sorted
    • src/test/fuzz/difference_formatter.cpp is missing the copyright header (I guess the llm was trained on removing copyright headers)
    • The fuzz target FUZZ_TARGET(difference_formatter) doesn’t add any new code coverage (this point was also already explained to you in your previous attempt at adding a fuzz target)
    • For a trivial serialization roundrip, you can just use the existing ./src/test/fuzz/deserialize.cpp framework.
    • The CI (lint) doesn’t pass.

    So I’ll close this for now. My recommendation for the future would be to create your first pull request fully by yourself. This will hopefully ensure that you understand the changes yourself and can reply to feedback.

    ( Generally, I think it is fine to use LLMs, if the author would have written the same code almost exactly the same way without the LLM, and also fully understands it, and also can claim copyright on it. But this is probably a meta discussion. )

    I will work to resolve the issues you raised as soon as I can please

  21. frankomosh force-pushed on Aug 25, 2025
  22. frankomosh renamed this:
    fuzz: add target for `DifferenceFormatter` and invariant check in `net_processing.cpp`
    fuzz: add target for `DifferenceFormatter` and p2p invariant check
    on Aug 25, 2025
  23. frankomosh commented at 1:16 pm on August 25, 2025: none
    dropped the serialization roundrip as @maflcko suggests, they can be done elsewhere (./src/test/fuzz/deserialize.cpp).
  24. DrahtBot removed the label CI failed on Aug 25, 2025
  25. frankomosh marked this as ready for review on Aug 25, 2025
  26. frankomosh renamed this:
    fuzz: add target for `DifferenceFormatter` and p2p invariant check
    add `DifferenceFormatter` fuzz target and p2p invariant check
    on Aug 26, 2025
  27. frankomosh renamed this:
    add `DifferenceFormatter` fuzz target and p2p invariant check
    p2p: add `DifferenceFormatter` fuzz target and invariant check
    on Aug 26, 2025
  28. in src/test/fuzz/CMakeLists.txt:136 in adfbeb3193 outdated
    133@@ -133,7 +134,6 @@ add_executable(fuzz
    134   validation_load_mempool.cpp
    135   vecdeque.cpp
    136   versionbits.cpp
    137-  difference_formatter.cpp
    


    maflcko commented at 9:33 am on August 28, 2025:
    this is the wrong commit. You’ll have to apply the patch to the correct commit.

    frankomosh commented at 10:41 am on August 28, 2025:
    okey. Will sort it out
  29. frankomosh force-pushed on Aug 28, 2025
  30. frankomosh force-pushed on Aug 29, 2025
  31. frankomosh force-pushed on Aug 29, 2025
  32. frankomosh commented at 11:04 am on August 29, 2025: none
    For commit b5c3a72, updated fuzz/difference_formatter.cpp to directly use BlockTransactionsRequest
  33. frankomosh force-pushed on Aug 29, 2025
  34. in src/net_processing.cpp:4141 in 9f628d59f8 outdated
    4134@@ -4135,6 +4135,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
    4135     if (msg_type == NetMsgType::GETBLOCKTXN) {
    4136         BlockTransactionsRequest req;
    4137         vRecv >> req;
    4138+        // Verify differential encoding invariant: indexes must be strictly increasing
    4139+        // DifferenceFormatter should guarantee this property during deserialization
    4140+        for (size_t i = 1; i < req.indexes.size(); ++i) {
    4141+            assert(req.indexes[i] > req.indexes[i-1]);
    


    dergoegge commented at 8:09 am on September 1, 2025:
    0            Assume(req.indexes[i] > req.indexes[i-1]);
    

    Just so the assertion isn’t active in release builds


    frankomosh commented at 4:18 am on September 2, 2025:
    yes. thanks
  35. in src/test/fuzz/difference_formatter.cpp:17 in 9f628d59f8 outdated
    12+namespace {
    13+void VerifyDifferenceFormatterInvariants(const std::vector<uint16_t>& indexes) {
    14+    // Core invariant: strictly monotonic increasing (no duplicates allowed)
    15+    for (size_t i = 1; i < indexes.size(); ++i) {
    16+        assert(indexes[i] > indexes[i-1]); // Must be STRICTLY greater
    17+    }
    


    dergoegge commented at 8:10 am on September 1, 2025:
    The two comments are saying the same thing, I’d suggest to just keep one
  36. in src/test/fuzz/difference_formatter.cpp:34 in 9f628d59f8 outdated
    29+        BlockTransactionsRequest test_container;
    30+        ss >> test_container;
    31+        assert(test_container.blockhash == block_hash);
    32+
    33+        // If deserialization succeeded, verify the DifferenceFormatter invariants
    34+        VerifyDifferenceFormatterInvariants(test_container.indexes);
    


    dergoegge commented at 8:11 am on September 1, 2025:
    There’s only one invariant we’re checking, perhaps we don’t need the function?

    frankomosh commented at 4:17 am on September 2, 2025:
    Had only kept it for readability, but yes we can definately do without it
  37. dergoegge changes_requested
  38. frankomosh force-pushed on Sep 2, 2025
  39. fuzz: add a target for DifferenceFormatter Class
    Add fuzz test to verify that arbitrary input successfully deserialized
    by DifferenceFormatter will maintain the sorted-without-duplicates invariant.
    58be359f6b
  40. p2p: add assertion for BlockTransactionsRequest indexes
    Adds assert() check in net_processing after deserialization and validate DifferenceFormatter Class invariants.
    7a6b3b4ebf
  41. frankomosh force-pushed on Sep 2, 2025
  42. frankomosh requested review from maflcko on Sep 2, 2025
  43. frankomosh requested review from brunoerg on Sep 2, 2025
  44. frankomosh requested review from dergoegge on Sep 2, 2025

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: 2025-09-02 06:12 UTC

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