]>
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 | |
56 | if (GetBoolArg("-datacarrier", true)) | |
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) | |
c4408a6c | 147 | break; |
148 | } | |
149 | else if (opcode1 != opcode2 || vch1 != vch2) | |
150 | { | |
151 | // Others must match exactly | |
152 | break; | |
153 | } | |
154 | } | |
155 | } | |
156 | ||
157 | vSolutionsRet.clear(); | |
158 | typeRet = TX_NONSTANDARD; | |
159 | return false; | |
160 | } | |
161 | ||
162 | int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions) | |
163 | { | |
164 | switch (t) | |
165 | { | |
166 | case TX_NONSTANDARD: | |
167 | case TX_NULL_DATA: | |
168 | return -1; | |
169 | case TX_PUBKEY: | |
170 | return 1; | |
171 | case TX_PUBKEYHASH: | |
172 | return 2; | |
173 | case TX_MULTISIG: | |
174 | if (vSolutions.size() < 1 || vSolutions[0].size() < 1) | |
175 | return -1; | |
176 | return vSolutions[0][0] + 1; | |
177 | case TX_SCRIPTHASH: | |
178 | return 1; // doesn't include args needed by the script | |
179 | } | |
180 | return -1; | |
181 | } | |
182 | ||
183 | bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) | |
184 | { | |
185 | vector<valtype> vSolutions; | |
186 | if (!Solver(scriptPubKey, whichType, vSolutions)) | |
187 | return false; | |
188 | ||
189 | if (whichType == TX_MULTISIG) | |
190 | { | |
191 | unsigned char m = vSolutions.front()[0]; | |
192 | unsigned char n = vSolutions.back()[0]; | |
193 | // Support up to x-of-3 multisig txns as standard | |
194 | if (n < 1 || n > 3) | |
195 | return false; | |
196 | if (m < 1 || m > n) | |
197 | return false; | |
198 | } | |
199 | ||
200 | return whichType != TX_NONSTANDARD; | |
201 | } | |
202 | ||
203 | bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) | |
204 | { | |
205 | vector<valtype> vSolutions; | |
206 | txnouttype whichType; | |
207 | if (!Solver(scriptPubKey, whichType, vSolutions)) | |
208 | return false; | |
209 | ||
210 | if (whichType == TX_PUBKEY) | |
211 | { | |
9d7cd4c5 AA |
212 | CPubKey pubKey(vSolutions[0]); |
213 | if (!pubKey.IsValid()) | |
b62d7030 | 214 | { |
215 | fprintf(stderr,"TX_PUBKEY invalid pubkey\n"); | |
9d7cd4c5 | 216 | return false; |
b62d7030 | 217 | } |
9d7cd4c5 AA |
218 | |
219 | addressRet = pubKey.GetID(); | |
c4408a6c | 220 | return true; |
221 | } | |
222 | else if (whichType == TX_PUBKEYHASH) | |
223 | { | |
224 | addressRet = CKeyID(uint160(vSolutions[0])); | |
225 | return true; | |
226 | } | |
227 | else if (whichType == TX_SCRIPTHASH) | |
228 | { | |
229 | addressRet = CScriptID(uint160(vSolutions[0])); | |
230 | return true; | |
231 | } | |
232 | // Multisig txns have more than one address... | |
233 | return false; | |
234 | } | |
235 | ||
236 | bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) | |
237 | { | |
238 | addressRet.clear(); | |
239 | typeRet = TX_NONSTANDARD; | |
240 | vector<valtype> vSolutions; | |
241 | if (!Solver(scriptPubKey, typeRet, vSolutions)) | |
242 | return false; | |
243 | if (typeRet == TX_NULL_DATA){ | |
244 | // This is data, not addresses | |
245 | return false; | |
246 | } | |
247 | ||
248 | if (typeRet == TX_MULTISIG) | |
249 | { | |
250 | nRequiredRet = vSolutions.front()[0]; | |
251 | for (unsigned int i = 1; i < vSolutions.size()-1; i++) | |
252 | { | |
9d7cd4c5 AA |
253 | CPubKey pubKey(vSolutions[i]); |
254 | if (!pubKey.IsValid()) | |
255 | continue; | |
256 | ||
257 | CTxDestination address = pubKey.GetID(); | |
c4408a6c | 258 | addressRet.push_back(address); |
259 | } | |
9d7cd4c5 AA |
260 | |
261 | if (addressRet.empty()) | |
262 | return false; | |
c4408a6c | 263 | } |
264 | else | |
265 | { | |
266 | nRequiredRet = 1; | |
267 | CTxDestination address; | |
268 | if (!ExtractDestination(scriptPubKey, address)) | |
269 | return false; | |
270 | addressRet.push_back(address); | |
271 | } | |
272 | ||
273 | return true; | |
274 | } | |
0be990ba PW |
275 | |
276 | namespace | |
277 | { | |
278 | class CScriptVisitor : public boost::static_visitor<bool> | |
279 | { | |
280 | private: | |
281 | CScript *script; | |
282 | public: | |
283 | CScriptVisitor(CScript *scriptin) { script = scriptin; } | |
284 | ||
285 | bool operator()(const CNoDestination &dest) const { | |
286 | script->clear(); | |
287 | return false; | |
288 | } | |
289 | ||
290 | bool operator()(const CKeyID &keyID) const { | |
291 | script->clear(); | |
e9ca4280 | 292 | *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; |
0be990ba PW |
293 | return true; |
294 | } | |
295 | ||
296 | bool operator()(const CScriptID &scriptID) const { | |
297 | script->clear(); | |
e9ca4280 | 298 | *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; |
0be990ba PW |
299 | return true; |
300 | } | |
301 | }; | |
302 | } | |
303 | ||
304 | CScript GetScriptForDestination(const CTxDestination& dest) | |
305 | { | |
306 | CScript script; | |
307 | ||
308 | boost::apply_visitor(CScriptVisitor(&script), dest); | |
309 | return script; | |
310 | } | |
311 | ||
312 | CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) | |
313 | { | |
314 | CScript script; | |
315 | ||
316 | script << CScript::EncodeOP_N(nRequired); | |
317 | BOOST_FOREACH(const CPubKey& key, keys) | |
e9ca4280 | 318 | script << ToByteVector(key); |
0be990ba PW |
319 | script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; |
320 | return script; | |
321 | } |