LCOV - code coverage report
Current view: top level - src/test - sighash_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 99 105 94.3 %
Date: 2020-09-26 01:30:44 Functions: 19 19 100.0 %

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

Generated by: LCOV version 1.15