Remove not-used-anywhere scriptPrereq from SignSignature()
[novacoin.git] / src / test / script_op_eval_tests.cpp
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>
7
8 #include "../main.h"
9 #include "../script.h"
10 #include "../wallet.h"
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);
16 extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOps,
17                          int nHashType, bool fStrictOpEval);
18
19 BOOST_AUTO_TEST_SUITE(script_op_eval_tests)
20
21 BOOST_AUTO_TEST_CASE(script_op_eval1)
22 {
23     // OP_EVAL looks like this:
24     // scriptSig:    <sig> <sig...> <serialized_script>
25     // scriptPubKey: DUP HASH160 <hash> EQUALVERIFY EVAL
26
27     // Test SignSignature() (and therefore the version of Solver() that signs transactions)
28     CBasicKeyStore keystore;
29     CKey key[4];
30     for (int i = 0; i < 4; i++)
31     {
32         key[i].MakeNewKey();
33         keystore.AddKey(key[i]);
34     }
35
36     // 8 Scripts: checking all combinations of
37     // different keys, straight/EVAL, pubkey/pubkeyhash
38     CScript standardScripts[4];
39     standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG;
40     standardScripts[1].SetBitcoinAddress(key[1].GetPubKey());
41     standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG;
42     standardScripts[3].SetBitcoinAddress(key[2].GetPubKey());
43     CScript evalScripts[4];
44     uint160 sigScriptHashes[4];
45     for (int i = 0; i < 4; i++)
46     {
47         sigScriptHashes[i] = Hash160(standardScripts[i]);
48         keystore.AddCScript(sigScriptHashes[i], standardScripts[i]);
49         evalScripts[i] << OP_DUP << OP_HASH160 << sigScriptHashes[i] << OP_EQUALVERIFY << OP_EVAL;
50     }
51
52     CTransaction txFrom;  // Funding transaction:
53     txFrom.vout.resize(8);
54     for (int i = 0; i < 4; i++)
55     {
56         txFrom.vout[i].scriptPubKey = evalScripts[i];
57         txFrom.vout[i+4].scriptPubKey = standardScripts[i];
58     }
59     BOOST_CHECK(txFrom.IsStandard());
60
61     CTransaction txTo[8]; // Spending transactions
62     for (int i = 0; i < 8; i++)
63     {
64         txTo[i].vin.resize(1);
65         txTo[i].vout.resize(1);
66         txTo[i].vin[0].prevout.n = i;
67         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
68         txTo[i].vout[0].nValue = 1;
69         BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
70     }
71     for (int i = 0; i < 8; i++)
72     {
73         BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
74     }
75     // All of the above should be OK, and the txTos have valid signatures
76     // Check to make sure signature verification fails if we use the wrong ScriptSig:
77     for (int i = 0; i < 8; i++)
78         for (int j = 0; j < 8; j++)
79         {
80             CScript sigSave = txTo[i].vin[0].scriptSig;
81             txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
82             int nUnused = 0;
83             bool sigOK = VerifySignature(txFrom, txTo[i], 0, nUnused);
84             if (i == j)
85                 BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
86             else
87                 BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
88             txTo[i].vin[0].scriptSig = sigSave;
89         }
90 }
91
92 BOOST_AUTO_TEST_CASE(script_op_eval2)
93 {
94     // Test OP_EVAL edge cases
95
96     // Make sure infinite recursion fails to validate:
97     CScript infiniteRecurse;
98     infiniteRecurse << OP_DUP << OP_EVAL;
99
100     uint160 infiniteRecurseHash = Hash160(infiniteRecurse);
101
102     CScript fund1;
103     fund1 << OP_DUP << OP_HASH160 << infiniteRecurseHash << OP_EQUALVERIFY << OP_EVAL;
104
105     CTransaction txFrom1;  // Funding transaction:
106     txFrom1.vout.resize(1);
107     txFrom1.vout[0].scriptPubKey = fund1;
108
109     BOOST_CHECK(txFrom1.IsStandard()); // Looks like a standard transaction until you try to spend it
110
111     std::vector<unsigned char> infiniteRecurseSerialized(infiniteRecurse);
112
113     CTransaction txTo1;
114     txTo1.vin.resize(1);
115     txTo1.vout.resize(1);
116     txTo1.vin[0].prevout.n = 0;
117     txTo1.vin[0].prevout.hash = txFrom1.GetHash();
118     txTo1.vin[0].scriptSig = CScript() << infiniteRecurseSerialized << infiniteRecurseSerialized;
119     txTo1.vout[0].nValue = 1;
120
121     int nUnused1 = 0;
122     BOOST_CHECK(!VerifyScript(txTo1.vin[0].scriptSig, txFrom1.vout[0].scriptPubKey, txTo1, 0, nUnused1, 0, true));
123     BOOST_CHECK(!VerifySignature(txFrom1, txTo1, 0, nUnused1, true));
124
125     // Make sure 3-level-deep recursion fails to validate:
126     CScript recurse3;
127     recurse3 << OP_EVAL;
128
129     uint160 recurse3Hash = Hash160(recurse3);
130
131     CScript fund2;
132     fund2 << OP_DUP << OP_HASH160 << recurse3Hash << OP_EQUALVERIFY << OP_EVAL;
133
134     CTransaction txFrom2;  // Funding transaction:
135     txFrom2.vout.resize(1);
136     txFrom2.vout[0].scriptPubKey = fund2;
137
138     BOOST_CHECK(txFrom2.IsStandard()); // Looks like a standard transaction until you try to spend it
139
140     std::vector<unsigned char> recurse3Serialized(recurse3);
141     CScript op1Script = CScript() << OP_1;
142     std::vector<unsigned char> op1Serialized(op1Script);
143
144     CTransaction txTo2;
145     txTo2.vin.resize(1);
146     txTo2.vout.resize(1);
147     txTo2.vin[0].prevout.n = 0;
148     txTo2.vin[0].prevout.hash = txFrom2.GetHash();
149     txTo2.vin[0].scriptSig = CScript() << op1Serialized << recurse3Serialized << recurse3Serialized;
150     txTo2.vout[0].nValue = 1;
151
152     int nUnused2 = 0;
153     BOOST_CHECK(!VerifyScript(txTo2.vin[0].scriptSig, txFrom2.vout[0].scriptPubKey, txTo2, 0, nUnused2, 0, true));
154     BOOST_CHECK(!VerifySignature(txFrom2, txTo2, 0, nUnused2, true));
155 }
156
157 BOOST_AUTO_TEST_CASE(script_op_eval3)
158 {
159     // Test the CScript::Set* methods
160     CBasicKeyStore keystore;
161     CKey key[4];
162     std::vector<CKey> keys;
163     for (int i = 0; i < 4; i++)
164     {
165         key[i].MakeNewKey();
166         keystore.AddKey(key[i]);
167         keys.push_back(key[i]);
168     }
169
170     CScript inner[4];
171     inner[0].SetBitcoinAddress(key[0].GetPubKey());
172     inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2));
173     inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2));
174     inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3));
175
176     CScript outer[4];
177     for (int i = 0; i < 4; i++)
178     {
179         outer[i].SetEval(inner[i]);
180         keystore.AddCScript(Hash160(inner[i]), inner[i]);
181     }
182
183     CTransaction txFrom;  // Funding transaction:
184     txFrom.vout.resize(4);
185     for (int i = 0; i < 4; i++)
186     {
187         txFrom.vout[i].scriptPubKey = outer[i];
188     }
189     BOOST_CHECK(txFrom.IsStandard());
190
191     CTransaction txTo[4]; // Spending transactions
192     for (int i = 0; i < 4; i++)
193     {
194         txTo[i].vin.resize(1);
195         txTo[i].vout.resize(1);
196         txTo[i].vin[0].prevout.n = i;
197         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
198         txTo[i].vout[0].nValue = 1;
199         txTo[i].vout[0].scriptPubKey = inner[i];
200         BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
201     }
202     for (int i = 0; i < 4; i++)
203     {
204         BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
205         BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i));
206     }
207 }
208
209 BOOST_AUTO_TEST_CASE(script_op_eval_backcompat1)
210 {
211     // Check backwards-incompatibility-testing code
212     CScript returnsEleven;
213     returnsEleven << OP_11;
214
215     // This should validate on new clients, but will
216     // be invalid on old clients (that interpret OP_EVAL as a no-op)
217     //  ... except there's a special rule that makes new clients reject
218     // it.
219     CScript fund;
220     fund << OP_EVAL << OP_11 << OP_EQUAL;
221
222     CTransaction txFrom;  // Funding transaction:
223     txFrom.vout.resize(1);
224     txFrom.vout[0].scriptPubKey = fund;
225
226     CTransaction txTo;
227     txTo.vin.resize(1);
228     txTo.vout.resize(1);
229     txTo.vin[0].prevout.n = 0;
230     txTo.vin[0].prevout.hash = txFrom.GetHash();
231     txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(returnsEleven);
232     txTo.vout[0].nValue = 1;
233
234     int nUnused = 0;
235     BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
236     BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused, true));
237 }
238
239 BOOST_AUTO_TEST_CASE(script_op_eval_switchover)
240 {
241     // Test OP_EVAL switchover code
242     CScript notValid;
243     notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
244
245     // This will be valid under old rules, invalid under new:
246     CScript fund;
247     fund << OP_EVAL;
248
249     CTransaction txFrom;  // Funding transaction:
250     txFrom.vout.resize(1);
251     txFrom.vout[0].scriptPubKey = fund;
252
253     CTransaction txTo;
254     txTo.vin.resize(1);
255     txTo.vout.resize(1);
256     txTo.vin[0].prevout.n = 0;
257     txTo.vin[0].prevout.hash = txFrom.GetHash();
258     txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(notValid);
259     txTo.vout[0].nValue = 1;
260
261     int nUnused = 0;
262     BOOST_CHECK(VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, false));
263
264     // Under strict op_eval switchover, it should be considered invalid:
265     BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
266 }
267
268 BOOST_AUTO_TEST_SUITE_END()