Support 3 new multisignature IsStandard transactions
[novacoin.git] / src / test / multisig_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 #include <boost/tuple/tuple.hpp>
8
9 #include <openssl/ec.h>
10 #include <openssl/err.h>
11
12 #include "keystore.h"
13 #include "main.h"
14 #include "script.h"
15 #include "wallet.h"
16
17 using namespace std;
18 using namespace boost::assign;
19
20 typedef vector<unsigned char> valtype;
21
22 extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
23 extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType);
24 extern bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType);
25 extern bool Solver(const CScript& scriptPubKey, vector<vector<pair<opcodetype, valtype> > >& vSolutionsRet);
26
27 BOOST_AUTO_TEST_SUITE(multisig_tests)
28
29 CScript
30 sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)
31 {
32     uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);
33
34     CScript result;
35     result << OP_0; // CHECKMULTISIG bug workaround
36     BOOST_FOREACH(CKey key, keys)
37     {
38         vector<unsigned char> vchSig;
39         BOOST_CHECK(key.Sign(hash, vchSig));
40         vchSig.push_back((unsigned char)SIGHASH_ALL);
41         result << vchSig;
42     }
43     return result;
44 }
45
46 BOOST_AUTO_TEST_CASE(multisig_verify)
47 {
48     CKey key[4];
49     for (int i = 0; i < 4; i++)
50         key[i].MakeNewKey();
51
52     CScript a_and_b;
53     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
54
55     CScript a_or_b;
56     a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
57
58     CScript escrow;
59     escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
60
61     CTransaction txFrom;  // Funding transaction
62     txFrom.vout.resize(3);
63     txFrom.vout[0].scriptPubKey = a_and_b;
64     txFrom.vout[1].scriptPubKey = a_or_b;
65     txFrom.vout[2].scriptPubKey = escrow;
66
67     CTransaction txTo[3]; // Spending transaction
68     for (int i = 0; i < 3; i++)
69     {
70         txTo[i].vin.resize(1);
71         txTo[i].vout.resize(1);
72         txTo[i].vin[0].prevout.n = i;
73         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
74         txTo[i].vout[0].nValue = 1;
75     }
76
77     vector<CKey> keys;
78     CScript s;
79
80     // Test a AND b:
81     keys.clear();
82     keys += key[0],key[1]; // magic operator+= from boost.assign
83     s = sign_multisig(a_and_b, keys, txTo[0], 0);
84     BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, 0));
85
86     for (int i = 0; i < 4; i++)
87     {
88         keys.clear();
89         keys += key[i];
90         s = sign_multisig(a_and_b, keys, txTo[0], 0);
91         BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, 0), strprintf("a&b 1: %d", i));
92
93         keys.clear();
94         keys += key[1],key[i];
95         s = sign_multisig(a_and_b, keys, txTo[0], 0);
96         BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, 0), strprintf("a&b 2: %d", i));
97     }
98
99     // Test a OR b:
100     for (int i = 0; i < 4; i++)
101     {
102         keys.clear();
103         keys += key[i];
104         s = sign_multisig(a_or_b, keys, txTo[1], 0);
105         if (i == 0 || i == 1)
106             BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
107         else
108             BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
109     }
110     s.clear();
111     s << OP_0 << OP_0;
112     BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
113     s.clear();
114     s << OP_0 << OP_1;
115     BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
116
117
118     for (int i = 0; i < 4; i++)
119         for (int j = 0; j < 4; j++)
120         {
121             keys.clear();
122             keys += key[i],key[j];
123             s = sign_multisig(escrow, keys, txTo[2], 0);
124             if (i < j && i < 3 && j < 3)
125                 BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 1: %d %d", i, j));
126             else
127                 BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 2: %d %d", i, j));
128         }
129 }
130
131 BOOST_AUTO_TEST_CASE(multisig_IsStandard)
132 {
133     CKey key[3];
134     for (int i = 0; i < 3; i++)
135         key[i].MakeNewKey();
136
137     CScript a_and_b;
138     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
139     BOOST_CHECK(::IsStandard(a_and_b));
140
141     CScript a_or_b;
142     a_or_b  << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
143     BOOST_CHECK(::IsStandard(a_or_b));
144
145     CScript escrow;
146     escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
147     BOOST_CHECK(::IsStandard(escrow));
148 }
149
150 BOOST_AUTO_TEST_CASE(multisig_Solver1)
151 {
152     // Tests Solver() that returns lists of keys that are
153     // required to satisfy a ScriptPubKey
154     //
155     // Also tests IsMine() and ExtractAddress()
156     //
157     // Note: ExtractAddress for the multisignature transactions
158     // always returns false for this release, even if you have
159     // one key that would satisfy an (a|b) or 2-of-3 keys needed
160     // to spend an escrow transaction.
161     //
162     CBasicKeyStore keystore, emptykeystore;
163     CKey key[3];
164     CBitcoinAddress keyaddr[3];
165     for (int i = 0; i < 3; i++)
166     {
167         key[i].MakeNewKey();
168         keystore.AddKey(key[i]);
169         keyaddr[i].SetPubKey(key[i].GetPubKey());
170     }
171
172     {
173         vector<vector<pair<opcodetype, valtype> > > solutions;
174         CScript s;
175         s << key[0].GetPubKey() << OP_CHECKSIG;
176         BOOST_CHECK(Solver(s, solutions));
177         BOOST_CHECK(solutions.size() == 1);
178         if (solutions.size() == 1)
179             BOOST_CHECK(solutions[0].size() == 1);
180         CBitcoinAddress addr;
181         BOOST_CHECK(ExtractAddress(s, &keystore, addr));
182         BOOST_CHECK(addr == keyaddr[0]);
183         BOOST_CHECK(IsMine(keystore, s));
184         BOOST_CHECK(!IsMine(emptykeystore, s));
185     }
186     {
187         vector<vector<pair<opcodetype, valtype> > > solutions;
188         CScript s;
189         s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey()) << OP_EQUALVERIFY << OP_CHECKSIG;
190         BOOST_CHECK(Solver(s, solutions));
191         BOOST_CHECK(solutions.size() == 1);
192         if (solutions.size() == 1)
193             BOOST_CHECK(solutions[0].size() == 1);
194         CBitcoinAddress addr;
195         BOOST_CHECK(ExtractAddress(s, &keystore, addr));
196         BOOST_CHECK(addr == keyaddr[0]);
197         BOOST_CHECK(IsMine(keystore, s));
198         BOOST_CHECK(!IsMine(emptykeystore, s));
199     }
200     {
201         vector<vector<pair<opcodetype, valtype> > > solutions;
202         CScript s;
203         s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
204         BOOST_CHECK(Solver(s, solutions));
205         BOOST_CHECK(solutions.size() == 1);
206         if (solutions.size() == 1)
207             BOOST_CHECK(solutions[0].size() == 2);
208         CBitcoinAddress addr;
209         BOOST_CHECK(!ExtractAddress(s, &keystore, addr));
210         BOOST_CHECK(IsMine(keystore, s));
211         BOOST_CHECK(!IsMine(emptykeystore, s));
212     }
213     {
214         vector<vector<pair<opcodetype, valtype> > > solutions;
215         CScript s;
216         s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
217         BOOST_CHECK(Solver(s, solutions));
218         BOOST_CHECK(solutions.size() == 2);
219         if (solutions.size() == 2)
220         {
221             BOOST_CHECK(solutions[0].size() == 1);
222             BOOST_CHECK(solutions[1].size() == 1);
223         }
224         CBitcoinAddress addr;
225         BOOST_CHECK(ExtractAddress(s, &keystore, addr));
226         BOOST_CHECK(addr == keyaddr[0]);
227         BOOST_CHECK(IsMine(keystore, s));
228         BOOST_CHECK(!IsMine(emptykeystore, s));
229     }
230     {
231         vector<vector<pair<opcodetype, valtype> > > solutions;
232         CScript s;
233         s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
234         BOOST_CHECK(Solver(s, solutions));
235         BOOST_CHECK(solutions.size() == 3);
236         if (solutions.size() == 3)
237         {
238             BOOST_CHECK(solutions[0].size() == 2);
239             BOOST_CHECK(solutions[1].size() == 2);
240             BOOST_CHECK(solutions[2].size() == 2);
241         }
242     }
243 }
244
245 BOOST_AUTO_TEST_CASE(multisig_Sign)
246 {
247     // Test SignSignature() (and therefore the version of Solver() that signs transactions)
248     CBasicKeyStore keystore;
249     CKey key[4];
250     for (int i = 0; i < 4; i++)
251     {
252         key[i].MakeNewKey();
253         keystore.AddKey(key[i]);
254     }
255
256     CScript a_and_b;
257     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
258
259     CScript a_or_b;
260     a_or_b  << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
261
262     CScript escrow;
263     escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
264
265     CTransaction txFrom;  // Funding transaction
266     txFrom.vout.resize(3);
267     txFrom.vout[0].scriptPubKey = a_and_b;
268     txFrom.vout[1].scriptPubKey = a_or_b;
269     txFrom.vout[2].scriptPubKey = escrow;
270
271     CTransaction txTo[3]; // Spending transaction
272     for (int i = 0; i < 3; i++)
273     {
274         txTo[i].vin.resize(1);
275         txTo[i].vout.resize(1);
276         txTo[i].vin[0].prevout.n = i;
277         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
278         txTo[i].vout[0].nValue = 1;
279     }
280
281     for (int i = 0; i < 3; i++)
282     {
283         BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
284     }
285 }
286
287
288 BOOST_AUTO_TEST_SUITE_END()