]>
Commit | Line | Data |
---|---|---|
c4408a6c | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
2d79bba3 | 3 | // Distributed under the MIT software license, see the accompanying |
c4408a6c | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | ||
6 | #include "script/standard.h" | |
7 | ||
d2e74c55 | 8 | #include "pubkey.h" |
c4408a6c | 9 | #include "script/script.h" |
10 | #include "util.h" | |
85c579e3 | 11 | #include "utilstrencodings.h" |
c4408a6c | 12 | |
13 | #include <boost/foreach.hpp> | |
14 | ||
15 | using namespace std; | |
16 | ||
17 | typedef vector<unsigned char> valtype; | |
18 | ||
2aa63292 LD |
19 | unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; |
20 | ||
d78f0daf | 21 | CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} |
066e2a14 | 22 | |
c4408a6c | 23 | const char* GetTxnOutputType(txnouttype t) |
24 | { | |
25 | switch (t) | |
26 | { | |
27 | case TX_NONSTANDARD: return "nonstandard"; | |
28 | case TX_PUBKEY: return "pubkey"; | |
29 | case TX_PUBKEYHASH: return "pubkeyhash"; | |
30 | case TX_SCRIPTHASH: return "scripthash"; | |
31 | case TX_MULTISIG: return "multisig"; | |
32 | case TX_NULL_DATA: return "nulldata"; | |
33 | } | |
34 | return NULL; | |
35 | } | |
36 | ||
b9a36b15 MF |
37 | /** |
38 | * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. | |
39 | */ | |
c4408a6c | 40 | bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet) |
41 | { | |
42 | // Templates | |
43 | static multimap<txnouttype, CScript> mTemplates; | |
44 | if (mTemplates.empty()) | |
45 | { | |
46 | // Standard tx, sender provides pubkey, receiver adds signature | |
47 | mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); | |
48 | ||
49 | // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey | |
50 | mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); | |
51 | ||
52 | // Sender provides N pubkeys, receivers provides M signatures | |
53 | mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); | |
54 | ||
55 | // Empty, provably prunable, data-carrying output | |
4aa2c64e | 56 | if (GetBoolArg("-datacarrier", true)) |
c4408a6c | 57 | mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA)); |
58 | mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN)); | |
59 | } | |
60 | ||
61 | // Shortcut for pay-to-script-hash, which are more constrained than the other types: | |
62 | // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL | |
63 | if (scriptPubKey.IsPayToScriptHash()) | |
64 | { | |
65 | typeRet = TX_SCRIPTHASH; | |
66 | vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); | |
67 | vSolutionsRet.push_back(hashBytes); | |
68 | return true; | |
69 | } | |
70 | ||
71 | // Scan templates | |
72 | const CScript& script1 = scriptPubKey; | |
73 | BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) | |
74 | { | |
75 | const CScript& script2 = tplate.second; | |
76 | vSolutionsRet.clear(); | |
77 | ||
78 | opcodetype opcode1, opcode2; | |
79 | vector<unsigned char> vch1, vch2; | |
80 | ||
81 | // Compare | |
82 | CScript::const_iterator pc1 = script1.begin(); | |
83 | CScript::const_iterator pc2 = script2.begin(); | |
84 | while (true) | |
85 | { | |
86 | if (pc1 == script1.end() && pc2 == script2.end()) | |
87 | { | |
88 | // Found a match | |
89 | typeRet = tplate.first; | |
90 | if (typeRet == TX_MULTISIG) | |
91 | { | |
92 | // Additional checks for TX_MULTISIG: | |
93 | unsigned char m = vSolutionsRet.front()[0]; | |
94 | unsigned char n = vSolutionsRet.back()[0]; | |
95 | if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) | |
96 | return false; | |
97 | } | |
98 | return true; | |
99 | } | |
100 | if (!script1.GetOp(pc1, opcode1, vch1)) | |
101 | break; | |
102 | if (!script2.GetOp(pc2, opcode2, vch2)) | |
103 | break; | |
104 | ||
105 | // Template matching opcodes: | |
106 | if (opcode2 == OP_PUBKEYS) | |
107 | { | |
108 | while (vch1.size() >= 33 && vch1.size() <= 65) | |
109 | { | |
110 | vSolutionsRet.push_back(vch1); | |
111 | if (!script1.GetOp(pc1, opcode1, vch1)) | |
112 | break; | |
113 | } | |
114 | if (!script2.GetOp(pc2, opcode2, vch2)) | |
115 | break; | |
116 | // Normal situation is to fall through | |
117 | // to other if/else statements | |
118 | } | |
119 | ||
120 | if (opcode2 == OP_PUBKEY) | |
121 | { | |
122 | if (vch1.size() < 33 || vch1.size() > 65) | |
123 | break; | |
124 | vSolutionsRet.push_back(vch1); | |
125 | } | |
126 | else if (opcode2 == OP_PUBKEYHASH) | |
127 | { | |
128 | if (vch1.size() != sizeof(uint160)) | |
129 | break; | |
130 | vSolutionsRet.push_back(vch1); | |
131 | } | |
132 | else if (opcode2 == OP_SMALLINTEGER) | |
133 | { // Single-byte small integer pushed onto vSolutions | |
134 | if (opcode1 == OP_0 || | |
135 | (opcode1 >= OP_1 && opcode1 <= OP_16)) | |
136 | { | |
137 | char n = (char)CScript::DecodeOP_N(opcode1); | |
138 | vSolutionsRet.push_back(valtype(1, n)); | |
139 | } | |
140 | else | |
141 | break; | |
142 | } | |
143 | else if (opcode2 == OP_SMALLDATA) | |
144 | { | |
2aa63292 LD |
145 | // small pushdata, <= nMaxDatacarrierBytes |
146 | if (vch1.size() > nMaxDatacarrierBytes) | |
cc0f93da | 147 | { |
148 | fprintf(stderr,"size.%d > nMaxDatacarrier.%d\n",(int32_t)vch1.size(),(int32_t)nMaxDatacarrierBytes); | |
c4408a6c | 149 | break; |
cc0f93da | 150 | } |
c4408a6c | 151 | } |
152 | else if (opcode1 != opcode2 || vch1 != vch2) | |
153 | { | |
154 | // Others must match exactly | |
155 | break; | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | vSolutionsRet.clear(); | |
161 | typeRet = TX_NONSTANDARD; | |
162 | return false; | |
163 | } | |
164 | ||
165 | int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions) | |
166 | { | |
167 | switch (t) | |
168 | { | |
169 | case TX_NONSTANDARD: | |
170 | case TX_NULL_DATA: | |
171 | return -1; | |
172 | case TX_PUBKEY: | |
173 | return 1; | |
174 | case TX_PUBKEYHASH: | |
175 | return 2; | |
176 | case TX_MULTISIG: | |
177 | if (vSolutions.size() < 1 || vSolutions[0].size() < 1) | |
178 | return -1; | |
179 | return vSolutions[0][0] + 1; | |
180 | case TX_SCRIPTHASH: | |
181 | return 1; // doesn't include args needed by the script | |
182 | } | |
183 | return -1; | |
184 | } | |
185 | ||
186 | bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) | |
187 | { | |
188 | vector<valtype> vSolutions; | |
189 | if (!Solver(scriptPubKey, whichType, vSolutions)) | |
cf9538e0 | 190 | { |
191 | int32_t i; uint8_t *ptr = (uint8_t *)scriptPubKey.data(); | |
192 | for (i=0; i<scriptPubKey.size(); i++) | |
193 | fprintf(stderr,"%02x",ptr[i]); | |
194 | fprintf(stderr," non-standard scriptPubKey\n"); | |
c4408a6c | 195 | return false; |
cf9538e0 | 196 | } |
c4408a6c | 197 | |
198 | if (whichType == TX_MULTISIG) | |
199 | { | |
200 | unsigned char m = vSolutions.front()[0]; | |
201 | unsigned char n = vSolutions.back()[0]; | |
cf9538e0 | 202 | // Support up to x-of-9 multisig txns as standard |
203 | if (n < 1 || n > 9) | |
c4408a6c | 204 | return false; |
205 | if (m < 1 || m > n) | |
206 | return false; | |
207 | } | |
c4408a6c | 208 | return whichType != TX_NONSTANDARD; |
209 | } | |
210 | ||
211 | bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) | |
212 | { | |
213 | vector<valtype> vSolutions; | |
214 | txnouttype whichType; | |
215 | if (!Solver(scriptPubKey, whichType, vSolutions)) | |
216 | return false; | |
217 | ||
218 | if (whichType == TX_PUBKEY) | |
219 | { | |
9d7cd4c5 AA |
220 | CPubKey pubKey(vSolutions[0]); |
221 | if (!pubKey.IsValid()) | |
b62d7030 | 222 | { |
223 | fprintf(stderr,"TX_PUBKEY invalid pubkey\n"); | |
9d7cd4c5 | 224 | return false; |
b62d7030 | 225 | } |
9d7cd4c5 AA |
226 | |
227 | addressRet = pubKey.GetID(); | |
c4408a6c | 228 | return true; |
229 | } | |
230 | else if (whichType == TX_PUBKEYHASH) | |
231 | { | |
232 | addressRet = CKeyID(uint160(vSolutions[0])); | |
233 | return true; | |
234 | } | |
235 | else if (whichType == TX_SCRIPTHASH) | |
236 | { | |
237 | addressRet = CScriptID(uint160(vSolutions[0])); | |
238 | return true; | |
239 | } | |
240 | // Multisig txns have more than one address... | |
241 | return false; | |
242 | } | |
243 | ||
244 | bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) | |
245 | { | |
246 | addressRet.clear(); | |
247 | typeRet = TX_NONSTANDARD; | |
248 | vector<valtype> vSolutions; | |
249 | if (!Solver(scriptPubKey, typeRet, vSolutions)) | |
250 | return false; | |
251 | if (typeRet == TX_NULL_DATA){ | |
252 | // This is data, not addresses | |
253 | return false; | |
254 | } | |
255 | ||
256 | if (typeRet == TX_MULTISIG) | |
257 | { | |
258 | nRequiredRet = vSolutions.front()[0]; | |
259 | for (unsigned int i = 1; i < vSolutions.size()-1; i++) | |
260 | { | |
9d7cd4c5 AA |
261 | CPubKey pubKey(vSolutions[i]); |
262 | if (!pubKey.IsValid()) | |
263 | continue; | |
264 | ||
265 | CTxDestination address = pubKey.GetID(); | |
c4408a6c | 266 | addressRet.push_back(address); |
267 | } | |
9d7cd4c5 AA |
268 | |
269 | if (addressRet.empty()) | |
270 | return false; | |
c4408a6c | 271 | } |
272 | else | |
273 | { | |
274 | nRequiredRet = 1; | |
275 | CTxDestination address; | |
276 | if (!ExtractDestination(scriptPubKey, address)) | |
277 | return false; | |
278 | addressRet.push_back(address); | |
279 | } | |
280 | ||
281 | return true; | |
282 | } | |
0be990ba PW |
283 | |
284 | namespace | |
285 | { | |
286 | class CScriptVisitor : public boost::static_visitor<bool> | |
287 | { | |
288 | private: | |
289 | CScript *script; | |
290 | public: | |
291 | CScriptVisitor(CScript *scriptin) { script = scriptin; } | |
292 | ||
293 | bool operator()(const CNoDestination &dest) const { | |
294 | script->clear(); | |
295 | return false; | |
296 | } | |
297 | ||
298 | bool operator()(const CKeyID &keyID) const { | |
299 | script->clear(); | |
e9ca4280 | 300 | *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; |
0be990ba PW |
301 | return true; |
302 | } | |
303 | ||
304 | bool operator()(const CScriptID &scriptID) const { | |
305 | script->clear(); | |
e9ca4280 | 306 | *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; |
0be990ba PW |
307 | return true; |
308 | } | |
309 | }; | |
310 | } | |
311 | ||
312 | CScript GetScriptForDestination(const CTxDestination& dest) | |
313 | { | |
314 | CScript script; | |
315 | ||
316 | boost::apply_visitor(CScriptVisitor(&script), dest); | |
317 | return script; | |
318 | } | |
319 | ||
320 | CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) | |
321 | { | |
322 | CScript script; | |
323 | ||
324 | script << CScript::EncodeOP_N(nRequired); | |
325 | BOOST_FOREACH(const CPubKey& key, keys) | |
e9ca4280 | 326 | script << ToByteVector(key); |
0be990ba PW |
327 | script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; |
328 | return script; | |
329 | } |