/ src / bench / verify_script.cpp
verify_script.cpp
  1  // Copyright (c) 2016-present The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #include <addresstype.h>
  6  #include <bench/bench.h>
  7  #include <key.h>
  8  #include <policy/policy.h>
  9  #include <primitives/transaction.h>
 10  #include <pubkey.h>
 11  #include <script/interpreter.h>
 12  #include <script/script.h>
 13  #include <span.h>
 14  #include <test/util/transaction_utils.h>
 15  #include <uint256.h>
 16  #include <util/translation.h>
 17  
 18  #include <array>
 19  #include <cassert>
 20  #include <cstdint>
 21  #include <vector>
 22  
 23  enum class ScriptType {
 24      P2WPKH, // segwitv0, witness-pubkey-hash (ECDSA signature)
 25      P2TR,   // segwitv1, taproot key-path spend (Schnorr signature)
 26  };
 27  
 28  // Microbenchmark for verification of standard scripts.
 29  static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
 30  {
 31      ECC_Context ecc_context{};
 32  
 33      // Create deterministic key material needed for output script creation / signing
 34      CKey privkey;
 35      privkey.Set(uint256::ONE.begin(), uint256::ONE.end(), /*fCompressedIn=*/true);
 36      CPubKey pubkey = privkey.GetPubKey();
 37      CKeyID key_id = pubkey.GetID();
 38  
 39      FlatSigningProvider keystore;
 40      keystore.keys.emplace(key_id, privkey);
 41      keystore.pubkeys.emplace(key_id, pubkey);
 42  
 43      // Create crediting and spending transactions with provided input type
 44      CTxDestination dest;
 45      switch (script_type) {
 46      case ScriptType::P2WPKH: dest = WitnessV0KeyHash(pubkey); break;
 47      case ScriptType::P2TR:   dest = WitnessV1Taproot(XOnlyPubKey{pubkey}); break;
 48      default: assert(false);
 49      }
 50      const CMutableTransaction& txCredit = BuildCreditingTransaction(GetScriptForDestination(dest), 1);
 51      CMutableTransaction txSpend = BuildSpendingTransaction(/*scriptSig=*/{}, /*scriptWitness=*/{}, CTransaction(txCredit));
 52  
 53      // Sign spending transaction, precompute transaction data
 54      PrecomputedTransactionData txdata;
 55      {
 56          std::map<COutPoint, Coin> coins;
 57          coins[txSpend.vin[0].prevout] = Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false);
 58          std::map<int, bilingual_str> input_errors;
 59          bool complete = SignTransaction(txSpend, &keystore, coins, SIGHASH_ALL, input_errors);
 60          assert(complete);
 61          txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]});
 62      }
 63  
 64      // Benchmark.
 65      bench.run([&] {
 66          ScriptError err;
 67          bool success = VerifyScript(
 68              txSpend.vin[0].scriptSig,
 69              txCredit.vout[0].scriptPubKey,
 70              &txSpend.vin[0].scriptWitness,
 71              STANDARD_SCRIPT_VERIFY_FLAGS,
 72              MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL),
 73              &err);
 74          assert(err == SCRIPT_ERR_OK);
 75          assert(success);
 76      });
 77  }
 78  
 79  static void VerifyScriptP2WPKH(benchmark::Bench& bench) { VerifyScriptBench(bench, ScriptType::P2WPKH); }
 80  static void VerifyScriptP2TR(benchmark::Bench& bench)   { VerifyScriptBench(bench, ScriptType::P2TR);   }
 81  
 82  static void VerifyNestedIfScript(benchmark::Bench& bench)
 83  {
 84      std::vector<std::vector<unsigned char>> stack;
 85      CScript script;
 86      for (int i = 0; i < 100; ++i) {
 87          script << OP_1 << OP_IF;
 88      }
 89      for (int i = 0; i < 1000; ++i) {
 90          script << OP_1;
 91      }
 92      for (int i = 0; i < 100; ++i) {
 93          script << OP_ENDIF;
 94      }
 95      bench.run([&] {
 96          auto stack_copy = stack;
 97          ScriptError error;
 98          bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
 99          assert(ret);
100      });
101  }
102  
103  BENCHMARK(VerifyScriptP2WPKH);
104  BENCHMARK(VerifyScriptP2TR);
105  BENCHMARK(VerifyNestedIfScript);