Branch data Line data Source code
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 : :
18 : 874186 : std::string GetTxnOutputType(TxoutType t)
19 : : {
20 [ + + + + : 874186 : switch (t) {
+ + + + +
+ + - ]
21 : 644298 : case TxoutType::NONSTANDARD: return "nonstandard";
22 : 17152 : case TxoutType::PUBKEY: return "pubkey";
23 : 15255 : case TxoutType::PUBKEYHASH: return "pubkeyhash";
24 : 73962 : case TxoutType::SCRIPTHASH: return "scripthash";
25 : 14565 : case TxoutType::MULTISIG: return "multisig";
26 : 4105 : case TxoutType::NULL_DATA: return "nulldata";
27 : 1728 : case TxoutType::ANCHOR: return "anchor";
28 : 38910 : case TxoutType::WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
29 : 37562 : case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
30 : 9410 : case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot";
31 : 17239 : case TxoutType::WITNESS_UNKNOWN: return "witness_unknown";
32 : : } // no default case, so the compiler can warn about missing cases
33 : 0 : assert(false);
34 : : }
35 : :
36 : 3710142 : static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
37 : : {
38 [ + + + + : 3710142 : if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE && script.back() == OP_CHECKSIG) {
+ + + + ]
39 : 39988 : pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1);
40 : 19994 : return CPubKey::ValidSize(pubkey);
41 : : }
42 [ + + + + : 3690148 : if (script.size() == CPubKey::COMPRESSED_SIZE + 2 && script[0] == CPubKey::COMPRESSED_SIZE && script.back() == OP_CHECKSIG) {
+ + + + ]
43 : 125938 : pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_SIZE + 1);
44 : 62969 : return CPubKey::ValidSize(pubkey);
45 : : }
46 : : return false;
47 : : }
48 : :
49 : 3638434 : static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
50 : : {
51 [ + + + + : 8093445 : if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ ]
52 : 1468636 : pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
53 : 734318 : return true;
54 : : }
55 : : return false;
56 : : }
57 : :
58 : : /** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
59 : 199665 : static constexpr bool IsSmallInteger(opcodetype opcode)
60 : : {
61 : 199665 : return opcode >= OP_1 && opcode <= OP_16;
62 : : }
63 : :
64 : : /** Retrieve a minimally-encoded number in range [min,max] from an (opcode, data) pair,
65 : : * whether it's OP_n or through a push. */
66 : 199665 : static std::optional<int> GetScriptNumber(opcodetype opcode, valtype data, int min, int max)
67 : : {
68 : 199665 : int count;
69 [ + + ]: 199665 : if (IsSmallInteger(opcode)) {
70 : 121930 : count = CScript::DecodeOP_N(opcode);
71 [ + + ]: 77735 : } else if (IsPushdataOp(opcode)) {
72 [ + + ]: 51993 : if (!CheckMinimalPush(data, opcode)) return {};
73 : 46784 : try {
74 [ + + ]: 46784 : count = CScriptNum(data, /* fRequireMinimal = */ true).getint();
75 [ - + ]: 18308 : } catch (const scriptnum_error&) {
76 : 18308 : return {};
77 : 18308 : }
78 : : } else {
79 : 25742 : return {};
80 : : }
81 [ + + + + ]: 150406 : if (count < min || count > max) return {};
82 : 130504 : return count;
83 : : }
84 : :
85 : 2904116 : static bool MatchMultisig(const CScript& script, int& required_sigs, std::vector<valtype>& pubkeys)
86 : : {
87 : 2904116 : opcodetype opcode;
88 : 2904116 : valtype data;
89 : :
90 [ + + ]: 2904116 : CScript::const_iterator it = script.begin();
91 [ + + + + : 5964618 : if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
+ + + + ]
92 : :
93 [ + - + + ]: 127134 : if (!script.GetOp(it, opcode, data)) return false;
94 [ + - + - ]: 120185 : auto req_sigs = GetScriptNumber(opcode, data, 1, MAX_PUBKEYS_PER_MULTISIG);
95 [ + + ]: 120185 : if (!req_sigs) return false;
96 : 78280 : required_sigs = *req_sigs;
97 [ + - + + : 267259 : while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
+ + ]
98 [ + - ]: 188979 : pubkeys.emplace_back(std::move(data));
99 : : }
100 [ + - + - ]: 78280 : auto num_keys = GetScriptNumber(opcode, data, required_sigs, MAX_PUBKEYS_PER_MULTISIG);
101 [ + + ]: 78280 : if (!num_keys) return false;
102 [ + + ]: 51024 : if (pubkeys.size() != static_cast<unsigned long>(*num_keys)) return false;
103 : :
104 : 46181 : return (it + 1 == script.end());
105 : 2904116 : }
106 : :
107 : 7921 : std::optional<std::pair<int, std::vector<Span<const unsigned char>>>> MatchMultiA(const CScript& script)
108 : : {
109 : 7921 : std::vector<Span<const unsigned char>> keyspans;
110 : :
111 : : // Redundant, but very fast and selective test.
112 [ + + + - : 26467 : if (script.size() == 0 || script[0] != 32 || script.back() != OP_NUMEQUAL) return {};
+ + + + -
+ + + ]
113 : :
114 : : // Parse keys
115 : 1200 : auto it = script.begin();
116 [ + + ]: 190161 : while (script.end() - it >= 34) {
117 [ - + ]: 188961 : if (*it != 32) return {};
118 [ + - ]: 188961 : ++it;
119 [ + - ]: 188961 : keyspans.emplace_back(&*it, 32);
120 [ + + ]: 188961 : it += 32;
121 [ - + ]: 188961 : if (*it != (keyspans.size() == 1 ? OP_CHECKSIG : OP_CHECKSIGADD)) return {};
122 : 188961 : ++it;
123 : : }
124 [ + - + - ]: 1200 : if (keyspans.size() == 0 || keyspans.size() > MAX_PUBKEYS_PER_MULTI_A) return {};
125 : :
126 : : // Parse threshold.
127 : 1200 : opcodetype opcode;
128 : 1200 : std::vector<unsigned char> data;
129 [ + - - + ]: 1200 : if (!script.GetOp(it, opcode, data)) return {};
130 [ - + ]: 1200 : if (it == script.end()) return {};
131 [ - + ]: 1200 : if (*it != OP_NUMEQUAL) return {};
132 [ - + ]: 1200 : ++it;
133 [ - + ]: 1200 : if (it != script.end()) return {};
134 [ + - + - ]: 1200 : auto threshold = GetScriptNumber(opcode, data, 1, (int)keyspans.size());
135 [ - + ]: 1200 : if (!threshold) return {};
136 : :
137 : : // Construct result.
138 : 1200 : return std::pair{*threshold, std::move(keyspans)};
139 : 9121 : }
140 : :
141 : 14837238 : TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
142 : : {
143 : 14837238 : 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 [ + + ]: 14837238 : if (scriptPubKey.IsPayToScriptHash())
148 : : {
149 [ + + ]: 5408486 : std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
150 [ + - ]: 2704243 : vSolutionsRet.push_back(hashBytes);
151 : 2704243 : return TxoutType::SCRIPTHASH;
152 : 2704243 : }
153 : :
154 : 12132995 : int witnessversion;
155 : 12132995 : std::vector<unsigned char> witnessprogram;
156 [ + - + + ]: 12132995 : if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
157 [ + + + + ]: 8401925 : if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
158 [ + - ]: 2321974 : vSolutionsRet.push_back(std::move(witnessprogram));
159 : : return TxoutType::WITNESS_V0_KEYHASH;
160 : : }
161 [ + + + + ]: 6079951 : if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
162 [ + - ]: 5320444 : vSolutionsRet.push_back(std::move(witnessprogram));
163 : : return TxoutType::WITNESS_V0_SCRIPTHASH;
164 : : }
165 [ + + + + ]: 759507 : if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE) {
166 [ + - ]: 677767 : vSolutionsRet.push_back(std::move(witnessprogram));
167 : : return TxoutType::WITNESS_V1_TAPROOT;
168 : : }
169 [ + - + + ]: 81740 : if (scriptPubKey.IsPayToAnchor()) {
170 : : return TxoutType::ANCHOR;
171 : : }
172 [ + + ]: 80361 : if (witnessversion != 0) {
173 [ + - + - ]: 150590 : vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
174 [ + - ]: 12132995 : vSolutionsRet.push_back(std::move(witnessprogram));
175 : : return TxoutType::WITNESS_UNKNOWN;
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 [ + + + + : 7701796 : if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
+ + + + +
- + + ]
186 : : return TxoutType::NULL_DATA;
187 : : }
188 : :
189 : 3710142 : std::vector<unsigned char> data;
190 [ + - + + ]: 3710142 : if (MatchPayToPubkey(scriptPubKey, data)) {
191 [ + - ]: 71708 : vSolutionsRet.push_back(std::move(data));
192 : : return TxoutType::PUBKEY;
193 : : }
194 : :
195 [ + - + + ]: 3638434 : if (MatchPayToPubkeyHash(scriptPubKey, data)) {
196 [ + - ]: 3710142 : vSolutionsRet.push_back(std::move(data));
197 : : return TxoutType::PUBKEYHASH;
198 : : }
199 : :
200 : 2904116 : int required;
201 : 2904116 : std::vector<std::vector<unsigned char>> keys;
202 [ + - + + ]: 2904116 : if (MatchMultisig(scriptPubKey, required, keys)) {
203 [ + - + - ]: 92096 : vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..20
204 [ + - ]: 46048 : vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
205 [ + - ]: 92096 : vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..20
206 : 46048 : return TxoutType::MULTISIG;
207 : : }
208 : :
209 : 2858068 : vSolutionsRet.clear();
210 : 2858068 : return TxoutType::NONSTANDARD;
211 : 18747253 : }
212 : :
213 : 4064 : CScript GetScriptForRawPubKey(const CPubKey& pubKey)
214 : : {
215 [ + - + - ]: 4064 : return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
216 : : }
217 : :
218 : 4663 : CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
219 : : {
220 : 4663 : CScript script;
221 : :
222 [ + - ]: 4663 : script << nRequired;
223 [ + + ]: 52926 : for (const CPubKey& key : keys)
224 [ + - ]: 48263 : script << ToByteVector(key);
225 [ + - + - ]: 4663 : script << keys.size() << OP_CHECKMULTISIG;
226 : :
227 : 4663 : return script;
228 : 0 : }
|