Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2016-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <addresstype.h>6#include <bench/bench.h>7#include <coins.h>8#include <key.h>9#include <policy/policy.h>10#include <primitives/transaction.h>11#include <pubkey.h>12#include <script/interpreter.h>13#include <script/script.h>14#include <script/script_error.h>15#include <script/sign.h>16#include <script/signingprovider.h>17#include <script/verify_flags.h>18#include <span.h>19#include <test/util/transaction_utils.h>20#include <uint256.h>21#include <util/check.h>22#include <util/translation.h>24#include <cstddef>25#include <map>26#include <span>27#include <vector>29enum class ScriptType {30P2WPKH, // segwitv0, witness-pubkey-hash (ECDSA signature)31P2TR_KeyPath, // segwitv1, taproot key-path spend (Schnorr signature)32P2TR_ScriptPath, // segwitv1, taproot script-path spend (Tapscript leaf with a single OP_CHECKSIG)33};35static size_t ExpectedWitnessStackSize(ScriptType script_type)36{37switch (script_type) {38case ScriptType::P2WPKH: return 2; // [pubkey, signature]39case ScriptType::P2TR_KeyPath: return 1; // [signature]40case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]41} // no default case, so the compiler can warn about missing cases42assert(false);43}45// Microbenchmark for verification of standard scripts.46static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)47{48ECC_Context ecc_context{};50// Create deterministic key material needed for output script creation / signing51CKey privkey;52privkey.Set(uint256::ONE.begin(), uint256::ONE.end(), /*fCompressedIn=*/true);53CPubKey pubkey = privkey.GetPubKey();54XOnlyPubKey xonly_pubkey{pubkey};55CKeyID key_id = pubkey.GetID();57FlatSigningProvider keystore;58keystore.keys.emplace(key_id, privkey);59keystore.pubkeys.emplace(key_id, pubkey);61// Create crediting and spending transactions with provided input type62const auto dest{[&]() -> CTxDestination {63switch (script_type) {64case ScriptType::P2WPKH: return WitnessV0KeyHash(pubkey);65case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(xonly_pubkey);66case ScriptType::P2TR_ScriptPath:67TaprootBuilder builder;68builder.Add(0, CScript() << ToByteVector(xonly_pubkey) << OP_CHECKSIG, TAPROOT_LEAF_TAPSCRIPT);69builder.Finalize(XOnlyPubKey::NUMS_H); // effectively unspendable key-path70const auto output{builder.GetOutput()};71keystore.tr_trees.emplace(output, builder);72return output;73} // no default case, so the compiler can warn about missing cases74assert(false);75}()};76const CMutableTransaction& txCredit = BuildCreditingTransaction(GetScriptForDestination(dest), 1);77CMutableTransaction txSpend = BuildSpendingTransaction(/*scriptSig=*/{}, /*scriptWitness=*/{}, CTransaction(txCredit));79// Sign spending transaction, precompute transaction data80PrecomputedTransactionData txdata;81{82const std::map<COutPoint, Coin> coins{83{txSpend.vin[0].prevout, Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false)}84};85std::map<int, bilingual_str> input_errors;86bool complete = SignTransaction(txSpend, &keystore, coins, {.sighash_type = SIGHASH_ALL}, input_errors);87assert(complete);88// Weak sanity check on witness data to ensure we produced the intended spending type89assert(txSpend.vin[0].scriptWitness.stack.size() == ExpectedWitnessStackSize(script_type));90txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]});91}93// Benchmark.94bench.unit("script").run([&] {95ScriptError err;96bool success = VerifyScript(97txSpend.vin[0].scriptSig,98txCredit.vout[0].scriptPubKey,99&txSpend.vin[0].scriptWitness,100STANDARD_SCRIPT_VERIFY_FLAGS,101MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL),102&err);103assert(err == SCRIPT_ERR_OK);104assert(success);105});106}108static void VerifyScriptP2WPKH(benchmark::Bench& bench) { VerifyScriptBench(bench, ScriptType::P2WPKH); }109static void VerifyScriptP2TR_KeyPath(benchmark::Bench& bench) { VerifyScriptBench(bench, ScriptType::P2TR_KeyPath); }110static void VerifyScriptP2TR_ScriptPath(benchmark::Bench& bench) { VerifyScriptBench(bench, ScriptType::P2TR_ScriptPath); }112static void VerifyNestedIfScript(benchmark::Bench& bench)113{114std::vector<std::vector<unsigned char>> stack;115CScript script;116for (int i = 0; i < 100; ++i) {117script << OP_1 << OP_IF;118}119for (int i = 0; i < 1000; ++i) {120script << OP_1;121}122for (int i = 0; i < 100; ++i) {123script << OP_ENDIF;124}125bench.unit("script")126.setup([&] { stack.clear(); })127.run([&] {128ScriptError error;129const bool ret{EvalScript(stack, script, /*flags=*/0, BaseSignatureChecker(), SigVersion::BASE, &error)};130assert(ret && error == SCRIPT_ERR_OK);131});132}134BENCHMARK(VerifyScriptP2WPKH);135BENCHMARK(VerifyScriptP2TR_KeyPath);136BENCHMARK(VerifyScriptP2TR_ScriptPath);137BENCHMARK(VerifyNestedIfScript);
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.