Bitcoin Core 28.99.0
P2P Digital Currency
solver.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <pubkey.h>
8#include <script/script.h>
9#include <script/solver.h>
10#include <span.h>
11
12#include <algorithm>
13#include <cassert>
14#include <string>
15
16typedef std::vector<unsigned char> valtype;
17
19{
20 switch (t) {
21 case TxoutType::NONSTANDARD: return "nonstandard";
22 case TxoutType::PUBKEY: return "pubkey";
23 case TxoutType::PUBKEYHASH: return "pubkeyhash";
24 case TxoutType::SCRIPTHASH: return "scripthash";
25 case TxoutType::MULTISIG: return "multisig";
26 case TxoutType::NULL_DATA: return "nulldata";
27 case TxoutType::ANCHOR: return "anchor";
28 case TxoutType::WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
29 case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
30 case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot";
31 case TxoutType::WITNESS_UNKNOWN: return "witness_unknown";
32 } // no default case, so the compiler can warn about missing cases
33 assert(false);
34}
35
36static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
37{
38 if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE && script.back() == OP_CHECKSIG) {
39 pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1);
40 return CPubKey::ValidSize(pubkey);
41 }
42 if (script.size() == CPubKey::COMPRESSED_SIZE + 2 && script[0] == CPubKey::COMPRESSED_SIZE && script.back() == OP_CHECKSIG) {
43 pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_SIZE + 1);
44 return CPubKey::ValidSize(pubkey);
45 }
46 return false;
47}
48
49static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
50{
51 if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
52 pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
53 return true;
54 }
55 return false;
56}
57
59static constexpr bool IsSmallInteger(opcodetype opcode)
60{
61 return opcode >= OP_1 && opcode <= OP_16;
62}
63
66static std::optional<int> GetScriptNumber(opcodetype opcode, valtype data, int min, int max)
67{
68 int count;
69 if (IsSmallInteger(opcode)) {
70 count = CScript::DecodeOP_N(opcode);
71 } else if (IsPushdataOp(opcode)) {
72 if (!CheckMinimalPush(data, opcode)) return {};
73 try {
74 count = CScriptNum(data, /* fRequireMinimal = */ true).getint();
75 } catch (const scriptnum_error&) {
76 return {};
77 }
78 } else {
79 return {};
80 }
81 if (count < min || count > max) return {};
82 return count;
83}
84
85static bool MatchMultisig(const CScript& script, int& required_sigs, std::vector<valtype>& pubkeys)
86{
87 opcodetype opcode;
89
91 if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
92
93 if (!script.GetOp(it, opcode, data)) return false;
94 auto req_sigs = GetScriptNumber(opcode, data, 1, MAX_PUBKEYS_PER_MULTISIG);
95 if (!req_sigs) return false;
96 required_sigs = *req_sigs;
97 while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
98 pubkeys.emplace_back(std::move(data));
99 }
100 auto num_keys = GetScriptNumber(opcode, data, required_sigs, MAX_PUBKEYS_PER_MULTISIG);
101 if (!num_keys) return false;
102 if (pubkeys.size() != static_cast<unsigned long>(*num_keys)) return false;
103
104 return (it + 1 == script.end());
105}
106
107std::optional<std::pair<int, std::vector<Span<const unsigned char>>>> MatchMultiA(const CScript& script)
108{
109 std::vector<Span<const unsigned char>> keyspans;
110
111 // Redundant, but very fast and selective test.
112 if (script.size() == 0 || script[0] != 32 || script.back() != OP_NUMEQUAL) return {};
113
114 // Parse keys
115 auto it = script.begin();
116 while (script.end() - it >= 34) {
117 if (*it != 32) return {};
118 ++it;
119 keyspans.emplace_back(&*it, 32);
120 it += 32;
121 if (*it != (keyspans.size() == 1 ? OP_CHECKSIG : OP_CHECKSIGADD)) return {};
122 ++it;
123 }
124 if (keyspans.size() == 0 || keyspans.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
125
126 // Parse threshold.
127 opcodetype opcode;
128 std::vector<unsigned char> data;
129 if (!script.GetOp(it, opcode, data)) return {};
130 if (it == script.end()) return {};
131 if (*it != OP_NUMEQUAL) return {};
132 ++it;
133 if (it != script.end()) return {};
134 auto threshold = GetScriptNumber(opcode, data, 1, (int)keyspans.size());
135 if (!threshold) return {};
136
137 // Construct result.
138 return std::pair{*threshold, std::move(keyspans)};
139}
140
141TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
142{
143 vSolutionsRet.clear();
144
145 // Shortcut for pay-to-script-hash, which are more constrained than the other types:
146 // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
147 if (scriptPubKey.IsPayToScriptHash())
148 {
149 std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
150 vSolutionsRet.push_back(hashBytes);
152 }
153
154 int witnessversion;
155 std::vector<unsigned char> witnessprogram;
156 if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
157 if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
158 vSolutionsRet.push_back(std::move(witnessprogram));
160 }
161 if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
162 vSolutionsRet.push_back(std::move(witnessprogram));
164 }
165 if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE) {
166 vSolutionsRet.push_back(std::move(witnessprogram));
168 }
169 if (scriptPubKey.IsPayToAnchor()) {
170 return TxoutType::ANCHOR;
171 }
172 if (witnessversion != 0) {
173 vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
174 vSolutionsRet.push_back(std::move(witnessprogram));
176 }
178 }
179
180 // Provably prunable, data-carrying output
181 //
182 // So long as script passes the IsUnspendable() test and all but the first
183 // byte passes the IsPushOnly() test we don't care what exactly is in the
184 // script.
185 if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
187 }
188
189 std::vector<unsigned char> data;
190 if (MatchPayToPubkey(scriptPubKey, data)) {
191 vSolutionsRet.push_back(std::move(data));
192 return TxoutType::PUBKEY;
193 }
194
195 if (MatchPayToPubkeyHash(scriptPubKey, data)) {
196 vSolutionsRet.push_back(std::move(data));
198 }
199
200 int required;
201 std::vector<std::vector<unsigned char>> keys;
202 if (MatchMultisig(scriptPubKey, required, keys)) {
203 vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..20
204 vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
205 vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..20
206 return TxoutType::MULTISIG;
207 }
208
209 vSolutionsRet.clear();
211}
212
214{
215 return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
216}
217
218CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
219{
221
222 script << nRequired;
223 for (const CPubKey& key : keys)
224 script << ToByteVector(key);
225 script << keys.size() << OP_CHECKMULTISIG;
226
227 return script;
228}
std::vector< unsigned char > valtype
Definition: addresstype.cpp:18
An encapsulated public key.
Definition: pubkey.h:34
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:40
const unsigned char * end() const
Definition: pubkey.h:115
static constexpr unsigned int SIZE
secp256k1:
Definition: pubkey.h:39
const unsigned char * begin() const
Definition: pubkey.h:114
static bool ValidSize(const std::vector< unsigned char > &vch)
Definition: pubkey.h:77
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:415
bool IsPushOnly(const_iterator pc) const
Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
Definition: script.cpp:259
bool IsPayToScriptHash() const
Definition: script.cpp:224
static int DecodeOP_N(opcodetype opcode)
Encode/decode small integers:
Definition: script.h:517
bool IsPayToAnchor() const
Definition: script.cpp:207
bool IsWitnessProgram(int &version, std::vector< unsigned char > &program) const
Definition: script.cpp:243
int getint() const
Definition: script.h:333
size_type size() const
Definition: prevector.h:294
iterator begin()
Definition: prevector.h:302
static constexpr size_t WITNESS_V0_KEYHASH_SIZE
Definition: interpreter.h:228
static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE
Signature hash sizes.
Definition: interpreter.h:227
static constexpr size_t WITNESS_V1_TAPROOT_SIZE
Definition: interpreter.h:229
bool CheckMinimalPush(const std::vector< unsigned char > &data, opcodetype opcode)
Definition: script.cpp:366
opcodetype
Script opcodes.
Definition: script.h:74
@ OP_CHECKMULTISIG
Definition: script.h:192
@ OP_CHECKSIG
Definition: script.h:190
@ OP_16
Definition: script.h:99
@ OP_NUMEQUAL
Definition: script.h:171
@ OP_DUP
Definition: script.h:125
@ OP_HASH160
Definition: script.h:187
@ OP_1
Definition: script.h:83
@ OP_CHECKSIGADD
Definition: script.h:210
@ OP_RETURN
Definition: script.h:111
@ OP_EQUALVERIFY
Definition: script.h:147
static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
Definition: script.h:37
static const int MAX_PUBKEYS_PER_MULTISIG
Definition: script.h:34
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:67
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: solver.cpp:141
std::optional< std::pair< int, std::vector< Span< const unsigned char > > > > MatchMultiA(const CScript &script)
Definition: solver.cpp:107
static bool MatchPayToPubkeyHash(const CScript &script, valtype &pubkeyhash)
Definition: solver.cpp:49
static constexpr bool IsSmallInteger(opcodetype opcode)
Test for "small positive integer" script opcodes - OP_1 through OP_16.
Definition: solver.cpp:59
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: solver.cpp:218
std::vector< unsigned char > valtype
Definition: solver.cpp:16
std::string GetTxnOutputType(TxoutType t)
Get the name of a TxoutType as a string.
Definition: solver.cpp:18
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: solver.cpp:213
static std::optional< int > GetScriptNumber(opcodetype opcode, valtype data, int min, int max)
Retrieve a minimally-encoded number in range [min,max] from an (opcode, data) pair,...
Definition: solver.cpp:66
static bool MatchMultisig(const CScript &script, int &required_sigs, std::vector< valtype > &pubkeys)
Definition: solver.cpp:85
static bool MatchPayToPubkey(const CScript &script, valtype &pubkey)
Definition: solver.cpp:36
constexpr bool IsPushdataOp(opcodetype opcode)
Definition: solver.h:40
TxoutType
Definition: solver.h:22
@ WITNESS_V1_TAPROOT
@ WITNESS_UNKNOWN
Only for Witness versions not already defined above.
@ ANCHOR
anyone can spend script
@ WITNESS_V0_SCRIPTHASH
@ NULL_DATA
unspendable OP_RETURN script that carries data
@ WITNESS_V0_KEYHASH
static int count
assert(!tx.IsCoinBase())