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