LCOV - code coverage report
Current view: top level - src/test - multisig_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 99.3 % 138 137
Test Date: 2026-03-16 05:20:51 Functions: 100.0 % 8 8
Branches: 52.1 % 766 399

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <key.h>
       6                 :             : #include <policy/policy.h>
       7                 :             : #include <script/interpreter.h>
       8                 :             : #include <script/script.h>
       9                 :             : #include <script/script_error.h>
      10                 :             : #include <script/sign.h>
      11                 :             : #include <script/signingprovider.h>
      12                 :             : #include <test/util/common.h>
      13                 :             : #include <test/util/setup_common.h>
      14                 :             : #include <test/util/transaction_utils.h>
      15                 :             : #include <tinyformat.h>
      16                 :             : #include <uint256.h>
      17                 :             : 
      18                 :             : 
      19                 :             : #include <boost/test/unit_test.hpp>
      20                 :             : 
      21                 :             : BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
      22                 :             : 
      23                 :             : static CScript
      24                 :          29 : sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
      25                 :             : {
      26                 :          29 :     uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);
      27                 :             : 
      28                 :          29 :     CScript result;
      29         [ +  - ]:          29 :     result << OP_0; // CHECKMULTISIG bug workaround
      30         [ +  + ]:          79 :     for (const CKey &key : keys)
      31                 :             :     {
      32                 :          50 :         std::vector<unsigned char> vchSig;
      33   [ +  -  +  -  :         100 :         BOOST_CHECK(key.Sign(hash, vchSig));
             +  -  +  - ]
      34                 :          50 :         vchSig.push_back((unsigned char)SIGHASH_ALL);
      35         [ -  + ]:          50 :         result << vchSig;
      36                 :          50 :     }
      37                 :          29 :     return result;
      38                 :           0 : }
      39                 :             : 
      40   [ +  -  +  -  :          10 : BOOST_AUTO_TEST_CASE(multisig_verify)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
             -  +  +  - ]
      41                 :             : {
      42                 :           1 :     script_verify_flags flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
      43                 :             : 
      44                 :           1 :     ScriptError err;
      45                 :           4 :     CKey key[4];
      46                 :           1 :     CAmount amount = 0;
      47         [ +  + ]:           5 :     for (int i = 0; i < 4; i++)
      48         [ +  - ]:           4 :         key[i].MakeNewKey(true);
      49                 :             : 
      50                 :           1 :     CScript a_and_b;
      51   [ +  -  +  -  :           4 :     a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      52                 :             : 
      53                 :           1 :     CScript a_or_b;
      54   [ +  -  +  -  :           4 :     a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      55                 :             : 
      56                 :           1 :     CScript escrow;
      57   [ +  -  +  -  :           5 :     escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
      58                 :             : 
      59         [ +  - ]:           1 :     CMutableTransaction txFrom;  // Funding transaction
      60         [ +  - ]:           1 :     txFrom.vout.resize(3);
      61                 :           1 :     txFrom.vout[0].scriptPubKey = a_and_b;
      62                 :           1 :     txFrom.vout[1].scriptPubKey = a_or_b;
      63                 :           1 :     txFrom.vout[2].scriptPubKey = escrow;
      64                 :             : 
      65   [ +  -  +  +  :          10 :     CMutableTransaction txTo[3]; // Spending transaction
                   -  - ]
      66         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
      67                 :             :     {
      68         [ +  - ]:           3 :         txTo[i].vin.resize(1);
      69         [ +  - ]:           3 :         txTo[i].vout.resize(1);
      70         [ +  - ]:           3 :         txTo[i].vin[0].prevout.n = i;
      71         [ +  - ]:           3 :         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
      72                 :           3 :         txTo[i].vout[0].nValue = 1;
      73                 :             :     }
      74                 :             : 
      75                 :           1 :     std::vector<CKey> keys;
      76                 :           1 :     CScript s;
      77                 :             : 
      78                 :             :     // Test a AND b:
      79         [ +  - ]:           1 :     keys.assign(1,key[0]);
      80         [ +  - ]:           1 :     keys.push_back(key[1]);
      81   [ +  -  +  - ]:           2 :     s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
      82   [ +  -  +  -  :           2 :     BOOST_CHECK(VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
             +  -  +  - ]
      83   [ +  -  +  -  :           2 :     BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
             +  -  +  - ]
      84                 :             : 
      85         [ +  + ]:           5 :     for (int i = 0; i < 4; i++)
      86                 :             :     {
      87         [ +  - ]:           4 :         keys.assign(1,key[i]);
      88   [ +  -  +  - ]:           8 :         s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
      89   [ +  -  +  -  :           8 :         BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 1: %d", i));
             +  -  +  - ]
      90   [ +  -  +  -  :           8 :         BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
                   +  - ]
      91                 :             : 
      92         [ +  - ]:           4 :         keys.assign(1,key[1]);
      93         [ +  - ]:           4 :         keys.push_back(key[i]);
      94   [ +  -  +  - ]:           8 :         s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
      95   [ +  -  +  -  :           8 :         BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 2: %d", i));
             +  -  +  - ]
      96   [ +  -  +  - ]:           8 :         BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
      97                 :             :     }
      98                 :             : 
      99                 :             :     // Test a OR b:
     100         [ +  + ]:           5 :     for (int i = 0; i < 4; i++)
     101                 :             :     {
     102         [ +  - ]:           4 :         keys.assign(1,key[i]);
     103   [ +  -  +  - ]:           8 :         s = sign_multisig(a_or_b, keys, CTransaction(txTo[1]), 0);
     104         [ +  + ]:           4 :         if (i == 0 || i == 1)
     105                 :             :         {
     106   [ +  -  +  -  :           4 :             BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
             +  -  +  - ]
     107   [ +  -  +  -  :           4 :             BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
                   +  - ]
     108                 :             :         }
     109                 :             :         else
     110                 :             :         {
     111   [ +  -  +  -  :           4 :             BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
             +  -  +  - ]
     112   [ +  -  +  -  :           6 :             BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
                   +  - ]
     113                 :             :         }
     114                 :             :     }
     115                 :           1 :     s.clear();
     116   [ +  -  +  - ]:           1 :     s << OP_0 << OP_1;
     117   [ +  -  +  -  :           2 :     BOOST_CHECK(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
             +  -  +  - ]
     118   [ +  -  +  -  :           2 :     BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
                   +  - ]
     119                 :             : 
     120                 :             : 
     121         [ +  + ]:           5 :     for (int i = 0; i < 4; i++)
     122         [ +  + ]:          20 :         for (int j = 0; j < 4; j++)
     123                 :             :         {
     124         [ +  - ]:          16 :             keys.assign(1,key[i]);
     125         [ +  - ]:          16 :             keys.push_back(key[j]);
     126   [ +  -  +  - ]:          32 :             s = sign_multisig(escrow, keys, CTransaction(txTo[2]), 0);
     127   [ +  +  +  -  :          16 :             if (i < j && i < 3 && j < 3)
                   +  + ]
     128                 :             :             {
     129   [ +  -  +  -  :           6 :                 BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 1: %d %d", i, j));
             +  -  +  - ]
     130   [ +  -  +  -  :           6 :                 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
                   +  - ]
     131                 :             :             }
     132                 :             :             else
     133                 :             :             {
     134   [ +  -  +  -  :          26 :                 BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 2: %d %d", i, j));
             +  -  +  - ]
     135   [ +  -  +  -  :          29 :                 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
                   +  - ]
     136                 :             :             }
     137                 :             :         }
     138   [ +  +  +  +  :          10 : }
             -  -  -  - ]
     139                 :             : 
     140   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(multisig_IsStandard)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     141                 :             : {
     142                 :           4 :     CKey key[4];
     143         [ +  + ]:           5 :     for (int i = 0; i < 4; i++)
     144         [ +  - ]:           4 :         key[i].MakeNewKey(true);
     145                 :             : 
     146                 :          11 :     const auto is_standard{[](const CScript& spk) {
     147                 :          10 :         TxoutType type;
     148                 :          10 :         bool res{::IsStandard(spk, type)};
     149         [ +  + ]:          10 :         if (res) {
     150         [ +  - ]:           3 :             BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
     151                 :             :         }
     152                 :          10 :         return res;
     153                 :             :     }};
     154                 :             : 
     155                 :           1 :     CScript a_and_b;
     156   [ +  -  +  -  :           4 :     a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     157   [ +  -  +  -  :           2 :     BOOST_CHECK(is_standard(a_and_b));
             +  -  +  - ]
     158                 :             : 
     159                 :           1 :     CScript a_or_b;
     160   [ +  -  +  -  :           4 :     a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     161   [ +  -  +  -  :           2 :     BOOST_CHECK(is_standard(a_or_b));
             +  -  +  - ]
     162                 :             : 
     163                 :           1 :     CScript escrow;
     164   [ +  -  +  -  :           5 :     escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     165   [ +  -  +  -  :           2 :     BOOST_CHECK(is_standard(escrow));
             +  -  +  - ]
     166                 :             : 
     167                 :           1 :     CScript one_of_four;
     168   [ +  -  +  -  :           6 :     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(!is_standard(one_of_four));
             +  -  +  - ]
     170                 :             : 
     171                 :           6 :     CScript malformed[6];
     172   [ +  -  +  -  :           4 :     malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     173   [ +  -  +  -  :           4 :     malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     174   [ +  -  +  -  :           4 :     malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     175   [ +  -  +  -  :           4 :     malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     176   [ +  -  +  -  :           4 :     malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
          +  -  +  -  +  
                -  +  - ]
     177   [ +  -  +  -  :           3 :     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(!is_standard(malformed[i]));
                   +  - ]
     181                 :             :     }
     182   [ +  +  +  +  :          13 : }
             -  -  -  - ]
     183                 :             : 
     184   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(multisig_Sign)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     185                 :             : {
     186                 :             :     // Test SignSignature() (and therefore the version of Solver() that signs transactions)
     187                 :           1 :     FillableSigningProvider keystore;
     188                 :           4 :     CKey key[4];
     189         [ +  + ]:           5 :     for (int i = 0; i < 4; i++)
     190                 :             :     {
     191         [ +  - ]:           4 :         key[i].MakeNewKey(true);
     192   [ +  -  +  -  :           8 :         BOOST_CHECK(keystore.AddKey(key[i]));
                   +  - ]
     193                 :             :     }
     194                 :             : 
     195                 :           1 :     CScript a_and_b;
     196   [ +  -  +  -  :           4 :     a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     197                 :             : 
     198                 :           1 :     CScript a_or_b;
     199   [ +  -  +  -  :           4 :     a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     200                 :             : 
     201                 :           1 :     CScript escrow;
     202   [ +  -  +  -  :           5 :     escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     203                 :             : 
     204         [ +  - ]:           1 :     CMutableTransaction txFrom;  // Funding transaction
     205         [ +  - ]:           1 :     txFrom.vout.resize(3);
     206                 :           1 :     txFrom.vout[0].scriptPubKey = a_and_b;
     207                 :           1 :     txFrom.vout[1].scriptPubKey = a_or_b;
     208                 :           1 :     txFrom.vout[2].scriptPubKey = escrow;
     209                 :             : 
     210   [ +  -  +  +  :          10 :     CMutableTransaction txTo[3]; // Spending transaction
                   -  - ]
     211         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
     212                 :             :     {
     213         [ +  - ]:           3 :         txTo[i].vin.resize(1);
     214         [ +  - ]:           3 :         txTo[i].vout.resize(1);
     215         [ +  - ]:           3 :         txTo[i].vin[0].prevout.n = i;
     216         [ +  - ]:           3 :         txTo[i].vin[0].prevout.hash = txFrom.GetHash();
     217                 :           3 :         txTo[i].vout[0].nValue = 1;
     218                 :             :     }
     219                 :             : 
     220         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
     221                 :             :     {
     222                 :           3 :         SignatureData empty;
     223   [ +  -  +  -  :           9 :         BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
          +  -  +  -  +  
                      - ]
     224                 :           3 :     }
     225   [ +  +  +  +  :          10 : }
             -  -  -  - ]
     226                 :             : 
     227                 :             : 
     228                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1