test: Add test coverage for `PartiallySignedTransaction::Merge()` #36224

pull nebula-21 wants to merge 3 commits into bitcoin:master from nebula-21:merge-psbt-coverage changing 1 files +96 −0
  1. nebula-21 commented at 11:24 PM on September 10, 2026: contributor

    This PR adds test coverage for PartiallySignedTransaction::Merge() divided into 3 tests:

    1.Commit 0d21098e27dff9dc930a1d1ce9f72d82f37aef89 only merge PSBTs with same version: Lines (46-47) have no coverage prior to this PR. The test can be triggered with this mutant as an example:

    <details> <summary>Diff</summary>

    diff --git a/src/psbt.cpp b/src/psbt.cpp
    index 51fb19591a..cf5eef0089 100644
    --- a/src/psbt.cpp
    +++ b/src/psbt.cpp
    @@ -43,7 +43,7 @@ bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt)
             return false;
         }
         if (GetVersion() != psbt.GetVersion()) {
    -        return false;
    +        return true;
         }
    
         for (unsigned int i = 0; i < inputs.size(); ++i) {
    

    </details>

    2.Commit 0aedfc5a5918fae10f26efccdbfc2e332c8ad458 merge PSBT fallback_locktime coverage: Line 56 checks if the psbt has a fallback locktime, if not, it adopts the one from the psbt is merging. Prior to this PR no coverage was provided. The test can be triggered with this mutant as an example:

    <details> <summary>Diff</summary>

    diff --git a/src/psbt.cpp b/src/psbt.cpp
    index 51fb19591a..ce909eb062 100644
    --- a/src/psbt.cpp
    +++ b/src/psbt.cpp
    @@ -53,7 +53,7 @@ bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt)
             outputs[i].Merge(psbt.outputs[i]);
         }
         MergeGlobalXPubs(psbt);
    -    if (fallback_locktime == std::nullopt && psbt.fallback_locktime != std::nullopt) fallback_locktime = psbt.fallback_locktime;
    +    if (fallback_locktime == std::nullopt || psbt.fallback_locktime != std::nullopt) fallback_locktime = psbt.fallback_locktime;
     
         // Set m_tx_modifiable only if either PSBT had it set
         if (m_tx_modifiable.has_value() || psbt.m_tx_modifiable.has_value()) {
    

    </details>

    While writing this test I had a question: If both PSBTs have a fallback_locktime value, the "this" (receiving side) wins silently. Is this the expected behavior? Why not keep the max or directly fail merging if we have two conflicting fallback_locktimes?

    3.Commit 4a5a082d306d9b4eab4ea9db6643efc307a9e961 merge PSBT m_tx_modifiable coverage: Added missing coverage for all the mutants. The test can be triggered with this mutant as one of the various examples:

    <details> <summary>Diff</summary>

    diff --git a/src/psbt.cpp b/src/psbt.cpp
    index 51fb19591a..29eb910014 100644
    --- a/src/psbt.cpp
    +++ b/src/psbt.cpp
    @@ -56,7 +56,7 @@ bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt)
         if (fallback_locktime == std::nullopt && psbt.fallback_locktime != std::nullopt) fallback_locktime = psbt.fallback_locktime;
     
         // Set m_tx_modifiable only if either PSBT had it set
    -    if (m_tx_modifiable.has_value() || psbt.m_tx_modifiable.has_value()) {
    +    if (m_tx_modifiable.has_value() && psbt.m_tx_modifiable.has_value()) {
             // In general, we AND the modifiable flags
             std::bitset<8> this_modifiable = m_tx_modifiable.value_or(0);
             std::bitset<8> psbt_modifiable = psbt.m_tx_modifiable.value_or(0);
    

    </details>

  2. DrahtBot added the label Tests on Sep 10, 2026
  3. DrahtBot commented at 11:24 PM on September 10, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

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

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #36382 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36382.svg"></sub> (rpc: flag invalid taproot leaf control blocks in decodepsbt by fametrano)
    • #36122 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36122.svg"></sub> (BIP460: CISA for Taproot key path spends by fjahr)
    • #35747 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35747.svg"></sub> (wallet: Fix FillPSBT failing to sign owned inputs when UTXOs disagree by nervana21)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. nebula-21 force-pushed on Sep 10, 2026
  5. DrahtBot added the label CI failed on Sep 10, 2026
  6. DrahtBot commented at 11:33 PM on September 10, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/34542023845/job/103086555994</sub> <sub>LLM reason (✨ experimental): CI failed due to a trailing_whitespace lint check error (trailing space detected in src/test/psbt_tests.cpp).</sub>

    <details><summary>Hints</summary>

    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.

    </details>

  7. DrahtBot removed the label CI failed on Sep 11, 2026
  8. sedited requested review from polespinasa on Sep 25, 2026
  9. in src/test/psbt_tests.cpp:321 in 0d21098e27
     312 | @@ -313,4 +313,14 @@ BOOST_AUTO_TEST_CASE(update_psbt_output_taproot)
     313 |      }
     314 |  }
     315 |  
     316 | +BOOST_AUTO_TEST_CASE(psbt_merge_only_same_version)
     317 | +{
     318 | +    CMutableTransaction mtx;
     319 | +    PartiallySignedTransaction psbt_v0(mtx, /*version*/0);
     320 | +    PartiallySignedTransaction psbt_v2(mtx, /*version*/2);
     321 | +    BOOST_REQUIRE(*psbt_v0.GetUniqueID() == *psbt_v2.GetUniqueID());
    


    polespinasa commented at 7:56 PM on September 28, 2026:

    in 0d21098e27dff9dc930a1d1ce9f72d82f37aef89 test: only merge PSBTs with same version

        BOOST_REQUIRE(psbt_v0.GetUniqueID() == psbt_v2.GetUniqueID());
    
    
  10. in src/test/psbt_tests.cpp:363 in 4a5a082d30 outdated
     359 | @@ -360,4 +360,43 @@ BOOST_AUTO_TEST_CASE(psbt_merge_fallback_locktime)
     360 |      BOOST_CHECK_EQUAL(*psbt1.fallback_locktime, 21);
     361 |  }
     362 |  
     363 | +BOOST_AUTO_TEST_CASE(psbt_merge_modifiable)
    


    polespinasa commented at 8:00 PM on September 28, 2026:

    in 4a5a082d306d9b4eab4ea9db6643efc307a9e961 test: merge PSBT m_tx_modifiable coverage

    maybe can increase the coverage with positive and case?

    psbt1.m_tx_modifiable.emplace();
    psbt1.m_tx_modifiable->set(0, true);
    psbt1.m_tx_modifiable->set(1, true);
    psbt2.m_tx_modifiable.emplace();
    psbt2.m_tx_modifiable->set(0, true);
    psbt2.m_tx_modifiable->set(1, true);
    BOOST_CHECK(psbt1.Merge(psbt2));
    BOOST_CHECK(psbt1.m_tx_modifiable->test(0) && psbt1.m_tx_modifiable->test(1));
    

    nebula-21 commented at 11:21 AM on October 1, 2026:

    Thanks! I’ve made the change and added you as a co-author.

  11. polespinasa commented at 8:02 PM on September 28, 2026: member

    reviewed 4a5a082d306d9b4eab4ea9db6643efc307a9e961

  12. test: only merge PSBTs with same version 6fc2ebd521
  13. nebula-21 force-pushed on Oct 1, 2026
  14. test: merge PSBT `fallback_locktime` coverage 776fb26375
  15. nebula-21 force-pushed on Oct 1, 2026
  16. nebula-21 force-pushed on Oct 1, 2026
  17. test: merge PSBT `m_tx_modifiable` coverage
    Co-authored-by: polespinasa <pol.espinasa@uab.cat>
    9b78edce89
  18. DrahtBot added the label CI failed on Oct 1, 2026
  19. DrahtBot commented at 11:25 AM on October 1, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/36854851942/job/110344798532</sub> <sub>LLM reason (✨ experimental): CI failed due to a commit_msg lint error: commit subject line (60edcd1ea8…) was not followed by a blank line before the body.</sub>

    <details><summary>Hints</summary>

    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.

    </details>

  20. DrahtBot removed the label CI failed on Oct 1, 2026
  21. sedited requested review from polespinasa on Oct 21, 2026


polespinasa

Labels

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-10-21 21:51 UTC

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