make sure IsMine only returns true when we own all keys
[novacoin.git] / src / test / multisig_tests.cpp
index 459d112..0c2e41a 100644 (file)
@@ -20,9 +20,8 @@ using namespace boost::assign;
 typedef vector<unsigned char> valtype;
 
 extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool Solver(const CScript& scriptPubKey, vector<vector<pair<opcodetype, valtype> > >& vSolutionsRet);
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOpCount,
+                         int nHashType, bool fStrictOpEval);
 
 BOOST_AUTO_TEST_SUITE(multisig_tests)
 
@@ -76,24 +75,25 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
 
     vector<CKey> keys;
     CScript s;
+    int nUnused = 0;
 
     // Test a AND b:
     keys.clear();
     keys += key[0],key[1]; // magic operator+= from boost.assign
     s = sign_multisig(a_and_b, keys, txTo[0], 0);
-    BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, 0));
+    BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true));
 
     for (int i = 0; i < 4; i++)
     {
         keys.clear();
         keys += key[i];
         s = sign_multisig(a_and_b, keys, txTo[0], 0);
-        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, 0), strprintf("a&b 1: %d", i));
+        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true), strprintf("a&b 1: %d", i));
 
         keys.clear();
         keys += key[1],key[i];
         s = sign_multisig(a_and_b, keys, txTo[0], 0);
-        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, 0), strprintf("a&b 2: %d", i));
+        BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, nUnused, 0, true), strprintf("a&b 2: %d", i));
     }
 
     // Test a OR b:
@@ -103,16 +103,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
         keys += key[i];
         s = sign_multisig(a_or_b, keys, txTo[1], 0);
         if (i == 0 || i == 1)
-            BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
+            BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true), strprintf("a|b: %d", i));
         else
-            BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, 0), strprintf("a|b: %d", i));
+            BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true), strprintf("a|b: %d", i));
     }
     s.clear();
     s << OP_0 << OP_0;
-    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
+    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true));
     s.clear();
     s << OP_0 << OP_1;
-    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, 0));
+    BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, nUnused, 0, true));
 
 
     for (int i = 0; i < 4; i++)
@@ -122,16 +122,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
             keys += key[i],key[j];
             s = sign_multisig(escrow, keys, txTo[2], 0);
             if (i < j && i < 3 && j < 3)
-                BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 1: %d %d", i, j));
+                BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, nUnused, 0, true), strprintf("escrow 1: %d %d", i, j));
             else
-                BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, 0), strprintf("escrow 2: %d %d", i, j));
+                BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, nUnused, 0, true), strprintf("escrow 2: %d %d", i, j));
         }
 }
 
 BOOST_AUTO_TEST_CASE(multisig_IsStandard)
 {
-    CKey key[3];
-    for (int i = 0; i < 3; i++)
+    CKey key[4];
+    for (int i = 0; i < 4; i++)
         key[i].MakeNewKey();
 
     CScript a_and_b;
@@ -145,6 +145,21 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
     CScript escrow;
     escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
     BOOST_CHECK(::IsStandard(escrow));
+
+    CScript one_of_four;
+    one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG;
+    BOOST_CHECK(!::IsStandard(one_of_four));
+
+    CScript malformed[6];
+    malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+    malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
+    malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
+    malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG;
+    malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG;
+    malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey();
+
+    for (int i = 0; i < 6; i++)
+        BOOST_CHECK(!::IsStandard(malformed[i]));
 }
 
 BOOST_AUTO_TEST_CASE(multisig_Solver1)
@@ -159,7 +174,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     // one key that would satisfy an (a|b) or 2-of-3 keys needed
     // to spend an escrow transaction.
     //
-    CBasicKeyStore keystore, emptykeystore;
+    CBasicKeyStore keystore, emptykeystore, partialkeystore;
     CKey key[3];
     CBitcoinAddress keyaddr[3];
     for (int i = 0; i < 3; i++)
@@ -168,77 +183,71 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
         keystore.AddKey(key[i]);
         keyaddr[i].SetPubKey(key[i].GetPubKey());
     }
+    partialkeystore.AddKey(key[0]);
 
     {
-        vector<vector<pair<opcodetype, valtype> > > solutions;
+        vector<valtype> solutions;
+        txnouttype whichType;
         CScript s;
         s << key[0].GetPubKey() << OP_CHECKSIG;
-        BOOST_CHECK(Solver(s, solutions));
+        BOOST_CHECK(Solver(s, whichType, solutions));
         BOOST_CHECK(solutions.size() == 1);
-        if (solutions.size() == 1)
-            BOOST_CHECK(solutions[0].size() == 1);
         CBitcoinAddress addr;
-        BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+        BOOST_CHECK(ExtractAddress(s, addr));
         BOOST_CHECK(addr == keyaddr[0]);
         BOOST_CHECK(IsMine(keystore, s));
         BOOST_CHECK(!IsMine(emptykeystore, s));
     }
     {
-        vector<vector<pair<opcodetype, valtype> > > solutions;
+        vector<valtype> solutions;
+        txnouttype whichType;
         CScript s;
         s << OP_DUP << OP_HASH160 << Hash160(key[0].GetPubKey()) << OP_EQUALVERIFY << OP_CHECKSIG;
-        BOOST_CHECK(Solver(s, solutions));
+        BOOST_CHECK(Solver(s, whichType, solutions));
         BOOST_CHECK(solutions.size() == 1);
-        if (solutions.size() == 1)
-            BOOST_CHECK(solutions[0].size() == 1);
         CBitcoinAddress addr;
-        BOOST_CHECK(ExtractAddress(s, &keystore, addr));
+        BOOST_CHECK(ExtractAddress(s, addr));
         BOOST_CHECK(addr == keyaddr[0]);
         BOOST_CHECK(IsMine(keystore, s));
         BOOST_CHECK(!IsMine(emptykeystore, s));
     }
     {
-        vector<vector<pair<opcodetype, valtype> > > solutions;
+        vector<valtype> solutions;
+        txnouttype whichType;
         CScript s;
         s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
-        BOOST_CHECK(Solver(s, solutions));
-        BOOST_CHECK(solutions.size() == 1);
-        if (solutions.size() == 1)
-            BOOST_CHECK(solutions[0].size() == 2);
+        BOOST_CHECK(Solver(s, whichType, solutions));
+        BOOST_CHECK_EQUAL(solutions.size(), 4);
         CBitcoinAddress addr;
-        BOOST_CHECK(!ExtractAddress(s, &keystore, addr));
+        BOOST_CHECK(!ExtractAddress(s, addr));
         BOOST_CHECK(IsMine(keystore, s));
         BOOST_CHECK(!IsMine(emptykeystore, s));
+        BOOST_CHECK(!IsMine(partialkeystore, s));
     }
     {
-        vector<vector<pair<opcodetype, valtype> > > solutions;
+        vector<valtype> solutions;
+        txnouttype whichType;
         CScript s;
         s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
-        BOOST_CHECK(Solver(s, solutions));
-        BOOST_CHECK(solutions.size() == 2);
-        if (solutions.size() == 2)
-        {
-            BOOST_CHECK(solutions[0].size() == 1);
-            BOOST_CHECK(solutions[1].size() == 1);
-        }
-        CBitcoinAddress addr;
-        BOOST_CHECK(ExtractAddress(s, &keystore, addr));
-        BOOST_CHECK(addr == keyaddr[0]);
+        BOOST_CHECK(Solver(s, whichType, solutions));
+        BOOST_CHECK_EQUAL(solutions.size(), 4);
+        vector<CBitcoinAddress> addrs;
+        int nRequired;
+        BOOST_CHECK(ExtractAddresses(s, whichType, addrs, nRequired));
+        BOOST_CHECK(addrs[0] == keyaddr[0]);
+        BOOST_CHECK(addrs[1] == keyaddr[1]);
+        BOOST_CHECK(nRequired = 1);
         BOOST_CHECK(IsMine(keystore, s));
         BOOST_CHECK(!IsMine(emptykeystore, s));
+        BOOST_CHECK(!IsMine(partialkeystore, s));
     }
     {
-        vector<vector<pair<opcodetype, valtype> > > solutions;
+        vector<valtype> solutions;
+        txnouttype whichType;
         CScript s;
         s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
-        BOOST_CHECK(Solver(s, solutions));
-        BOOST_CHECK(solutions.size() == 3);
-        if (solutions.size() == 3)
-        {
-            BOOST_CHECK(solutions[0].size() == 2);
-            BOOST_CHECK(solutions[1].size() == 2);
-            BOOST_CHECK(solutions[2].size() == 2);
-        }
+        BOOST_CHECK(Solver(s, whichType, solutions));
+        BOOST_CHECK(solutions.size() == 5);
     }
 }