LCOV - code coverage report
Current view: top level - src/test - sighash_tests.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 104 110 94.5 %
Date: 2026-06-25 07:23:51 Functions: 20 20 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2013-2021 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 <consensus/tx_check.h>
       6             : #include <consensus/validation.h>
       7             : #include <hash.h>
       8             : #include <script/interpreter.h>
       9             : #include <script/script.h>
      10             : #include <serialize.h>
      11             : #include <streams.h>
      12             : #include <test/data/sighash.json.h>
      13             : #include <test/util/json.h>
      14             : #include <test/util/random.h>
      15             : #include <test/util/setup_common.h>
      16             : #include <util/strencodings.h>
      17             : #include <version.h>
      18             : 
      19             : #include <boost/test/unit_test.hpp>
      20             : 
      21             : #include <univalue.h>
      22             : 
      23             : // Old script.cpp SignatureHash function
      24       50000 : uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
      25             : {
      26       50000 :     if (nIn >= txTo.vin.size())
      27             :     {
      28           0 :         return uint256::ONE;
      29             :     }
      30       50000 :     CMutableTransaction txTmp(txTo);
      31             : 
      32             :     // In case concatenating two scripts ends up with two codeseparators,
      33             :     // or an extra one at the end, this prevents all those possible incompatibilities.
      34       50000 :     FindAndDelete(scriptCode, CScript(OP_CODESEPARATOR));
      35             : 
      36             :     // Blank out other inputs' signatures
      37      175189 :     for (unsigned int i = 0; i < txTmp.vin.size(); i++)
      38      125189 :         txTmp.vin[i].scriptSig = CScript();
      39       50000 :     txTmp.vin[nIn].scriptSig = scriptCode;
      40             : 
      41             :     // Blank out some of the outputs
      42       50000 :     if ((nHashType & 0x1f) == SIGHASH_NONE)
      43             :     {
      44             :         // Wildcard payee
      45        1622 :         txTmp.vout.clear();
      46             : 
      47             :         // Let the others update at will
      48        5741 :         for (unsigned int i = 0; i < txTmp.vin.size(); i++)
      49        6616 :             if (i != nIn)
      50        2497 :                 txTmp.vin[i].nSequence = 0;
      51        1622 :     }
      52       48378 :     else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
      53             :     {
      54             :         // Only lock-in the txout payee at same index as txin
      55        1558 :         unsigned int nOut = nIn;
      56        1558 :         if (nOut >= txTmp.vout.size())
      57             :         {
      58           0 :             return uint256::ONE;
      59             :         }
      60        1558 :         txTmp.vout.resize(nOut+1);
      61        2701 :         for (unsigned int i = 0; i < nOut; i++)
      62        1143 :             txTmp.vout[i].SetNull();
      63             : 
      64             :         // Let the others update at will
      65        5412 :         for (unsigned int i = 0; i < txTmp.vin.size(); i++)
      66        6150 :             if (i != nIn)
      67        2296 :                 txTmp.vin[i].nSequence = 0;
      68        1558 :     }
      69             : 
      70             :     // Blank out other inputs completely, not recommended for open transactions
      71       50000 :     if (nHashType & SIGHASH_ANYONECANPAY)
      72             :     {
      73       25107 :         txTmp.vin[0] = txTmp.vin[nIn];
      74       25107 :         txTmp.vin.resize(1);
      75       25107 :     }
      76             : 
      77             :     // Serialize and hash
      78       50000 :     CHashWriter ss(SER_GETHASH, 0);
      79       50000 :     ss << txTmp << nHashType;
      80       50000 :     return ss.GetHash();
      81       50000 : }
      82             : 
      83      300249 : void static RandomScript(CScript &script) {
      84             :     static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};
      85      300249 :     script = CScript();
      86      300249 :     int ops = (InsecureRandRange(10));
      87     1649966 :     for (int i=0; i<ops; i++)
      88     1349717 :         script << oplist[InsecureRandRange(std::size(oplist))];
      89      300249 : }
      90             : 
      91       50000 : void static RandomTransaction(CMutableTransaction &tx, bool fSingle)
      92             : {
      93       50000 :     tx.nVersion = int(InsecureRandRange(2)) + 1;
      94       50000 :     tx.vin.clear();
      95       50000 :     tx.vout.clear();
      96       50000 :     tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0;
      97       50000 :     int ins = (InsecureRandBits(2)) + 1;
      98       50000 :     int outs = fSingle ? ins : (InsecureRandBits(2)) + 1;
      99      175189 :     for (int in = 0; in < ins; in++) {
     100      125189 :         tx.vin.emplace_back();
     101      125189 :         CTxIn &txin = tx.vin.back();
     102      125189 :         txin.prevout.hash = InsecureRand256();
     103      125189 :         txin.prevout.n = InsecureRandBits(2);
     104      125189 :         RandomScript(txin.scriptSig);
     105      125189 :         txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : std::numeric_limits<uint32_t>::max();
     106      125189 :     }
     107      175060 :     for (int out = 0; out < outs; out++) {
     108      125060 :         tx.vout.emplace_back();
     109      125060 :         CTxOut &txout = tx.vout.back();
     110      125060 :         txout.nValue = InsecureRandMoneyAmount();
     111      125060 :         RandomScript(txout.scriptPubKey);
     112      125060 :     }
     113       50000 : }
     114             : 
     115         146 : BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup)
     116             : 
     117         149 : BOOST_AUTO_TEST_CASE(sighash_test)
     118             : {
     119             :     #if defined(PRINT_SIGHASH_JSON)
     120             :     std::cout << "[\n";
     121             :     std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n";
     122             :     int nRandomTests = 500;
     123             :     #else
     124           1 :     int nRandomTests = 50000;
     125             :     #endif
     126       50001 :     for (int i=0; i<nRandomTests; i++) {
     127       50000 :         int nHashType{int(InsecureRand32())};
     128       50000 :         CMutableTransaction txTo;
     129       50000 :         RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
     130       50000 :         CScript scriptCode;
     131       50000 :         RandomScript(scriptCode);
     132       50000 :         int nIn = InsecureRandRange(txTo.vin.size());
     133             : 
     134       50000 :         uint256 sh, sho;
     135       50000 :         sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType);
     136       50000 :         sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SigVersion::BASE);
     137             :         #if defined(PRINT_SIGHASH_JSON)
     138             :         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
     139             :         ss << txTo;
     140             : 
     141             :         std::cout << "\t[\"" ;
     142             :         std::cout << HexStr(ss) << "\", \"";
     143             :         std::cout << HexStr(scriptCode) << "\", ";
     144             :         std::cout << nIn << ", ";
     145             :         std::cout << nHashType << ", \"";
     146             :         std::cout << sho.GetHex() << "\"]";
     147             :         if (i+1 != nRandomTests) {
     148             :           std::cout << ",";
     149             :         }
     150             :         std::cout << "\n";
     151             :         #endif
     152       50000 :         BOOST_CHECK(sh == sho);
     153       50000 :     }
     154             :     #if defined(PRINT_SIGHASH_JSON)
     155             :     std::cout << "]\n";
     156             :     #endif
     157           1 : }
     158             : 
     159             : // Goal: check that SignatureHash generates correct hash
     160         149 : BOOST_AUTO_TEST_CASE(sighash_from_data)
     161             : {
     162           1 :     UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
     163             : 
     164         502 :     for (unsigned int idx = 0; idx < tests.size(); idx++) {
     165         501 :         const UniValue& test = tests[idx];
     166         501 :         std::string strTest = test.write();
     167         501 :         if (test.size() < 1) // Allow for extra stuff (useful for comments)
     168             :         {
     169           0 :             BOOST_ERROR("Bad test: " << strTest);
     170           0 :             continue;
     171             :         }
     172         501 :         if (test.size() == 1) continue; // comment
     173             : 
     174         500 :         std::string raw_tx, raw_script, sigHashHex;
     175             :         int nIn, nHashType;
     176         500 :         uint256 sh;
     177         500 :         CTransactionRef tx;
     178         500 :         CScript scriptCode = CScript();
     179             : 
     180             :         try {
     181             :           // deserialize test data
     182         500 :           raw_tx = test[0].get_str();
     183         500 :           raw_script = test[1].get_str();
     184         500 :           nIn = test[2].getInt<int>();
     185         500 :           nHashType = test[3].getInt<int>();
     186         500 :           sigHashHex = test[4].get_str();
     187             : 
     188         500 :           CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
     189         500 :           stream >> tx;
     190             : 
     191         500 :           TxValidationState state;
     192         500 :           BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
     193         500 :           BOOST_CHECK(state.IsValid());
     194             : 
     195         500 :           std::vector<unsigned char> raw = ParseHex(raw_script);
     196         500 :           scriptCode.insert(scriptCode.end(), raw.begin(), raw.end());
     197         500 :         } catch (...) {
     198           0 :           BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest);
     199             :           continue;
     200           0 :         }
     201             : 
     202         500 :         sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SigVersion::BASE);
     203         500 :         BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
     204         501 :     }
     205           1 : }
     206         146 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.16