Microbenchmark for verification of standard scripts.
| 44 | |
| 45 | // Microbenchmark for verification of standard scripts. |
| 46 | static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type) |
| 47 | { |
| 48 | ECC_Context ecc_context{}; |
| 49 | |
| 50 | // Create deterministic key material needed for output script creation / signing |
| 51 | CKey privkey; |
| 52 | privkey.Set(uint256::ONE.begin(), uint256::ONE.end(), /*fCompressedIn=*/true); |
| 53 | CPubKey pubkey = privkey.GetPubKey(); |
| 54 | XOnlyPubKey xonly_pubkey{pubkey}; |
| 55 | CKeyID key_id = pubkey.GetID(); |
| 56 | |
| 57 | FlatSigningProvider keystore; |
| 58 | keystore.keys.emplace(key_id, privkey); |
| 59 | keystore.pubkeys.emplace(key_id, pubkey); |
| 60 | |
| 61 | // Create crediting and spending transactions with provided input type |
| 62 | const auto dest{[&]() -> CTxDestination { |
| 63 | switch (script_type) { |
| 64 | case ScriptType::P2WPKH: return WitnessV0KeyHash(pubkey); |
| 65 | case ScriptType::P2TR_KeyPath: return WitnessV1Taproot(xonly_pubkey); |
| 66 | case ScriptType::P2TR_ScriptPath: |
| 67 | TaprootBuilder builder; |
| 68 | builder.Add(0, CScript() << ToByteVector(xonly_pubkey) << OP_CHECKSIG, TAPROOT_LEAF_TAPSCRIPT); |
| 69 | builder.Finalize(XOnlyPubKey::NUMS_H); // effectively unspendable key-path |
| 70 | const auto output{builder.GetOutput()}; |
| 71 | keystore.tr_trees.emplace(output, builder); |
| 72 | return output; |
| 73 | } // no default case, so the compiler can warn about missing cases |
| 74 | assert(false); |
| 75 | }()}; |
| 76 | const CMutableTransaction& txCredit = BuildCreditingTransaction(GetScriptForDestination(dest), 1); |
| 77 | CMutableTransaction txSpend = BuildSpendingTransaction(/*scriptSig=*/{}, /*scriptWitness=*/{}, CTransaction(txCredit)); |
| 78 | |
| 79 | // Sign spending transaction, precompute transaction data |
| 80 | PrecomputedTransactionData txdata; |
| 81 | { |
| 82 | const std::map<COutPoint, Coin> coins{ |
| 83 | {txSpend.vin[0].prevout, Coin(txCredit.vout[0], /*nHeightIn=*/100, /*fCoinBaseIn=*/false)} |
| 84 | }; |
| 85 | std::map<int, bilingual_str> input_errors; |
| 86 | bool complete = SignTransaction(txSpend, &keystore, coins, {.sighash_type = SIGHASH_ALL}, input_errors); |
| 87 | assert(complete); |
| 88 | // Weak sanity check on witness data to ensure we produced the intended spending type |
| 89 | assert(txSpend.vin[0].scriptWitness.stack.size() == ExpectedWitnessStackSize(script_type)); |
| 90 | txdata.Init(txSpend, /*spent_outputs=*/{txCredit.vout[0]}); |
| 91 | } |
| 92 | |
| 93 | // Benchmark. |
| 94 | bench.unit("script").run([&] { |
| 95 | ScriptError err; |
| 96 | bool success = VerifyScript( |
| 97 | txSpend.vin[0].scriptSig, |
| 98 | txCredit.vout[0].scriptPubKey, |
| 99 | &txSpend.vin[0].scriptWitness, |
| 100 | STANDARD_SCRIPT_VERIFY_FLAGS, |
| 101 | MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL), |
| 102 | &err); |
| 103 | assert(err == SCRIPT_ERR_OK); |
no test coverage detected