]>
Commit | Line | Data |
---|---|---|
51ed9ec9 BD |
1 | #include "script.h" |
2 | ||
3 | #include "key.h" | |
4 | #include "keystore.h" | |
5 | #include "main.h" | |
6 | #include "script.h" | |
922e8e29 | 7 | |
51ed9ec9 BD |
8 | #include <vector> |
9 | ||
10 | #include <boost/test/unit_test.hpp> | |
922e8e29 GA |
11 | |
12 | using namespace std; | |
13 | ||
14 | // Test routines internal to script.cpp: | |
15 | extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); | |
922e8e29 GA |
16 | |
17 | // Helpers: | |
18 | static std::vector<unsigned char> | |
19 | Serialize(const CScript& s) | |
20 | { | |
21 | std::vector<unsigned char> sSerialized(s); | |
22 | return sSerialized; | |
23 | } | |
24 | ||
25 | static bool | |
26 | Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) | |
27 | { | |
28 | // Create dummy to/from transactions: | |
29 | CTransaction txFrom; | |
30 | txFrom.vout.resize(1); | |
31 | txFrom.vout[0].scriptPubKey = scriptPubKey; | |
32 | ||
33 | CTransaction txTo; | |
34 | txTo.vin.resize(1); | |
35 | txTo.vout.resize(1); | |
36 | txTo.vin[0].prevout.n = 0; | |
37 | txTo.vin[0].prevout.hash = txFrom.GetHash(); | |
38 | txTo.vin[0].scriptSig = scriptSig; | |
39 | txTo.vout[0].nValue = 1; | |
40 | ||
99d0d0f3 | 41 | return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); |
922e8e29 GA |
42 | } |
43 | ||
44 | ||
45 | BOOST_AUTO_TEST_SUITE(script_P2SH_tests) | |
46 | ||
47 | BOOST_AUTO_TEST_CASE(sign) | |
48 | { | |
49 | // Pay-to-script-hash looks like this: | |
50 | // scriptSig: <sig> <sig...> <serialized_script> | |
51 | // scriptPubKey: HASH160 <hash> EQUAL | |
52 | ||
53 | // Test SignSignature() (and therefore the version of Solver() that signs transactions) | |
54 | CBasicKeyStore keystore; | |
55 | CKey key[4]; | |
56 | for (int i = 0; i < 4; i++) | |
57 | { | |
0d56f11a | 58 | key[i].MakeNewKey(true); |
922e8e29 GA |
59 | keystore.AddKey(key[i]); |
60 | } | |
61 | ||
62 | // 8 Scripts: checking all combinations of | |
63 | // different keys, straight/P2SH, pubkey/pubkeyhash | |
64 | CScript standardScripts[4]; | |
65 | standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG; | |
10254401 | 66 | standardScripts[1].SetDestination(key[1].GetPubKey().GetID()); |
922e8e29 | 67 | standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG; |
10254401 | 68 | standardScripts[3].SetDestination(key[2].GetPubKey().GetID()); |
922e8e29 GA |
69 | CScript evalScripts[4]; |
70 | for (int i = 0; i < 4; i++) | |
71 | { | |
72 | keystore.AddCScript(standardScripts[i]); | |
10254401 | 73 | evalScripts[i].SetDestination(standardScripts[i].GetID()); |
922e8e29 GA |
74 | } |
75 | ||
76 | CTransaction txFrom; // Funding transaction: | |
980bfe6e | 77 | string reason; |
922e8e29 GA |
78 | txFrom.vout.resize(8); |
79 | for (int i = 0; i < 4; i++) | |
80 | { | |
81 | txFrom.vout[i].scriptPubKey = evalScripts[i]; | |
8de9bb53 | 82 | txFrom.vout[i].nValue = COIN; |
922e8e29 | 83 | txFrom.vout[i+4].scriptPubKey = standardScripts[i]; |
8de9bb53 | 84 | txFrom.vout[i+4].nValue = COIN; |
922e8e29 | 85 | } |
980bfe6e | 86 | BOOST_CHECK(IsStandardTx(txFrom, reason)); |
922e8e29 GA |
87 | |
88 | CTransaction txTo[8]; // Spending transactions | |
89 | for (int i = 0; i < 8; i++) | |
90 | { | |
91 | txTo[i].vin.resize(1); | |
92 | txTo[i].vout.resize(1); | |
93 | txTo[i].vin[0].prevout.n = i; | |
94 | txTo[i].vin[0].prevout.hash = txFrom.GetHash(); | |
95 | txTo[i].vout[0].nValue = 1; | |
96 | BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); | |
97 | } | |
98 | for (int i = 0; i < 8; i++) | |
99 | { | |
100 | BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); | |
101 | } | |
102 | // All of the above should be OK, and the txTos have valid signatures | |
103 | // Check to make sure signature verification fails if we use the wrong ScriptSig: | |
104 | for (int i = 0; i < 8; i++) | |
105 | for (int j = 0; j < 8; j++) | |
106 | { | |
107 | CScript sigSave = txTo[i].vin[0].scriptSig; | |
108 | txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; | |
99d0d0f3 | 109 | bool sigOK = VerifySignature(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); |
922e8e29 GA |
110 | if (i == j) |
111 | BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); | |
112 | else | |
113 | BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j)); | |
114 | txTo[i].vin[0].scriptSig = sigSave; | |
115 | } | |
116 | } | |
117 | ||
118 | BOOST_AUTO_TEST_CASE(norecurse) | |
119 | { | |
120 | // Make sure only the outer pay-to-script-hash does the | |
121 | // extra-validation thing: | |
122 | CScript invalidAsScript; | |
123 | invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; | |
124 | ||
125 | CScript p2sh; | |
10254401 | 126 | p2sh.SetDestination(invalidAsScript.GetID()); |
922e8e29 GA |
127 | |
128 | CScript scriptSig; | |
129 | scriptSig << Serialize(invalidAsScript); | |
130 | ||
131 | // Should not verify, because it will try to execute OP_INVALIDOPCODE | |
132 | BOOST_CHECK(!Verify(scriptSig, p2sh, true)); | |
133 | ||
814efd6f | 134 | // Try to recur, and verification should succeed because |
922e8e29 GA |
135 | // the inner HASH160 <> EQUAL should only check the hash: |
136 | CScript p2sh2; | |
10254401 | 137 | p2sh2.SetDestination(p2sh.GetID()); |
922e8e29 GA |
138 | CScript scriptSig2; |
139 | scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); | |
140 | ||
141 | BOOST_CHECK(Verify(scriptSig2, p2sh2, true)); | |
142 | } | |
143 | ||
144 | BOOST_AUTO_TEST_CASE(set) | |
145 | { | |
146 | // Test the CScript::Set* methods | |
147 | CBasicKeyStore keystore; | |
148 | CKey key[4]; | |
dfa23b94 | 149 | std::vector<CPubKey> keys; |
922e8e29 GA |
150 | for (int i = 0; i < 4; i++) |
151 | { | |
0d56f11a | 152 | key[i].MakeNewKey(true); |
922e8e29 | 153 | keystore.AddKey(key[i]); |
dfa23b94 | 154 | keys.push_back(key[i].GetPubKey()); |
922e8e29 GA |
155 | } |
156 | ||
157 | CScript inner[4]; | |
10254401 | 158 | inner[0].SetDestination(key[0].GetPubKey().GetID()); |
dfa23b94 PW |
159 | inner[1].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2)); |
160 | inner[2].SetMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2)); | |
161 | inner[3].SetMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3)); | |
922e8e29 GA |
162 | |
163 | CScript outer[4]; | |
164 | for (int i = 0; i < 4; i++) | |
165 | { | |
10254401 | 166 | outer[i].SetDestination(inner[i].GetID()); |
922e8e29 GA |
167 | keystore.AddCScript(inner[i]); |
168 | } | |
169 | ||
170 | CTransaction txFrom; // Funding transaction: | |
980bfe6e | 171 | string reason; |
922e8e29 GA |
172 | txFrom.vout.resize(4); |
173 | for (int i = 0; i < 4; i++) | |
174 | { | |
175 | txFrom.vout[i].scriptPubKey = outer[i]; | |
8de9bb53 | 176 | txFrom.vout[i].nValue = CENT; |
922e8e29 | 177 | } |
980bfe6e | 178 | BOOST_CHECK(IsStandardTx(txFrom, reason)); |
922e8e29 GA |
179 | |
180 | CTransaction txTo[4]; // Spending transactions | |
181 | for (int i = 0; i < 4; i++) | |
182 | { | |
183 | txTo[i].vin.resize(1); | |
184 | txTo[i].vout.resize(1); | |
185 | txTo[i].vin[0].prevout.n = i; | |
186 | txTo[i].vin[0].prevout.hash = txFrom.GetHash(); | |
8de9bb53 | 187 | txTo[i].vout[0].nValue = 1*CENT; |
922e8e29 GA |
188 | txTo[i].vout[0].scriptPubKey = inner[i]; |
189 | BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); | |
190 | } | |
191 | for (int i = 0; i < 4; i++) | |
192 | { | |
193 | BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); | |
980bfe6e | 194 | BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); |
922e8e29 GA |
195 | } |
196 | } | |
197 | ||
198 | BOOST_AUTO_TEST_CASE(is) | |
199 | { | |
200 | // Test CScript::IsPayToScriptHash() | |
201 | uint160 dummy; | |
202 | CScript p2sh; | |
203 | p2sh << OP_HASH160 << dummy << OP_EQUAL; | |
204 | BOOST_CHECK(p2sh.IsPayToScriptHash()); | |
205 | ||
206 | // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes: | |
207 | 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 }; | |
208 | BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash()); | |
209 | 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 }; | |
210 | BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash()); | |
211 | 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 }; | |
212 | BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash()); | |
213 | 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 }; | |
214 | BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash()); | |
215 | ||
216 | CScript not_p2sh; | |
217 | BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); | |
218 | ||
219 | not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << dummy << OP_EQUAL; | |
220 | BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); | |
221 | ||
222 | not_p2sh.clear(); not_p2sh << OP_NOP << dummy << OP_EQUAL; | |
223 | BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); | |
224 | ||
225 | not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << OP_CHECKSIG; | |
226 | BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); | |
227 | } | |
228 | ||
229 | BOOST_AUTO_TEST_CASE(switchover) | |
230 | { | |
814efd6f | 231 | // Test switch over code |
922e8e29 GA |
232 | CScript notValid; |
233 | notValid << OP_11 << OP_12 << OP_EQUALVERIFY; | |
234 | CScript scriptSig; | |
235 | scriptSig << Serialize(notValid); | |
236 | ||
237 | CScript fund; | |
10254401 | 238 | fund.SetDestination(notValid.GetID()); |
922e8e29 GA |
239 | |
240 | ||
241 | // Validation should succeed under old rules (hash is correct): | |
242 | BOOST_CHECK(Verify(scriptSig, fund, false)); | |
243 | // Fail under new: | |
244 | BOOST_CHECK(!Verify(scriptSig, fund, true)); | |
245 | } | |
246 | ||
247 | BOOST_AUTO_TEST_CASE(AreInputsStandard) | |
248 | { | |
450cbb09 PW |
249 | CCoinsView coinsDummy; |
250 | CCoinsViewCache coins(coinsDummy); | |
922e8e29 GA |
251 | CBasicKeyStore keystore; |
252 | CKey key[3]; | |
dfa23b94 | 253 | vector<CPubKey> keys; |
922e8e29 GA |
254 | for (int i = 0; i < 3; i++) |
255 | { | |
0d56f11a | 256 | key[i].MakeNewKey(true); |
922e8e29 | 257 | keystore.AddKey(key[i]); |
dfa23b94 | 258 | keys.push_back(key[i].GetPubKey()); |
922e8e29 GA |
259 | } |
260 | ||
261 | CTransaction txFrom; | |
137d0685 | 262 | txFrom.vout.resize(6); |
922e8e29 GA |
263 | |
264 | // First three are standard: | |
10254401 | 265 | CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID()); |
922e8e29 | 266 | keystore.AddCScript(pay1); |
10254401 | 267 | CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID()); |
922e8e29 GA |
268 | CScript pay1of3; pay1of3.SetMultisig(1, keys); |
269 | ||
270 | txFrom.vout[0].scriptPubKey = payScriptHash1; | |
450cbb09 | 271 | txFrom.vout[0].nValue = 1000; |
922e8e29 | 272 | txFrom.vout[1].scriptPubKey = pay1; |
450cbb09 | 273 | txFrom.vout[1].nValue = 2000; |
922e8e29 | 274 | txFrom.vout[2].scriptPubKey = pay1of3; |
450cbb09 | 275 | txFrom.vout[2].nValue = 3000; |
922e8e29 | 276 | |
137d0685 | 277 | // Last three non-standard: |
922e8e29 GA |
278 | CScript empty; |
279 | keystore.AddCScript(empty); | |
280 | txFrom.vout[3].scriptPubKey = empty; | |
450cbb09 | 281 | txFrom.vout[3].nValue = 4000; |
922e8e29 GA |
282 | // Can't use SetPayToScriptHash, it checks for the empty Script. So: |
283 | txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL; | |
450cbb09 | 284 | txFrom.vout[4].nValue = 5000; |
137d0685 GA |
285 | CScript oneOfEleven; |
286 | oneOfEleven << OP_1; | |
287 | for (int i = 0; i < 11; i++) | |
288 | oneOfEleven << key[0].GetPubKey(); | |
289 | oneOfEleven << OP_11 << OP_CHECKMULTISIG; | |
10254401 | 290 | txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID()); |
450cbb09 | 291 | txFrom.vout[5].nValue = 6000; |
922e8e29 | 292 | |
450cbb09 | 293 | coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0)); |
922e8e29 GA |
294 | |
295 | CTransaction txTo; | |
296 | txTo.vout.resize(1); | |
10254401 | 297 | txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); |
922e8e29 GA |
298 | |
299 | txTo.vin.resize(3); | |
300 | txTo.vin[0].prevout.n = 0; | |
301 | txTo.vin[0].prevout.hash = txFrom.GetHash(); | |
302 | BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0)); | |
303 | txTo.vin[1].prevout.n = 1; | |
304 | txTo.vin[1].prevout.hash = txFrom.GetHash(); | |
305 | BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1)); | |
306 | txTo.vin[2].prevout.n = 2; | |
307 | txTo.vin[2].prevout.hash = txFrom.GetHash(); | |
308 | BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2)); | |
309 | ||
05df3fc6 EL |
310 | BOOST_CHECK(::AreInputsStandard(txTo, coins)); |
311 | BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 1U); | |
922e8e29 | 312 | |
39f0d968 GA |
313 | // Make sure adding crap to the scriptSigs makes them non-standard: |
314 | for (int i = 0; i < 3; i++) | |
315 | { | |
316 | CScript t = txTo.vin[i].scriptSig; | |
317 | txTo.vin[i].scriptSig = (CScript() << 11) + t; | |
05df3fc6 | 318 | BOOST_CHECK(!::AreInputsStandard(txTo, coins)); |
39f0d968 GA |
319 | txTo.vin[i].scriptSig = t; |
320 | } | |
321 | ||
922e8e29 GA |
322 | CTransaction txToNonStd; |
323 | txToNonStd.vout.resize(1); | |
10254401 | 324 | txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); |
450cbb09 | 325 | txToNonStd.vout[0].nValue = 1000; |
137d0685 | 326 | txToNonStd.vin.resize(2); |
922e8e29 GA |
327 | txToNonStd.vin[0].prevout.n = 4; |
328 | txToNonStd.vin[0].prevout.hash = txFrom.GetHash(); | |
329 | txToNonStd.vin[0].scriptSig << Serialize(empty); | |
137d0685 GA |
330 | txToNonStd.vin[1].prevout.n = 5; |
331 | txToNonStd.vin[1].prevout.hash = txFrom.GetHash(); | |
332 | txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven); | |
922e8e29 | 333 | |
05df3fc6 EL |
334 | BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins)); |
335 | BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd, coins), 11U); | |
922e8e29 GA |
336 | |
337 | txToNonStd.vin[0].scriptSig.clear(); | |
05df3fc6 | 338 | BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins)); |
922e8e29 GA |
339 | } |
340 | ||
341 | BOOST_AUTO_TEST_SUITE_END() |