Bitcoin Core 31.99.0
P2P Digital Currency
verify_script.cpp
Go to the documentation of this file.
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 <coins.h>
8#include <key.h>
9#include <policy/policy.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>
17#include <script/verify_flags.h>
18#include <span.h>
20#include <uint256.h>
21#include <util/check.h>
22#include <util/translation.h>
23
24#include <cstddef>
25#include <map>
26#include <span>
27#include <vector>
28
29enum class ScriptType {
30 P2WPKH, // segwitv0, witness-pubkey-hash (ECDSA signature)
31 P2TR_KeyPath, // segwitv1, taproot key-path spend (Schnorr signature)
32 P2TR_ScriptPath, // segwitv1, taproot script-path spend (Tapscript leaf with a single OP_CHECKSIG)
33};
34
35static size_t ExpectedWitnessStackSize(ScriptType script_type)
36{
37 switch (script_type) {
38 case ScriptType::P2WPKH: return 2; // [pubkey, signature]
39 case ScriptType::P2TR_KeyPath: return 1; // [signature]
40 case ScriptType::P2TR_ScriptPath: return 3; // [signature, tapscript, control block]
41 } // no default case, so the compiler can warn about missing cases
42 assert(false);
43}
44
45// Microbenchmark for verification of standard scripts.
46static void VerifyScriptBench(benchmark::Bench& bench, ScriptType script_type)
47{
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);
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 }()};
77 CMutableTransaction txSpend = BuildSpendingTransaction(/*scriptSig=*/{}, /*scriptWitness=*/{}, CTransaction(txCredit));
78
79 // Sign spending transaction, precompute transaction data
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,
101 MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL),
102 &err);
103 assert(err == SCRIPT_ERR_OK);
104 assert(success);
105 });
106}
107
111
113{
114 std::vector<std::vector<unsigned char>> stack;
116 for (int i = 0; i < 100; ++i) {
117 script << OP_1 << OP_IF;
118 }
119 for (int i = 0; i < 1000; ++i) {
120 script << OP_1;
121 }
122 for (int i = 0; i < 100; ++i) {
123 script << OP_ENDIF;
124 }
125 bench.unit("script")
126 .setup([&] { stack.clear(); })
127 .run([&] {
128 ScriptError error;
129 const bool ret{EvalScript(stack, script, /*flags=*/0, BaseSignatureChecker(), SigVersion::BASE, &error)};
130 assert(ret && error == SCRIPT_ERR_OK);
131 });
132}
133
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:143
int ret
ECC_Context ecc_context
An encapsulated private key.
Definition: key.h:37
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:182
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:105
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:24
An encapsulated public key.
Definition: pubkey.h:32
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:158
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:406
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:281
A UTXO entry.
Definition: coins.h:35
RAII class initializing and deinitializing global state for elliptic curve support.
Definition: key.h:327
Utility class to construct Taproot outputs from internal key and script tree.
WitnessV1Taproot GetOutput()
Compute scriptPubKey (after Finalize()).
TaprootBuilder & Add(int depth, std::span< const unsigned char > script, int leaf_version, bool track=true)
Add a new script at a certain depth in the tree.
TaprootBuilder & Finalize(const XOnlyPubKey &internal_key)
Finalize the construction.
static const XOnlyPubKey NUMS_H
Nothing Up My Sleeve point H Used as an internal key for provably disabling the key path spend see BI...
Definition: pubkey.h:233
Main entry point to nanobench's benchmarking facility.
Definition: nanobench.h:649
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1308
Bench & unit(char const *unit)
Sets the operation unit.
detail::SetupRunner< SetupOp > setup(SetupOp setupOp)
Configure an untimed setup step per epoch (forces single-iteration epochs).
Definition: nanobench.h:1302
static const uint256 ONE
Definition: uint256.h:205
bool EvalScript(std::vector< std::vector< unsigned char > > &stack, const CScript &script, script_verify_flags flags, const BaseSignatureChecker &checker, SigVersion sigversion, ScriptExecutionData &execdata, ScriptError *serror)
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, script_verify_flags flags, const BaseSignatureChecker &checker, ScriptError *serror)
@ BASE
Bare scripts and BIP16 P2SH-wrapped redeemscripts.
static constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT
Definition: interpreter.h:243
@ SIGHASH_ALL
Definition: interpreter.h:32
@ ASSERT_FAIL
Abort execution through assertion failure (for consensus code)
static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS
Standard script verification flags that standard transactions will comply with.
Definition: policy.h:118
void SignTransaction(CMutableTransaction &mtx, const SigningProvider *keystore, const std::map< COutPoint, Coin > &coins, const UniValue &hashType, UniValue &result)
Sign a transaction with the given keystore and previous transactions.
@ OP_IF
Definition: script.h:105
@ OP_CHECKSIG
Definition: script.h:191
@ OP_ENDIF
Definition: script.h:110
@ OP_1
Definition: script.h:84
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:68
enum ScriptError_t ScriptError
@ SCRIPT_ERR_OK
Definition: script_error.h:13
A mutable version of CTransaction.
Definition: transaction.h:358
std::vector< CTxOut > vout
Definition: transaction.h:360
std::vector< CTxIn > vin
Definition: transaction.h:359
std::map< CKeyID, CPubKey > pubkeys
std::map< CKeyID, CKey > keys
std::map< XOnlyPubKey, TaprootBuilder > tr_trees
CMutableTransaction BuildSpendingTransaction(const CScript &scriptSig, const CScriptWitness &scriptWitness, const CTransaction &txCredit)
CMutableTransaction BuildCreditingTransaction(const CScript &scriptPubKey, CAmount nValue)
assert(!tx.IsCoinBase())
ScriptType
static void VerifyNestedIfScript(benchmark::Bench &bench)
static void VerifyScriptP2TR_ScriptPath(benchmark::Bench &bench)
static void VerifyScriptP2WPKH(benchmark::Bench &bench)
static void VerifyScriptBench(benchmark::Bench &bench, ScriptType script_type)
static void VerifyScriptP2TR_KeyPath(benchmark::Bench &bench)
static size_t ExpectedWitnessStackSize(ScriptType script_type)
BENCHMARK(VerifyScriptP2WPKH)