LCOV - code coverage report
Current view: top level - src/test - multisig_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 203 203 100.0 %
Date: 2025-02-23 09:33:43 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2013 The Bitcoin Core developers
       2             : // Copyright (c) 2019-2021 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "key.h"
       7             : #include "keystore.h"
       8             : #include "policy/policy.h"
       9             : #include "script/script.h"
      10             : #include "script/script_error.h"
      11             : #include "script/interpreter.h"
      12             : #include "script/sign.h"
      13             : #include "script/ismine.h"
      14             : #include "uint256.h"
      15             : #include "test_pivx.h"
      16             : 
      17             : 
      18             : #include <boost/test/unit_test.hpp>
      19             : 
      20             : 
      21             : typedef std::vector<unsigned char> valtype;
      22             : 
      23             : BOOST_FIXTURE_TEST_SUITE(multisig_tests, TestingSetup)
      24             : 
      25             : CScript
      26          29 : sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
      27             : {
      28          29 :     const uint256& hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE);
      29             : 
      30          29 :     CScript result;
      31          29 :     result << OP_0; // CHECKMULTISIG bug workaround
      32          79 :     for (const CKey &key : keys)
      33             :     {
      34         100 :         std::vector<unsigned char> vchSig;
      35         100 :         BOOST_CHECK(key.Sign(hash, vchSig));
      36          50 :         vchSig.push_back((unsigned char)SIGHASH_ALL);
      37          50 :         result << vchSig;
      38             :     }
      39          29 :     return result;
      40             : }
      41             : 
      42           2 : BOOST_AUTO_TEST_CASE(multisig_verify)
      43             : {
      44           1 :     unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
      45             : 
      46           1 :     ScriptError err;
      47          10 :     CKey key[4];
      48           5 :     CAmount amount = 0;
      49           5 :     for (int i = 0; i < 4; i++)
      50           4 :         key[i].MakeNewKey(true);
      51             : 
      52           2 :     CScript a_and_b;
      53           2 :     a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
      54             : 
      55           2 :     CScript a_or_b;
      56           2 :     a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
      57             : 
      58           2 :     CScript escrow;
      59           3 :     escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
      60             : 
      61           2 :     CMutableTransaction txFrom;  // Funding transaction
      62           1 :     txFrom.vout.resize(3);
      63           1 :     txFrom.vout[0].scriptPubKey = a_and_b;
      64           1 :     txFrom.vout[1].scriptPubKey = a_or_b;
      65           1 :     txFrom.vout[2].scriptPubKey = escrow;
      66             : 
      67           8 :     CMutableTransaction txTo[3]; // Spending transaction
      68           4 :     for (int i = 0; i < 3; i++)
      69             :     {
      70           3 :         txTo[i].vin.resize(1);
      71           3 :         txTo[i].vout.resize(1);
      72           3 :         txTo[i].vin[0].prevout.n = i;
      73           3 :         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
      74           3 :         txTo[i].vout[0].nValue = 1;
      75             :     }
      76             : 
      77           1 :     std::vector<CKey> keys;
      78           2 :     CScript s;
      79             : 
      80             :     // Test a AND b:
      81           1 :     keys.clear();
      82           1 :     keys.push_back(key[0]);
      83           1 :     keys.push_back(key[1]);
      84           1 :     s = sign_multisig(a_and_b, keys, txTo[0], 0);
      85           2 :     BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), SIGVERSION_BASE, &err));
      86           2 :     BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
      87             : 
      88           5 :     for (int i = 0; i < 4; i++)
      89             :     {
      90           4 :         keys.clear();
      91           4 :         keys.push_back(key[i]);
      92           8 :         s = sign_multisig(a_and_b, keys, txTo[0], 0);
      93           8 :         BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), SIGVERSION_BASE, &err), strprintf("a&b 1: %d", i));
      94           8 :         BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
      95             : 
      96           4 :         keys.clear();
      97           4 :         keys.push_back(key[1]);
      98           4 :         keys.push_back(key[i]);
      99           8 :         s = sign_multisig(a_and_b, keys, txTo[0], 0);
     100           8 :         BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), SIGVERSION_BASE, &err), strprintf("a&b 2: %d", i));
     101           8 :         BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
     102             :     }
     103             : 
     104             :     // Test a OR b:
     105           5 :     for (int i = 0; i < 4; i++)
     106             :     {
     107           4 :         keys.clear();
     108           4 :         keys.push_back(key[i]);
     109           8 :         s = sign_multisig(a_or_b, keys, txTo[1], 0);
     110           4 :         if (i == 0 || i == 1)
     111             :         {
     112           4 :             BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), SIGVERSION_BASE, &err), strprintf("a|b: %d", i));
     113           4 :             BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
     114             :         }
     115             :         else
     116             :         {
     117           4 :             BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), SIGVERSION_BASE, &err), strprintf("a|b: %d", i));
     118           4 :             BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
     119             :         }
     120             :     }
     121           1 :     s.clear();
     122           1 :     s << OP_0 << OP_1;
     123           2 :     BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), SIGVERSION_BASE, &err));
     124           2 :     BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
     125             : 
     126             : 
     127           5 :     for (int i = 0; i < 4; i++)
     128          20 :         for (int j = 0; j < 4; j++)
     129             :         {
     130          16 :             keys.clear();
     131          16 :             keys.push_back(key[i]);
     132          16 :             keys.push_back(key[j]);
     133          31 :             s = sign_multisig(escrow, keys, txTo[2], 0);
     134          16 :             if (i < j && i < 3 && j < 3)
     135             :             {
     136           6 :                 BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), SIGVERSION_BASE, &err), strprintf("escrow 1: %d %d", i, j));
     137           6 :                 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
     138             :             }
     139             :             else
     140             :             {
     141          26 :                 BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), SIGVERSION_BASE, &err), strprintf("escrow 2: %d %d", i, j));
     142          26 :                 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
     143             :             }
     144             :         }
     145           1 : }
     146             : 
     147           2 : BOOST_AUTO_TEST_CASE(multisig_IsStandard)
     148             : {
     149          10 :     CKey key[4];
     150           5 :     for (int i = 0; i < 4; i++)
     151           4 :         key[i].MakeNewKey(true);
     152             : 
     153           1 :     txnouttype whichType;
     154             : 
     155           2 :     CScript a_and_b;
     156           2 :     a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     157           2 :     BOOST_CHECK(::IsStandard(a_and_b, whichType));
     158             : 
     159           2 :     CScript a_or_b;
     160           2 :     a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     161           2 :     BOOST_CHECK(::IsStandard(a_or_b, whichType));
     162             : 
     163           2 :     CScript escrow;
     164           3 :     escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
     165           2 :     BOOST_CHECK(::IsStandard(escrow, whichType));
     166             : 
     167           2 :     CScript one_of_four;
     168           4 :     one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG;
     169           2 :     BOOST_CHECK(!::IsStandard(one_of_four, whichType));
     170             : 
     171          14 :     CScript malformed[6];
     172           2 :     malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     173           2 :     malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
     174           2 :     malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     175           2 :     malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;
     176           2 :     malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
     177           2 :     malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
     178             : 
     179           7 :     for (int i = 0; i < 6; i++)
     180          12 :         BOOST_CHECK(!::IsStandard(malformed[i], whichType));
     181           1 : }
     182             : 
     183           2 : BOOST_AUTO_TEST_CASE(multisig_Solver1)
     184             : {
     185             :     // Tests Solver() that returns lists of keys that are
     186             :     // required to satisfy a ScriptPubKey
     187             :     //
     188             :     // Also tests IsMine() and ExtractDestination()
     189             :     //
     190             :     // Note: ExtractDestination for the multisignature transactions
     191             :     // always returns false for this release, even if you have
     192             :     // one key that would satisfy an (a|b) or 2-of-3 keys needed
     193             :     // to spend an escrow transaction.
     194             :     //
     195           2 :     CBasicKeyStore keystore, emptykeystore, partialkeystore;
     196           8 :     CKey key[3];
     197           8 :     CTxDestination keyaddr[3];
     198           4 :     for (int i = 0; i < 3; i++)
     199             :     {
     200           3 :         key[i].MakeNewKey(true);
     201           3 :         keystore.AddKey(key[i]);
     202           3 :         keyaddr[i] = key[i].GetPubKey().GetID();
     203             :     }
     204           1 :     partialkeystore.AddKey(key[0]);
     205             : 
     206           1 :     {
     207           1 :         std::vector<valtype> solutions;
     208           1 :         txnouttype whichType;
     209           2 :         CScript s;
     210           1 :         s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
     211           2 :         BOOST_CHECK(Solver(s, whichType, solutions));
     212           2 :         BOOST_CHECK(solutions.size() == 1);
     213           2 :         CTxDestination addr;
     214           2 :         BOOST_CHECK(ExtractDestination(s, addr));
     215           2 :         BOOST_CHECK(addr == keyaddr[0]);
     216           2 :         BOOST_CHECK(IsMine(keystore, s));
     217           2 :         BOOST_CHECK(!IsMine(emptykeystore, s));
     218             :     }
     219           1 :     {
     220           1 :         std::vector<valtype> solutions;
     221           1 :         txnouttype whichType;
     222           2 :         CScript s;
     223           1 :         s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
     224           2 :         BOOST_CHECK(Solver(s, whichType, solutions));
     225           2 :         BOOST_CHECK(solutions.size() == 1);
     226           2 :         CTxDestination addr;
     227           2 :         BOOST_CHECK(ExtractDestination(s, addr));
     228           2 :         BOOST_CHECK(addr == keyaddr[0]);
     229           2 :         BOOST_CHECK(IsMine(keystore, s));
     230           2 :         BOOST_CHECK(!IsMine(emptykeystore, s));
     231             :     }
     232           1 :     {
     233           1 :         std::vector<valtype> solutions;
     234           1 :         txnouttype whichType;
     235           2 :         CScript s;
     236           2 :         s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     237           2 :         BOOST_CHECK(Solver(s, whichType, solutions));
     238           1 :         BOOST_CHECK_EQUAL(solutions.size(), 4U);
     239           2 :         CTxDestination addr;
     240           2 :         BOOST_CHECK(!ExtractDestination(s, addr));
     241           2 :         BOOST_CHECK(IsMine(keystore, s));
     242           2 :         BOOST_CHECK(!IsMine(emptykeystore, s));
     243           2 :         BOOST_CHECK(!IsMine(partialkeystore, s));
     244             :     }
     245           1 :     {
     246           1 :         std::vector<valtype> solutions;
     247           1 :         txnouttype whichType;
     248           2 :         CScript s;
     249           2 :         s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     250           2 :         BOOST_CHECK(Solver(s, whichType, solutions));
     251           1 :         BOOST_CHECK_EQUAL(solutions.size(), 4U);
     252           2 :         std::vector<CTxDestination> addrs;
     253           1 :         int nRequired;
     254           2 :         BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
     255           2 :         BOOST_CHECK(addrs[0] == keyaddr[0]);
     256           2 :         BOOST_CHECK(addrs[1] == keyaddr[1]);
     257           2 :         BOOST_CHECK(nRequired == 1);
     258           2 :         BOOST_CHECK(IsMine(keystore, s));
     259           2 :         BOOST_CHECK(!IsMine(emptykeystore, s));
     260           2 :         BOOST_CHECK(!IsMine(partialkeystore, s));
     261             :     }
     262           1 :     {
     263           1 :         std::vector<valtype> solutions;
     264           1 :         txnouttype whichType;
     265           2 :         CScript s;
     266           3 :         s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
     267           2 :         BOOST_CHECK(Solver(s, whichType, solutions));
     268           2 :         BOOST_CHECK(solutions.size() == 5);
     269             :     }
     270           1 : }
     271             : 
     272           2 : BOOST_AUTO_TEST_CASE(multisig_Sign)
     273             : {
     274             :     // Test SignSignature() (and therefore the version of Solver() that signs transactions)
     275           1 :     CBasicKeyStore keystore;
     276          10 :     CKey key[4];
     277           5 :     for (int i = 0; i < 4; i++)
     278             :     {
     279           4 :         key[i].MakeNewKey(true);
     280           4 :         keystore.AddKey(key[i]);
     281             :     }
     282             : 
     283           2 :     CScript a_and_b;
     284           2 :     a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     285             : 
     286           2 :     CScript a_or_b;
     287           2 :     a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
     288             : 
     289           2 :     CScript escrow;
     290           3 :     escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
     291             : 
     292           2 :     CMutableTransaction txFrom;  // Funding transaction
     293           1 :     txFrom.vout.resize(3);
     294           1 :     txFrom.vout[0].scriptPubKey = a_and_b;
     295           1 :     txFrom.vout[1].scriptPubKey = a_or_b;
     296           1 :     txFrom.vout[2].scriptPubKey = escrow;
     297             : 
     298           8 :     CMutableTransaction txTo[3]; // Spending transaction
     299           4 :     for (int i = 0; i < 3; i++)
     300             :     {
     301           3 :         txTo[i].vin.resize(1);
     302           3 :         txTo[i].vout.resize(1);
     303           3 :         txTo[i].vin[0].prevout.n = i;
     304           3 :         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
     305           3 :         txTo[i].vout[0].nValue = 1;
     306             :     }
     307             : 
     308           4 :     for (int i = 0; i < 3; i++)
     309             :     {
     310           6 :         BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
     311             :     }
     312           1 : }
     313             : 
     314             : 
     315             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14