verify_script.cpp raw

   1  // Copyright (c) 2016-2022 The Limenka 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 <limenka-build-config.h> // IWYU pragma: keep
   6  
   7  #include <bench/bench.h>
   8  #include <hash.h>
   9  #include <key.h>
  10  #include <primitives/transaction.h>
  11  #include <pubkey.h>
  12  #if defined(HAVE_CONSENSUS_LIB)
  13  #include <script/limenkaconsensus.h>
  14  #endif
  15  #include <script/interpreter.h>
  16  #include <script/script.h>
  17  #include <span.h>
  18  #include <streams.h>
  19  #include <test/util/transaction_utils.h>
  20  #include <uint256.h>
  21  
  22  #include <array>
  23  #include <cassert>
  24  #include <cstdint>
  25  #include <vector>
  26  
  27  // Microbenchmark for verification of a basic P2WPKH script. Can be easily
  28  // modified to measure performance of other types of scripts.
  29  static void VerifyScriptBench(benchmark::Bench& bench)
  30  {
  31      ECC_Context ecc_context{};
  32  
  33      const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
  34      const int witnessversion = 0;
  35  
  36      // Key pair.
  37      CKey key;
  38      static const std::array<unsigned char, 32> vchKey = {
  39          {
  40              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  41          }
  42      };
  43      key.Set(vchKey.begin(), vchKey.end(), false);
  44      CPubKey pubkey = key.GetPubKey();
  45      uint160 pubkeyHash;
  46      CHash160().Write(pubkey).Finalize(pubkeyHash);
  47  
  48      // Script.
  49      CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
  50      CScript scriptSig;
  51      CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
  52      const CMutableTransaction& txCredit = BuildCreditingTransaction(scriptPubKey, 1);
  53      CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, CScriptWitness(), CTransaction(txCredit));
  54      CScriptWitness& witness = txSpend.vin[0].scriptWitness;
  55      witness.stack.emplace_back();
  56      key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0), witness.stack.back());
  57      witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
  58      witness.stack.push_back(ToByteVector(pubkey));
  59  
  60      // Benchmark.
  61      bench.run([&] {
  62          ScriptError err;
  63          bool success = VerifyScript(
  64              txSpend.vin[0].scriptSig,
  65              txCredit.vout[0].scriptPubKey,
  66              &txSpend.vin[0].scriptWitness,
  67              flags,
  68              MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL),
  69              &err);
  70          assert(err == SCRIPT_ERR_OK);
  71          assert(success);
  72  
  73  #if defined(HAVE_CONSENSUS_LIB)
  74          DataStream stream;
  75          stream << TX_WITH_WITNESS(txSpend);
  76          int csuccess = limenkaconsensus_verify_script_with_amount(
  77              txCredit.vout[0].scriptPubKey.data(),
  78              txCredit.vout[0].scriptPubKey.size(),
  79              txCredit.vout[0].nValue,
  80              (const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr);
  81          assert(csuccess == 1);
  82  #endif
  83      });
  84  }
  85  
  86  static void VerifyNestedIfScript(benchmark::Bench& bench)
  87  {
  88      std::vector<std::vector<unsigned char>> stack;
  89      CScript script;
  90      for (int i = 0; i < 100; ++i) {
  91          script << OP_1 << OP_IF;
  92      }
  93      for (int i = 0; i < 1000; ++i) {
  94          script << OP_1;
  95      }
  96      for (int i = 0; i < 100; ++i) {
  97          script << OP_ENDIF;
  98      }
  99      bench.run([&] {
 100          auto stack_copy = stack;
 101          ScriptError error;
 102          bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
 103          assert(ret);
 104      });
 105  }
 106  
 107  BENCHMARK(VerifyScriptBench, benchmark::PriorityLevel::HIGH);
 108  BENCHMARK(VerifyNestedIfScript, benchmark::PriorityLevel::HIGH);
 109