bench: add script verification benchmark for P2TR script-path spends #35038

pull theStack wants to merge 2 commits into bitcoin:master from theStack:202604-bench_add_script_verify_p2tr_scriptspend changing 1 files +39 −15
  1. theStack commented at 3:20 PM on April 9, 2026: contributor

    Similarly as #34472 already did for key-path spends, this PR adds a benchmark for P2TR script-path spends. So far we don't have a benchmark on master yet that exercises the verification of taproot commitments (VerifyTaprootCommitment).

    Note that the tapscript leaf intentionally includes a single OP_CHECKSIG as it likely reflects the real world best. Spending tapscript leafs without any signature checks don't make much sense (they could be trivially tampered with and thus stolen by miners), and doing more than one signature check seems the exception rather than the rule.

    The primary motivation for this PR is to evaluate how potential secp256k1 changes in pubkey tweaking (e.g. #1843) may impact script verification performance.

  2. DrahtBot added the label Tests on Apr 9, 2026
  3. DrahtBot commented at 3:20 PM on April 9, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK l0rinc, davidgumberg, sedited

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #32876 (refactor: use options struct for signing and PSBT operations by Sjors)
    • #32857 (wallet: allow skipping script paths by Sjors)

    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. in src/bench/verify_script.cpp:86 in ba3cf01781
      81 | +        assert(false);
      82 | +    }()};
      83 | +    assert(txSpend.vin[0].scriptWitness.stack.size() == expected_wit_count);
      84 | +
      85 |      // Benchmark.
      86 |      bench.run([&] {
    


    davidgumberg commented at 1:41 AM on April 10, 2026:

    nit: while touching this area:

        bench.unit("script").run([&] {
    

    theStack commented at 7:56 PM on April 13, 2026:

    Thanks, done.

  5. davidgumberg commented at 1:45 AM on April 10, 2026: contributor

    crACK https://github.com/bitcoin/bitcoin/pull/35038/commits/ba3cf017819177d6517292c200db7991c4371746

    ./build/bin/bench_bitcoin --filter="VerifyScript.*"
    

    | ns/script | script/s | err% | ins/script | cyc/script | IPC | bra/script | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 20,238.11 | 49,411.73 | 0.2% | 467,600.47 | 86,770.69 | 5.389 | 4,548.08 | 0.0% | 0.01 | VerifyScriptP2TR_KeyPath | 36,073.54 | 27,721.15 | 0.1% | 846,768.85 | 154,685.88 | 5.474 | 9,090.15 | 0.2% | 0.01 | VerifyScriptP2TR_ScriptPath | 20,260.06 | 49,358.19 | 0.3% | 459,586.47 | 86,832.23 | 5.293 | 5,805.08 | 0.1% | 0.01 | VerifyScriptP2WPKH


    Feel free to disregard as out-of-scope, but maybe while touching this file anyways would be nice to use new setup api introduced in #34208 for the nested if script benchmark:

    -    bench.run([&] {
    -        auto stack_copy = stack;
    +    bench.unit("script").epochIterations(1).setup([&] {
    +        stack = {};
    +    }).run([&] {
             ScriptError error;
    -        bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
    +        bool ret = EvalScript(stack, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
             assert(ret);
         });
     }
    

    on master:

    | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 19,890.59 | 50,275.02 | 1.3% | 673,992.65 | 85,238.74 | 7.907 | 143,404.89 | 0.0% | 0.01 | VerifyNestedIfScript

    vs this diff:

    | ns/script | script/s | err% | ins/script | cyc/script | IPC | bra/script | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 12,089.00 | 82,719.83 | 0.4% | 375,703.00 | 51,987.00 | 7.227 | 69,249.00 | 0.2% | 0.00 | VerifyNestedIfScript

  6. theStack force-pushed on Apr 13, 2026
  7. theStack commented at 8:02 PM on April 13, 2026: contributor

    Feel free to disregard as out-of-scope, but maybe while touching this file anyways would be nice to use new setup api introduced in #34208 for the nested if script benchmark:

    Was a bit on the fence about whether to include in this PR or not (strictly speaking it's not directly related, I guess), but decided for it as it's simple enough and a nice improvement. Added a commit under your name with the before/after benchmark output in the commit body. If others feel strongly, the commit could be moved to a separate PR and discussed there.

    (fwiw, I probably would have preferred stack.clear(), but it doesn't really matter).

  8. davidgumberg commented at 8:32 PM on April 13, 2026: contributor

    reACK https://github.com/bitcoin/bitcoin/pull/35038/commits/37d36833d9f50549b4680da1f3818bb762a4c873

    Reviewed the trivial diff since last ACK,:

    <details>

    <summary>

    git range-diff ba3cf0178...37d36833

    </summary>

    1:  ba3cf01781 ! 1:  205c858891 bench: add script verification benchmark for P2TR script-path spends
        @@ Commit message
             To reflect the likely most common real-world scenario, a single
             OP_CHECKSIG is contained in the Tapscript leaf.
         
        +    While touching this benchmark, also set the operation unit to "script".
        +
        +    Co-authored-by: David Gumberg <davidzgumberg@gmail.com>
        +
          ## src/bench/verify_script.cpp ##
         @@
          
        @`@ src/bench/verify_script.cpp: static void VerifyScriptBench(benchmark::Bench& ben
         +    assert(txSpend.vin[0].scriptWitness.stack.size() == expected_wit_count);
         +
              // Benchmark.
        -     bench.run([&] {
        +-    bench.run([&] {
        ++    bench.unit("script").run([&] {
                  ScriptError err;
        +         bool success = VerifyScript(
        +             txSpend.vin[0].scriptSig,
         @@ src/bench/verify_script.cpp: static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
          }
          
    -:  ---------- > 2:  37d36833d9 bench: improve `VerifyNestedIfScript` benchmark precision (make stack clearing untimed)
    

    </details>

    Github: https://github.com/bitcoin/bitcoin/compare/ba3cf017819177d6517292c200db7991c4371746..37d36833d9f50549b4680da1f3818bb762a4c873


    I agree that stack.clear() is better, happy to re-ACK if you want to push that.

  9. theStack force-pushed on Apr 13, 2026
  10. theStack commented at 9:22 PM on April 13, 2026: contributor

    I agree that stack.clear() is better, happy to re-ACK if you want to push that.

    Done :ok_hand:

  11. in src/bench/verify_script.cpp:75 in 205c858891
      70 | @@ -62,8 +71,19 @@ static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
      71 |          txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]});
      72 |      }
      73 |  
      74 | +    // Weak sanity check on witness data to ensure we produced the intended spending type
      75 | +    const auto expected_wit_count{[&]() -> size_t {
    


    l0rinc commented at 7:59 AM on April 14, 2026:

    205c858 bench: add script verification benchmark for P2TR script-path spends:

    This looks like an extension of the enum, so we could reduce the noise in this already complicated method by moving it closer to the source. Modifying ScriptType should likely also require updating WitnessElementCount:

    enum class ScriptType {
        P2WPKH, // segwitv0, witness-pubkey-hash (ECDSA signature)
        P2TR_KeyPath, // segwitv1, taproot key-path spend (Schnorr signature)
        P2TR_ScriptPath, // segwitv1, taproot script-path spend (Tapscript leaf with a single OP_CHECKSIG)
    };
    
    static size_t WitnessElementCount(ScriptType script_type)
    {
        switch (script_type) {
        case ScriptType::P2WPKH: return 2; // [pubkey, signature]
        case ScriptType::P2TR_KeyPath: return 1; // [signature]
        case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]
        } // no default case, so the compiler can warn about missing cases
        assert(false);
    }
    

    This would also let us validate the witness shape before calling txdata.Init(), something like:

        // Sign spending transaction, precompute transaction data
        PrecomputedTransactionData txdata;
        {
            const std::map<COutPoint, Coin> coins{{txSpend.vin[0].prevout, Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false)}};
            std::map<int, bilingual_str> input_errors;
            assert(SignTransaction(txSpend, &keystore, coins, SIGHASH_ALL, input_errors));
            assert(txSpend.vin[0].scriptWitness.stack.size() == WitnessElementCount(script_type));
            txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]});
        }
    

    I also inlined bool complete = SignTransaction(...) since other usages in the codebase look like that.


    nit: if you decide to keep it, is wit a commonly used abbreviation?

        const auto expected_witness_count{[&]() -> size_t {
    

    theStack commented at 12:01 PM on April 14, 2026:

    Makes sense to have an extra function for that closer to the enum and do the check right after signing. Done.

    nit: if you decide to keep it, is wit a commonly used abbreviation?

    There are a handful of instances (see e.g. $ git grep " wit_.*;"), but probably not really widespread. I agree it's preferred to be explicit.

  12. in src/bench/verify_script.cpp:123 in c4b4212be0
     121 | +    }).run([&] {
     122 |          ScriptError error;
     123 | -        bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
     124 | +        bool ret = EvalScript(stack, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
     125 |          assert(ret);
     126 |      });
    


    l0rinc commented at 8:13 AM on April 14, 2026:

    c4b4212 bench: improve VerifyNestedIfScript benchmark precision (make stack clearing untimed):

    We could inline the EvalScript call here to avoid one level of indirection and enable an extra assertion. As DrahtBot noted, we could also add a type hint for the literal: /*flags=*/0.

        bench.unit("script").epochIterations(1)
            .setup([&] { stack.clear(); })
            .run([&] {
                ScriptError error;
                ScriptExecutionData execdata;
                const bool ret{EvalScript(stack, script, /*flags=*/0, BaseSignatureChecker(), SigVersion::BASE, execdata, &error)};
                assert(ret && error == SCRIPT_ERR_OK && !execdata.m_validation_weight_left_init);
            });
    

    theStack commented at 12:02 PM on April 14, 2026:

    Thanks, done. Didn't add the m_validation_weight_left_init check though, as it seemed too script-interpreter-internal and thus out of scope for me for a benchmark. If we want to add it, I think it would need a dedicated comment on what it really verifies (IIUC, checking that this is not a P2TR script-path execution, as that's the only place I could find where it's set to true?).

  13. in src/bench/verify_script.cpp:48 in 205c858891
      44 | @@ -44,7 +45,15 @@ static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
      45 |      const auto dest{[&]() -> CTxDestination {
      46 |          switch (script_type) {
      47 |          case ScriptType::P2WPKH: return WitnessV0KeyHash(pubkey);
      48 | -        case ScriptType::P2TR: return WitnessV1Taproot(XOnlyPubKey{pubkey});
      49 | +        case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(XOnlyPubKey{pubkey});
    


    l0rinc commented at 8:23 AM on April 14, 2026:

    205c858 bench: add script verification benchmark for P2TR script-path spends:

    We could extract the duplicate XOnlyPubKey{pubkey} now that we need it in multiple places:

        CPubKey pubkey = privkey.GetPubKey();
        XOnlyPubKey xonly_pubkey{pubkey};
        CKeyID key_id = pubkey.GetID();
    

    theStack commented at 12:02 PM on April 14, 2026:

    Done.

  14. l0rinc approved
  15. l0rinc commented at 9:01 AM on April 14, 2026: contributor

    Concept ACK

    I left a few suggestions, happy to re-review if you decide to take them.

    <details><summary>All suggestions applied</summary>

    diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
    --- a/src/bench/verify_script.cpp	(revision 530b49c2ddda7b56d0d18b16a0be2b73d4527957)
    +++ b/src/bench/verify_script.cpp	(date 1776157499822)
    @@ -26,6 +26,16 @@
         P2TR_ScriptPath, // segwitv1, taproot script-path spend (Tapscript leaf with a single OP_CHECKSIG)
     };
     
    +static size_t WitnessElementCount(ScriptType script_type)
    +{
    +    switch (script_type) {
    +    case ScriptType::P2WPKH: return 2; // [pubkey, signature]
    +    case ScriptType::P2TR_KeyPath: return 1; // [signature]
    +    case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]
    +    } // no default case, so the compiler can warn about missing cases
    +    assert(false);
    +}
    +
     // Microbenchmark for verification of standard scripts.
     static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
     {
    @@ -35,6 +45,7 @@
         CKey privkey;
         privkey.Set(uint256::ONE.begin(), uint256::ONE.end(), /*fCompressedIn=*/true);
         CPubKey pubkey = privkey.GetPubKey();
    +    XOnlyPubKey xonly_pubkey{pubkey};
         CKeyID key_id = pubkey.GetID();
     
         FlatSigningProvider keystore;
    @@ -45,13 +56,12 @@
         const auto dest{[&]() -> CTxDestination {
             switch (script_type) {
             case ScriptType::P2WPKH: return WitnessV0KeyHash(pubkey);
    -        case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(XOnlyPubKey{pubkey});
    +        case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(xonly_pubkey);
             case ScriptType::P2TR_ScriptPath:
                 TaprootBuilder builder;
    -            CScript tapscript = CScript() << ToByteVector(XOnlyPubKey{pubkey}) << OP_CHECKSIG;
    -            builder.Add(0, tapscript, TAPROOT_LEAF_TAPSCRIPT);
    +            builder.Add(0, CScript() << ToByteVector(xonly_pubkey) << OP_CHECKSIG, TAPROOT_LEAF_TAPSCRIPT);
                 builder.Finalize(XOnlyPubKey::NUMS_H); // effectively unspendable key-path
    -            const auto output = builder.GetOutput();
    +            const auto output{builder.GetOutput()};
                 keystore.tr_trees.emplace(output, builder);
                 return output;
             } // no default case, so the compiler can warn about missing cases
    @@ -63,25 +73,13 @@
         // Sign spending transaction, precompute transaction data
         PrecomputedTransactionData txdata;
         {
    -        std::map<COutPoint, Coin> coins;
    -        coins[txSpend.vin[0].prevout] = Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false);
    +        const std::map<COutPoint, Coin> coins{{txSpend.vin[0].prevout, Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false)}};
             std::map<int, bilingual_str> input_errors;
    -        bool complete = SignTransaction(txSpend, &keystore, coins, SIGHASH_ALL, input_errors);
    -        assert(complete);
    +        assert(SignTransaction(txSpend, &keystore, coins, SIGHASH_ALL, input_errors));
    +        assert(txSpend.vin[0].scriptWitness.stack.size() == WitnessElementCount(script_type));
             txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]});
         }
     
    -    // Weak sanity check on witness data to ensure we produced the intended spending type
    -    const auto expected_wit_count{[&]() -> size_t {
    -        switch (script_type) {
    -        case ScriptType::P2WPKH:          return 2; // [pubkey, signature]
    -        case ScriptType::P2TR_KeyPath:    return 1; // [signature]
    -        case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]
    -        } // no default case, so the compiler can warn about missing cases
    -        assert(false);
    -    }()};
    -    assert(txSpend.vin[0].scriptWitness.stack.size() == expected_wit_count);
    -
         // Benchmark.
         bench.unit("script").run([&] {
             ScriptError err;
    @@ -114,13 +112,14 @@
         for (int i = 0; i < 100; ++i) {
             script << OP_ENDIF;
         }
    -    bench.unit("script").epochIterations(1).setup([&] {
    -        stack.clear();
    -    }).run([&] {
    -        ScriptError error;
    -        bool ret = EvalScript(stack, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
    -        assert(ret);
    -    });
    +    bench.unit("script").epochIterations(1)
    +        .setup([&] { stack.clear(); })
    +        .run([&] {
    +            ScriptError error;
    +            ScriptExecutionData execdata;
    +            const bool ret{EvalScript(stack, script, /*flags=*/0, BaseSignatureChecker(), SigVersion::BASE, execdata, &error)};
    +            assert(ret && error == SCRIPT_ERR_OK && !execdata.m_validation_weight_left_init);
    +        });
     }
     
     BENCHMARK(VerifyScriptP2WPKH);
    
    

    </details>

  16. bench: add script verification benchmark for P2TR script-path spends
    To reflect the likely most common real-world scenario, a single
    OP_CHECKSIG is contained in the Tapscript leaf.
    
    While touching this benchmark, also set the operation unit to "script"
    and do some minor refactorings to deduplicate code and improve readability.
    
    Co-authored-by: David Gumberg <davidzgumberg@gmail.com>
    Co-authored-by: Lőrinc <pap.lorinc@gmail.com>
    616ee6fe74
  17. bench: improve `VerifyNestedIfScript` benchmark precision (make stack clearing untimed)
    on `master`:
    
    |               ns/op |                op/s |    err% |          ins/op |          cyc/op |    IPC |         bra/op |   miss% |     total | benchmark
    |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
    |           19,890.59 |           50,275.02 |    1.3% |      673,992.65 |       85,238.74 |  7.907 |     143,404.89 |    0.0% |      0.01 | `VerifyNestedIfScript`
    
    vs this commit:
    
    |           ns/script |            script/s |    err% |      ins/script |      cyc/script |    IPC |     bra/script |   miss% |     total | benchmark
    |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
    |           12,089.00 |           82,719.83 |    0.4% |      375,703.00 |       51,987.00 |  7.227 |      69,249.00 |    0.2% |      0.00 | `VerifyNestedIfScript`
    
    Co-authored-by: Lőrinc <pap.lorinc@gmail.com>
    fbffe8a64a
  18. theStack force-pushed on Apr 14, 2026
  19. theStack commented at 12:02 PM on April 14, 2026: contributor

    @l0rinc: Thanks for the detailed review, I took most of your suggestions (with only minor naming changes and keeping the "Weak sanity check on witness data..." comment). As it's mostly refactoring changes, it should be simple to re-review.

  20. l0rinc approved
  21. l0rinc commented at 2:08 PM on April 14, 2026: contributor

    ACK fbffe8a64a96ebd46111157fa5381d7c54fe9aea

    Thanks for taking my suggestions and for extending coverage.

  22. DrahtBot requested review from davidgumberg on Apr 14, 2026
  23. davidgumberg commented at 10:03 PM on April 14, 2026: contributor

    reACK fbffe8a

    Reviewed diff since last:

    git diff 37d3683 fbffe8a --color-moved=dimmed-zebra --color-moved-ws=ignore-space-change`
    

    All reasonable refactors and adds a sanity check that error == SCRIPT_ERR_OK.

    <details>

    <summary>

    git diff 37d3683 fbffe8a

    </summary>

    diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
    index bdb614595e..af254ae778 100644
    --- a/src/bench/verify_script.cpp
    +++ b/src/bench/verify_script.cpp
    @@ -26,6 +26,16 @@ enum class ScriptType {
         P2TR_ScriptPath, // segwitv1, taproot script-path spend (Tapscript leaf with a single OP_CHECKSIG)
     };
     
    +static size_t ExpectedWitnessStackSize(ScriptType script_type)
    +{
    +    switch (script_type) {
    +    case ScriptType::P2WPKH: return 2; // [pubkey, signature]
    +    case ScriptType::P2TR_KeyPath: return 1; // [signature]
    +    case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]
    +    } // no default case, so the compiler can warn about missing cases
    +    assert(false);
    +}
    +
     // Microbenchmark for verification of standard scripts.
     static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
     {
    @@ -35,6 +45,7 @@ static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
         CKey privkey;
         privkey.Set(uint256::ONE.begin(), uint256::ONE.end(), /*fCompressedIn=*/true);
         CPubKey pubkey = privkey.GetPubKey();
    +    XOnlyPubKey xonly_pubkey{pubkey};
         CKeyID key_id = pubkey.GetID();
     
         FlatSigningProvider keystore;
    @@ -45,13 +56,12 @@ static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
         const auto dest{[&]() -> CTxDestination {
             switch (script_type) {
             case ScriptType::P2WPKH: return WitnessV0KeyHash(pubkey);
    -        case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(XOnlyPubKey{pubkey});
    +        case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(xonly_pubkey);
             case ScriptType::P2TR_ScriptPath:
                 TaprootBuilder builder;
    -            CScript tapscript = CScript() << ToByteVector(XOnlyPubKey{pubkey}) << OP_CHECKSIG;
    -            builder.Add(0, tapscript, TAPROOT_LEAF_TAPSCRIPT);
    +            builder.Add(0, CScript() << ToByteVector(xonly_pubkey) << OP_CHECKSIG, TAPROOT_LEAF_TAPSCRIPT);
                 builder.Finalize(XOnlyPubKey::NUMS_H); // effectively unspendable key-path
    -            const auto output = builder.GetOutput();
    +            const auto output{builder.GetOutput()};
                 keystore.tr_trees.emplace(output, builder);
                 return output;
             } // no default case, so the compiler can warn about missing cases
    @@ -63,25 +73,16 @@ static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
         // Sign spending transaction, precompute transaction data
         PrecomputedTransactionData txdata;
         {
    -        std::map<COutPoint, Coin> coins;
    -        coins[txSpend.vin[0].prevout] = Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false);
    +        const std::map<COutPoint, Coin> coins{
    +            {txSpend.vin[0].prevout, Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false)}
    +        };
             std::map<int, bilingual_str> input_errors;
    -        bool complete = SignTransaction(txSpend, &keystore, coins, SIGHASH_ALL, input_errors);
    -        assert(complete);
    +        assert(SignTransaction(txSpend, &keystore, coins, SIGHASH_ALL, input_errors));
    +        // Weak sanity check on witness data to ensure we produced the intended spending type
    +        assert(txSpend.vin[0].scriptWitness.stack.size() == ExpectedWitnessStackSize(script_type));
             txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]});
         }
     
    -    // Weak sanity check on witness data to ensure we produced the intended spending type
    -    const auto expected_wit_count{[&]() -> size_t {
    -        switch (script_type) {
    -        case ScriptType::P2WPKH:          return 2; // [pubkey, signature]
    -        case ScriptType::P2TR_KeyPath:    return 1; // [signature]
    -        case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]
    -        } // no default case, so the compiler can warn about missing cases
    -        assert(false);
    -    }()};
    -    assert(txSpend.vin[0].scriptWitness.stack.size() == expected_wit_count);
    -
         // Benchmark.
         bench.unit("script").run([&] {
             ScriptError err;
    @@ -114,13 +115,13 @@ static void VerifyNestedIfScript(benchmark::Bench& bench)
         for (int i = 0; i < 100; ++i) {
             script << OP_ENDIF;
         }
    -    bench.unit("script").epochIterations(1).setup([&] {
    -        stack = {};
    -    }).run([&] {
    -        ScriptError error;
    -        bool ret = EvalScript(stack, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
    -        assert(ret);
    -    });
    +    bench.unit("script").epochIterations(1)
    +        .setup([&] { stack.clear(); })
    +        .run([&] {
    +            ScriptError error;
    +            const bool ret{EvalScript(stack, script, /*flags=*/0, BaseSignatureChecker(), SigVersion::BASE, &error)};
    +            assert(ret && error == SCRIPT_ERR_OK);
    +        });
     }
     
     BENCHMARK(VerifyScriptP2WPKH);
    

    </details>

  24. sedited approved
  25. sedited commented at 9:53 AM on April 19, 2026: contributor

    ACK fbffe8a64a96ebd46111157fa5381d7c54fe9aea

  26. sedited merged this on Apr 19, 2026
  27. sedited closed this on Apr 19, 2026

  28. theStack deleted the branch on Apr 19, 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-05-02 06:12 UTC

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