Bitcoin Core  28.1.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>
7 #include <script/interpreter.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 
16 typedef 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 
36 static 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 
49 static 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 
59 static constexpr bool IsSmallInteger(opcodetype opcode)
60 {
61  return opcode >= OP_1 && opcode <= OP_16;
62 }
63 
66 static 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 
85 static bool MatchMultisig(const CScript& script, int& required_sigs, std::vector<valtype>& pubkeys)
86 {
87  opcodetype opcode;
88  valtype data;
89 
90  CScript::const_iterator it = script.begin();
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 
107 std::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 
141 TxoutType 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);
151  return TxoutType::SCRIPTHASH;
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  }
177  return TxoutType::NONSTANDARD;
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)) {
186  return TxoutType::NULL_DATA;
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));
197  return TxoutType::PUBKEYHASH;
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();
210  return TxoutType::NONSTANDARD;
211 }
212 
214 {
215  return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
216 }
217 
218 CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
219 {
220  CScript script;
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 }
constexpr bool IsPushdataOp(opcodetype opcode)
Definition: solver.h:40
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: solver.cpp:218
static constexpr unsigned int SIZE
secp256k1:
Definition: pubkey.h:39
static int DecodeOP_N(opcodetype opcode)
Encode/decode small integers:
Definition: script.h:506
bool CheckMinimalPush(const std::vector< unsigned char > &data, opcodetype opcode)
Definition: script.cpp:366
int getint() const
Definition: script.h:332
assert(!tx.IsCoinBase())
static constexpr size_t WITNESS_V1_TAPROOT_SIZE
Definition: interpreter.h:229
Definition: script.h:124
bool IsPayToScriptHash() const
Definition: script.cpp:224
static bool MatchPayToPubkey(const CScript &script, valtype &pubkey)
Definition: solver.cpp:36
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
bool IsWitnessProgram(int &version, std::vector< unsigned char > &program) const
Definition: script.cpp:243
static bool MatchMultisig(const CScript &script, int &required_sigs, std::vector< valtype > &pubkeys)
Definition: solver.cpp:85
static const int MAX_PUBKEYS_PER_MULTISIG
Definition: script.h:33
const unsigned char * begin() const
Definition: pubkey.h:114
Definition: script.h:82
static constexpr bool IsSmallInteger(opcodetype opcode)
Test for "small positive integer" script opcodes - OP_1 through OP_16.
Definition: solver.cpp:59
static bool ValidSize(const std::vector< unsigned char > &vch)
Definition: pubkey.h:77
anyone can spend script
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:40
const unsigned char * end() const
Definition: pubkey.h:115
bool IsPushOnly(const_iterator pc) const
Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
Definition: script.cpp:259
An encapsulated public key.
Definition: pubkey.h:33
opcodetype
Script opcodes.
Definition: script.h:72
static constexpr unsigned int MAX_PUBKEYS_PER_MULTI_A
The limit of keys in OP_CHECKSIGADD-based scripts.
Definition: script.h:36
static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE
Signature hash sizes.
Definition: interpreter.h:227
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, whether it&#39;s OP_n or through a push.
Definition: solver.cpp:66
bool IsPayToAnchor() const
Definition: script.cpp:207
std::vector< unsigned char > valtype
Definition: addresstype.cpp:18
std::string GetTxnOutputType(TxoutType t)
Get the name of a TxoutType as a string.
Definition: solver.cpp:18
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:66
TxoutType
Definition: solver.h:22
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:413
static constexpr size_t WITNESS_V0_KEYHASH_SIZE
Definition: interpreter.h:228
static int count
iterator begin()
Definition: prevector.h:304
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: solver.cpp:213
size_type size() const
Definition: prevector.h:296
Definition: script.h:98
std::optional< std::pair< int, std::vector< Span< const unsigned char > > > > MatchMultiA(const CScript &script)
Definition: solver.cpp:107
Only for Witness versions not already defined above.
static bool MatchPayToPubkeyHash(const CScript &script, valtype &pubkeyhash)
Definition: solver.cpp:49
std::vector< unsigned char > valtype
Definition: solver.cpp:16
unspendable OP_RETURN script that carries data