Line data Source code
1 : // Copyright (c) 2012-2013 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include "key.h"
6 : #include "keystore.h"
7 : #include "main.h"
8 : #include "policy/policy.h"
9 : #include "script/script.h"
10 : #include "script/script_error.h"
11 : #include "script/sign.h"
12 : #include "test/test_bitcoin.h"
13 :
14 : #ifdef ENABLE_WALLET
15 : #include "wallet/wallet_ismine.h"
16 : #endif
17 :
18 : #include <vector>
19 :
20 : #include <boost/test/unit_test.hpp>
21 :
22 : using namespace std;
23 :
24 : // Helpers:
25 : static std::vector<unsigned char>
26 : Serialize(const CScript& s)
27 : {
28 3 : std::vector<unsigned char> sSerialized(s);
29 : return sSerialized;
30 : }
31 :
32 : static bool
33 4 : Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
34 : {
35 : // Create dummy to/from transactions:
36 4 : CMutableTransaction txFrom;
37 8 : txFrom.vout.resize(1);
38 4 : txFrom.vout[0].scriptPubKey = scriptPubKey;
39 :
40 4 : CMutableTransaction txTo;
41 8 : txTo.vin.resize(1);
42 8 : txTo.vout.resize(1);
43 4 : txTo.vin[0].prevout.n = 0;
44 4 : txTo.vin[0].prevout.hash = txFrom.GetHash();
45 4 : txTo.vin[0].scriptSig = scriptSig;
46 4 : txTo.vout[0].nValue = 1;
47 :
48 8 : return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
49 : }
50 :
51 :
52 1 : BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup)
53 :
54 6 : BOOST_AUTO_TEST_CASE(sign)
55 : {
56 1 : LOCK(cs_main);
57 : // Pay-to-script-hash looks like this:
58 : // scriptSig: <sig> <sig...> <serialized_script>
59 : // scriptPubKey: HASH160 <hash> EQUAL
60 :
61 : // Test SignSignature() (and therefore the version of Solver() that signs transactions)
62 2 : CBasicKeyStore keystore;
63 9 : CKey key[4];
64 4 : for (int i = 0; i < 4; i++)
65 : {
66 4 : key[i].MakeNewKey(true);
67 4 : keystore.AddKey(key[i]);
68 : }
69 :
70 : // 8 Scripts: checking all combinations of
71 : // different keys, straight/P2SH, pubkey/pubkeyhash
72 9 : CScript standardScripts[4];
73 2 : standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
74 4 : standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID());
75 2 : standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
76 4 : standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID());
77 10 : CScript evalScripts[4];
78 4 : for (int i = 0; i < 4; i++)
79 : {
80 4 : keystore.AddCScript(standardScripts[i]);
81 16 : evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i]));
82 : }
83 :
84 1 : CMutableTransaction txFrom; // Funding transaction:
85 : string reason;
86 2 : txFrom.vout.resize(8);
87 5 : for (int i = 0; i < 4; i++)
88 : {
89 8 : txFrom.vout[i].scriptPubKey = evalScripts[i];
90 8 : txFrom.vout[i].nValue = COIN;
91 8 : txFrom.vout[i+4].scriptPubKey = standardScripts[i];
92 8 : txFrom.vout[i+4].nValue = COIN;
93 : }
94 9 : BOOST_CHECK(IsStandardTx(txFrom, reason));
95 :
96 17 : CMutableTransaction txTo[8]; // Spending transactions
97 9 : for (int i = 0; i < 8; i++)
98 : {
99 16 : txTo[i].vin.resize(1);
100 16 : txTo[i].vout.resize(1);
101 8 : txTo[i].vin[0].prevout.n = i;
102 8 : txTo[i].vin[0].prevout.hash = txFrom.GetHash();
103 8 : txTo[i].vout[0].nValue = 1;
104 : #ifdef ENABLE_WALLET
105 72 : BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
106 : #endif
107 : }
108 9 : for (int i = 0; i < 8; i++)
109 : {
110 72 : BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
111 : }
112 : // All of the above should be OK, and the txTos have valid signatures
113 : // Check to make sure signature verification fails if we use the wrong ScriptSig:
114 9 : for (int i = 0; i < 8; i++)
115 72 : for (int j = 0; j < 8; j++)
116 : {
117 64 : CScript sigSave = txTo[i].vin[0].scriptSig;
118 64 : txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
119 320 : bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
120 64 : if (i == j)
121 64 : BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
122 : else
123 448 : BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
124 64 : txTo[i].vin[0].scriptSig = sigSave;
125 : }
126 1 : }
127 :
128 6 : BOOST_AUTO_TEST_CASE(norecurse)
129 : {
130 : ScriptError err;
131 : // Make sure only the outer pay-to-script-hash does the
132 : // extra-validation thing:
133 : CScript invalidAsScript;
134 1 : invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE;
135 :
136 3 : CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript));
137 :
138 : CScript scriptSig;
139 2 : scriptSig << Serialize(invalidAsScript);
140 :
141 : // Should not verify, because it will try to execute OP_INVALIDOPCODE
142 8 : BOOST_CHECK(!Verify(scriptSig, p2sh, true, err));
143 7 : BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err));
144 :
145 : // Try to recur, and verification should succeed because
146 : // the inner HASH160 <> EQUAL should only check the hash:
147 3 : CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh));
148 : CScript scriptSig2;
149 3 : scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh);
150 :
151 8 : BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err));
152 7 : BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
153 1 : }
154 :
155 6 : BOOST_AUTO_TEST_CASE(set)
156 : {
157 1 : LOCK(cs_main);
158 : // Test the CScript::Set* methods
159 2 : CBasicKeyStore keystore;
160 9 : CKey key[4];
161 : std::vector<CPubKey> keys;
162 5 : for (int i = 0; i < 4; i++)
163 : {
164 4 : key[i].MakeNewKey(true);
165 4 : keystore.AddKey(key[i]);
166 4 : keys.push_back(key[i].GetPubKey());
167 : }
168 :
169 9 : CScript inner[4];
170 4 : inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID());
171 5 : inner[1] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
172 5 : inner[2] = GetScriptForMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
173 5 : inner[3] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3));
174 :
175 10 : CScript outer[4];
176 4 : for (int i = 0; i < 4; i++)
177 : {
178 16 : outer[i] = GetScriptForDestination(CScriptID(inner[i]));
179 4 : keystore.AddCScript(inner[i]);
180 : }
181 :
182 1 : CMutableTransaction txFrom; // Funding transaction:
183 : string reason;
184 2 : txFrom.vout.resize(4);
185 5 : for (int i = 0; i < 4; i++)
186 : {
187 8 : txFrom.vout[i].scriptPubKey = outer[i];
188 8 : txFrom.vout[i].nValue = CENT;
189 : }
190 9 : BOOST_CHECK(IsStandardTx(txFrom, reason));
191 :
192 9 : CMutableTransaction txTo[4]; // Spending transactions
193 5 : for (int i = 0; i < 4; i++)
194 : {
195 8 : txTo[i].vin.resize(1);
196 8 : txTo[i].vout.resize(1);
197 4 : txTo[i].vin[0].prevout.n = i;
198 4 : txTo[i].vin[0].prevout.hash = txFrom.GetHash();
199 4 : txTo[i].vout[0].nValue = 1*CENT;
200 4 : txTo[i].vout[0].scriptPubKey = inner[i];
201 : #ifdef ENABLE_WALLET
202 36 : BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
203 : #endif
204 : }
205 5 : for (int i = 0; i < 4; i++)
206 : {
207 36 : BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
208 36 : BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i));
209 : }
210 1 : }
211 :
212 6 : BOOST_AUTO_TEST_CASE(is)
213 : {
214 : // Test CScript::IsPayToScriptHash()
215 : uint160 dummy;
216 : CScript p2sh;
217 2 : p2sh << OP_HASH160 << ToByteVector(dummy) << OP_EQUAL;
218 8 : BOOST_CHECK(p2sh.IsPayToScriptHash());
219 :
220 : // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes:
221 : static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
222 9 : BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash());
223 : static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
224 9 : BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash());
225 : static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
226 9 : BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash());
227 : static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
228 9 : BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash());
229 :
230 : CScript not_p2sh;
231 8 : BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
232 :
233 3 : not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << ToByteVector(dummy) << OP_EQUAL;
234 8 : BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
235 :
236 2 : not_p2sh.clear(); not_p2sh << OP_NOP << ToByteVector(dummy) << OP_EQUAL;
237 8 : BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
238 :
239 2 : not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << OP_CHECKSIG;
240 8 : BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
241 1 : }
242 :
243 6 : BOOST_AUTO_TEST_CASE(switchover)
244 : {
245 : // Test switch over code
246 : CScript notValid;
247 : ScriptError err;
248 1 : notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
249 : CScript scriptSig;
250 2 : scriptSig << Serialize(notValid);
251 :
252 3 : CScript fund = GetScriptForDestination(CScriptID(notValid));
253 :
254 :
255 : // Validation should succeed under old rules (hash is correct):
256 8 : BOOST_CHECK(Verify(scriptSig, fund, false, err));
257 7 : BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
258 : // Fail under new:
259 8 : BOOST_CHECK(!Verify(scriptSig, fund, true, err));
260 7 : BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err));
261 1 : }
262 :
263 6 : BOOST_AUTO_TEST_CASE(AreInputsStandard)
264 : {
265 1 : LOCK(cs_main);
266 : CCoinsView coinsDummy;
267 2 : CCoinsViewCache coins(&coinsDummy);
268 2 : CBasicKeyStore keystore;
269 13 : CKey key[6];
270 : vector<CPubKey> keys;
271 7 : for (int i = 0; i < 6; i++)
272 : {
273 6 : key[i].MakeNewKey(true);
274 6 : keystore.AddKey(key[i]);
275 : }
276 3 : for (int i = 0; i < 3; i++)
277 3 : keys.push_back(key[i].GetPubKey());
278 :
279 1 : CMutableTransaction txFrom;
280 2 : txFrom.vout.resize(7);
281 :
282 : // First three are standard:
283 3 : CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID());
284 1 : keystore.AddCScript(pay1);
285 1 : CScript pay1of3 = GetScriptForMultisig(1, keys);
286 :
287 4 : txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); // P2SH (OP_CHECKSIG)
288 1 : txFrom.vout[0].nValue = 1000;
289 1 : txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG
290 1 : txFrom.vout[1].nValue = 2000;
291 1 : txFrom.vout[2].scriptPubKey = pay1of3; // ordinary OP_CHECKMULTISIG
292 1 : txFrom.vout[2].nValue = 3000;
293 :
294 : // vout[3] is complicated 1-of-3 AND 2-of-3
295 : // ... that is OK if wrapped in P2SH:
296 : CScript oneAndTwo;
297 4 : oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey());
298 1 : oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY;
299 4 : oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey());
300 1 : oneAndTwo << OP_3 << OP_CHECKMULTISIG;
301 1 : keystore.AddCScript(oneAndTwo);
302 4 : txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo));
303 1 : txFrom.vout[3].nValue = 4000;
304 :
305 : // vout[4] is max sigops:
306 1 : CScript fifteenSigops; fifteenSigops << OP_1;
307 15 : for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++)
308 30 : fifteenSigops << ToByteVector(key[i%3].GetPubKey());
309 1 : fifteenSigops << OP_15 << OP_CHECKMULTISIG;
310 1 : keystore.AddCScript(fifteenSigops);
311 4 : txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops));
312 1 : txFrom.vout[4].nValue = 5000;
313 :
314 : // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS
315 1 : CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG;
316 1 : keystore.AddCScript(sixteenSigops);
317 4 : txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops));
318 1 : txFrom.vout[5].nValue = 5000;
319 1 : CScript twentySigops; twentySigops << OP_CHECKMULTISIG;
320 1 : keystore.AddCScript(twentySigops);
321 4 : txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops));
322 1 : txFrom.vout[6].nValue = 6000;
323 :
324 3 : coins.ModifyCoins(txFrom.GetHash())->FromTx(txFrom, 0);
325 :
326 1 : CMutableTransaction txTo;
327 2 : txTo.vout.resize(1);
328 4 : txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());
329 :
330 2 : txTo.vin.resize(5);
331 6 : for (int i = 0; i < 5; i++)
332 : {
333 10 : txTo.vin[i].prevout.n = i;
334 10 : txTo.vin[i].prevout.hash = txFrom.GetHash();
335 : }
336 9 : BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
337 9 : BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
338 9 : BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
339 : // SignSignature doesn't know how to sign these. We're
340 : // not testing validating signatures, so just create
341 : // dummy signatures that DO include the correct P2SH scripts:
342 2 : txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo);
343 2 : txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops);
344 :
345 9 : BOOST_CHECK(::AreInputsStandard(txTo, coins));
346 : // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
347 6 : BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
348 :
349 : // Make sure adding crap to the scriptSigs makes them non-standard:
350 3 : for (int i = 0; i < 3; i++)
351 : {
352 6 : CScript t = txTo.vin[i].scriptSig;
353 12 : txTo.vin[i].scriptSig = (CScript() << 11) + t;
354 27 : BOOST_CHECK(!::AreInputsStandard(txTo, coins));
355 6 : txTo.vin[i].scriptSig = t;
356 : }
357 :
358 1 : CMutableTransaction txToNonStd1;
359 2 : txToNonStd1.vout.resize(1);
360 4 : txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());
361 1 : txToNonStd1.vout[0].nValue = 1000;
362 2 : txToNonStd1.vin.resize(1);
363 1 : txToNonStd1.vin[0].prevout.n = 5;
364 1 : txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
365 2 : txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops);
366 :
367 9 : BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins));
368 6 : BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
369 :
370 1 : CMutableTransaction txToNonStd2;
371 2 : txToNonStd2.vout.resize(1);
372 4 : txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());
373 1 : txToNonStd2.vout[0].nValue = 1000;
374 2 : txToNonStd2.vin.resize(1);
375 1 : txToNonStd2.vin[0].prevout.n = 6;
376 1 : txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
377 2 : txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops);
378 :
379 9 : BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins));
380 6 : BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
381 1 : }
382 :
383 3 : BOOST_AUTO_TEST_SUITE_END()
|