1 #include <boost/assert.hpp>
2 #include <boost/assign/list_of.hpp>
3 #include <boost/assign/list_inserter.hpp>
4 #include <boost/assign/std/vector.hpp>
5 #include <boost/test/unit_test.hpp>
6 #include <boost/foreach.hpp>
10 #include "../wallet.h"
14 // Test routines internal to script.cpp:
15 extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
16 extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
17 bool fValidatePayToScriptHash, int nHashType);
20 static std::vector<unsigned char>
21 Serialize(const CScript& s)
23 std::vector<unsigned char> sSerialized(s);
28 Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
30 // Create dummy to/from transactions:
32 txFrom.vout.resize(1);
33 txFrom.vout[0].scriptPubKey = scriptPubKey;
38 txTo.vin[0].prevout.n = 0;
39 txTo.vin[0].prevout.hash = txFrom.GetHash();
40 txTo.vin[0].scriptSig = scriptSig;
41 txTo.vout[0].nValue = 1;
43 return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, 0);
47 BOOST_AUTO_TEST_SUITE(script_P2SH_tests)
49 BOOST_AUTO_TEST_CASE(sign)
51 // Pay-to-script-hash looks like this:
52 // scriptSig: <sig> <sig...> <serialized_script>
53 // scriptPubKey: HASH160 <hash> EQUAL
55 // Test SignSignature() (and therefore the version of Solver() that signs transactions)
56 CBasicKeyStore keystore;
58 for (int i = 0; i < 4; i++)
60 key[i].MakeNewKey(true);
61 keystore.AddKey(key[i]);
64 // 8 Scripts: checking all combinations of
65 // different keys, straight/P2SH, pubkey/pubkeyhash
66 CScript standardScripts[4];
67 standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG;
68 standardScripts[1].SetDestination(key[1].GetPubKey().GetID());
69 standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG;
70 standardScripts[3].SetDestination(key[2].GetPubKey().GetID());
71 CScript evalScripts[4];
72 for (int i = 0; i < 4; i++)
74 keystore.AddCScript(standardScripts[i]);
75 evalScripts[i].SetDestination(standardScripts[i].GetID());
78 CTransaction txFrom; // Funding transaction:
79 txFrom.vout.resize(8);
80 for (int i = 0; i < 4; i++)
82 txFrom.vout[i].scriptPubKey = evalScripts[i];
83 txFrom.vout[i+4].scriptPubKey = standardScripts[i];
85 BOOST_CHECK(txFrom.IsStandard());
87 CTransaction txTo[8]; // Spending transactions
88 for (int i = 0; i < 8; i++)
90 txTo[i].vin.resize(1);
91 txTo[i].vout.resize(1);
92 txTo[i].vin[0].prevout.n = i;
93 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
94 txTo[i].vout[0].nValue = 1;
95 BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
97 for (int i = 0; i < 8; i++)
99 BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
101 // All of the above should be OK, and the txTos have valid signatures
102 // Check to make sure signature verification fails if we use the wrong ScriptSig:
103 for (int i = 0; i < 8; i++)
104 for (int j = 0; j < 8; j++)
106 CScript sigSave = txTo[i].vin[0].scriptSig;
107 txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
108 bool sigOK = VerifySignature(txFrom, txTo[i], 0, true, 0);
110 BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
112 BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
113 txTo[i].vin[0].scriptSig = sigSave;
117 BOOST_AUTO_TEST_CASE(norecurse)
119 // Make sure only the outer pay-to-script-hash does the
120 // extra-validation thing:
121 CScript invalidAsScript;
122 invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE;
125 p2sh.SetDestination(invalidAsScript.GetID());
128 scriptSig << Serialize(invalidAsScript);
130 // Should not verify, because it will try to execute OP_INVALIDOPCODE
131 BOOST_CHECK(!Verify(scriptSig, p2sh, true));
133 // Try to recur, and verification should succeed because
134 // the inner HASH160 <> EQUAL should only check the hash:
136 p2sh2.SetDestination(p2sh.GetID());
138 scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh);
140 BOOST_CHECK(Verify(scriptSig2, p2sh2, true));
143 BOOST_AUTO_TEST_CASE(set)
145 // Test the CScript::Set* methods
146 CBasicKeyStore keystore;
148 std::vector<CKey> keys;
149 for (int i = 0; i < 4; i++)
151 key[i].MakeNewKey(true);
152 keystore.AddKey(key[i]);
153 keys.push_back(key[i]);
157 inner[0].SetDestination(key[0].GetPubKey().GetID());
158 inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2));
159 inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2));
160 inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3));
163 for (int i = 0; i < 4; i++)
165 outer[i].SetDestination(inner[i].GetID());
166 keystore.AddCScript(inner[i]);
169 CTransaction txFrom; // Funding transaction:
170 txFrom.vout.resize(4);
171 for (int i = 0; i < 4; i++)
173 txFrom.vout[i].scriptPubKey = outer[i];
175 BOOST_CHECK(txFrom.IsStandard());
177 CTransaction txTo[4]; // Spending transactions
178 for (int i = 0; i < 4; i++)
180 txTo[i].vin.resize(1);
181 txTo[i].vout.resize(1);
182 txTo[i].vin[0].prevout.n = i;
183 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
184 txTo[i].vout[0].nValue = 1;
185 txTo[i].vout[0].scriptPubKey = inner[i];
186 BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
188 for (int i = 0; i < 4; i++)
190 BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
191 BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i));
195 BOOST_AUTO_TEST_CASE(is)
197 // Test CScript::IsPayToScriptHash()
200 p2sh << OP_HASH160 << dummy << OP_EQUAL;
201 BOOST_CHECK(p2sh.IsPayToScriptHash());
203 // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes:
204 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 };
205 BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash());
206 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 };
207 BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash());
208 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 };
209 BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash());
210 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 };
211 BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash());
214 BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
216 not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << dummy << OP_EQUAL;
217 BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
219 not_p2sh.clear(); not_p2sh << OP_NOP << dummy << OP_EQUAL;
220 BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
222 not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << OP_CHECKSIG;
223 BOOST_CHECK(!not_p2sh.IsPayToScriptHash());
226 BOOST_AUTO_TEST_CASE(switchover)
228 // Test switch over code
230 notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
232 scriptSig << Serialize(notValid);
235 fund.SetDestination(notValid.GetID());
238 // Validation should succeed under old rules (hash is correct):
239 BOOST_CHECK(Verify(scriptSig, fund, false));
241 BOOST_CHECK(!Verify(scriptSig, fund, true));
244 BOOST_AUTO_TEST_CASE(AreInputsStandard)
246 std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs;
247 CBasicKeyStore keystore;
250 for (int i = 0; i < 3; i++)
252 key[i].MakeNewKey(true);
253 keystore.AddKey(key[i]);
254 keys.push_back(key[i]);
258 txFrom.vout.resize(6);
260 // First three are standard:
261 CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID());
262 keystore.AddCScript(pay1);
263 CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID());
264 CScript pay1of3; pay1of3.SetMultisig(1, keys);
266 txFrom.vout[0].scriptPubKey = payScriptHash1;
267 txFrom.vout[1].scriptPubKey = pay1;
268 txFrom.vout[2].scriptPubKey = pay1of3;
270 // Last three non-standard:
272 keystore.AddCScript(empty);
273 txFrom.vout[3].scriptPubKey = empty;
274 // Can't use SetPayToScriptHash, it checks for the empty Script. So:
275 txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL;
278 for (int i = 0; i < 11; i++)
279 oneOfEleven << key[0].GetPubKey();
280 oneOfEleven << OP_11 << OP_CHECKMULTISIG;
281 txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID());
283 mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom);
287 txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
290 txTo.vin[0].prevout.n = 0;
291 txTo.vin[0].prevout.hash = txFrom.GetHash();
292 BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
293 txTo.vin[1].prevout.n = 1;
294 txTo.vin[1].prevout.hash = txFrom.GetHash();
295 BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
296 txTo.vin[2].prevout.n = 2;
297 txTo.vin[2].prevout.hash = txFrom.GetHash();
298 BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
300 BOOST_CHECK(txTo.AreInputsStandard(mapInputs));
301 BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1);
303 // Make sure adding crap to the scriptSigs makes them non-standard:
304 for (int i = 0; i < 3; i++)
306 CScript t = txTo.vin[i].scriptSig;
307 txTo.vin[i].scriptSig = (CScript() << 11) + t;
308 BOOST_CHECK(!txTo.AreInputsStandard(mapInputs));
309 txTo.vin[i].scriptSig = t;
312 CTransaction txToNonStd;
313 txToNonStd.vout.resize(1);
314 txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
315 txToNonStd.vin.resize(2);
316 txToNonStd.vin[0].prevout.n = 4;
317 txToNonStd.vin[0].prevout.hash = txFrom.GetHash();
318 txToNonStd.vin[0].scriptSig << Serialize(empty);
319 txToNonStd.vin[1].prevout.n = 5;
320 txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
321 txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
323 BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs));
324 BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(mapInputs), 11);
326 txToNonStd.vin[0].scriptSig.clear();
327 BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs));
330 BOOST_AUTO_TEST_SUITE_END()