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