LCOV - code coverage report
Current view: top level - src/test - script_assets_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 20.8 % 101 21
Test Date: 2025-08-01 05:08:13 Functions: 33.3 % 9 3
Branches: 16.4 % 304 50

             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 <primitives/transaction.h>
       6                 :             : #include <script/interpreter.h>
       7                 :             : #include <script/script.h>
       8                 :             : #include <script/sigcache.h>
       9                 :             : #include <script/sign.h>
      10                 :             : #include <script/signingprovider.h>
      11                 :             : #include <span.h>
      12                 :             : #include <streams.h>
      13                 :             : #include <test/util/json.h>
      14                 :             : #include <util/check.h>
      15                 :             : #include <util/fs.h>
      16                 :             : #include <util/strencodings.h>
      17                 :             : 
      18                 :             : #include <cstdint>
      19                 :             : #include <cstdlib>
      20                 :             : #include <fstream>
      21                 :             : #include <utility>
      22                 :             : #include <vector>
      23                 :             : 
      24                 :             : #include <boost/test/unit_test.hpp>
      25                 :             : 
      26                 :             : #include <univalue.h>
      27                 :             : 
      28                 :             : unsigned int ParseScriptFlags(std::string strFlags);
      29                 :             : 
      30                 :             : BOOST_AUTO_TEST_SUITE(script_assets_tests)
      31                 :             : 
      32                 :             : template <typename T>
      33                 :           0 : CScript ToScript(const T& byte_container)
      34                 :             : {
      35                 :           0 :     auto span{MakeUCharSpan(byte_container)};
      36                 :           0 :     return {span.begin(), span.end()};
      37                 :             : }
      38                 :             : 
      39                 :           0 : static CScript ScriptFromHex(const std::string& str)
      40                 :             : {
      41         [ #  # ]:           0 :     return ToScript(*Assert(TryParseHex(str)));
      42                 :             : }
      43                 :             : 
      44                 :           0 : static CMutableTransaction TxFromHex(const std::string& str)
      45                 :             : {
      46                 :           0 :     CMutableTransaction tx;
      47   [ #  #  #  # ]:           0 :     SpanReader{ParseHex(str)} >> TX_NO_WITNESS(tx);
      48                 :           0 :     return tx;
      49                 :           0 : }
      50                 :             : 
      51                 :           0 : static std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue)
      52                 :             : {
      53         [ #  # ]:           0 :     assert(univalue.isArray());
      54                 :           0 :     std::vector<CTxOut> prevouts;
      55         [ #  # ]:           0 :     for (size_t i = 0; i < univalue.size(); ++i) {
      56                 :           0 :         CTxOut txout;
      57   [ #  #  #  #  :           0 :         SpanReader{ParseHex(univalue[i].get_str())} >> txout;
             #  #  #  # ]
      58         [ #  # ]:           0 :         prevouts.push_back(std::move(txout));
      59                 :           0 :     }
      60                 :           0 :     return prevouts;
      61                 :           0 : }
      62                 :             : 
      63                 :           0 : static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue)
      64                 :             : {
      65         [ #  # ]:           0 :     assert(univalue.isArray());
      66                 :           0 :     CScriptWitness scriptwitness;
      67         [ #  # ]:           0 :     for (size_t i = 0; i < univalue.size(); ++i) {
      68   [ #  #  #  #  :           0 :         auto bytes = ParseHex(univalue[i].get_str());
                   #  # ]
      69         [ #  # ]:           0 :         scriptwitness.stack.push_back(std::move(bytes));
      70                 :           0 :     }
      71                 :           0 :     return scriptwitness;
      72                 :           0 : }
      73                 :             : 
      74                 :         139 : static std::vector<unsigned int> AllConsensusFlags()
      75                 :             : {
      76                 :         139 :     std::vector<unsigned int> ret;
      77                 :             : 
      78         [ +  + ]:       17931 :     for (unsigned int i = 0; i < 128; ++i) {
      79                 :       17792 :         unsigned int flag = 0;
      80         [ +  + ]:       17792 :         if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
      81         [ +  + ]:       17792 :         if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
      82         [ +  + ]:       17792 :         if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
      83         [ +  + ]:       17792 :         if (i & 8) flag |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
      84         [ +  + ]:       17792 :         if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
      85         [ +  + ]:       17792 :         if (i & 32) flag |= SCRIPT_VERIFY_WITNESS;
      86         [ +  + ]:       17792 :         if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT;
      87                 :             : 
      88                 :             :         // SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH
      89         [ +  + ]:       17792 :         if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue;
      90                 :             :         // SCRIPT_VERIFY_TAPROOT requires SCRIPT_VERIFY_WITNESS
      91         [ +  + ]:       13344 :         if (flag & SCRIPT_VERIFY_TAPROOT && !(flag & SCRIPT_VERIFY_WITNESS)) continue;
      92                 :             : 
      93         [ +  - ]:        8896 :         ret.push_back(flag);
      94                 :             :     }
      95                 :             : 
      96                 :         139 :     return ret;
      97                 :           0 : }
      98                 :             : 
      99                 :             : /** Precomputed list of all valid combinations of consensus-relevant script validation flags. */
     100                 :             : static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
     101                 :             : 
     102                 :           0 : static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
     103                 :             : {
     104         [ #  # ]:           0 :     BOOST_CHECK(test.isObject());
     105                 :             : 
     106   [ #  #  #  #  :           0 :     CMutableTransaction mtx = TxFromHex(test["tx"].get_str());
                   #  # ]
     107   [ #  #  #  #  :           0 :     const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
                   #  # ]
     108   [ #  #  #  #  :           0 :     BOOST_CHECK(prevouts.size() == mtx.vin.size());
                   #  # ]
     109   [ #  #  #  #  :           0 :     size_t idx = test["index"].getInt<int64_t>();
                   #  # ]
     110   [ #  #  #  #  :           0 :     uint32_t test_flags{ParseScriptFlags(test["flags"].get_str())};
          #  #  #  #  #  
                      # ]
     111   [ #  #  #  #  :           0 :     bool fin = test.exists("final") && test["final"].get_bool();
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     112                 :             : 
     113   [ #  #  #  # ]:           0 :     if (test.exists("success")) {
     114   [ #  #  #  #  :           0 :         mtx.vin[idx].scriptSig = ScriptFromHex(test["success"]["scriptSig"].get_str());
          #  #  #  #  #  
                #  #  # ]
     115   [ #  #  #  #  :           0 :         mtx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["success"]["witness"]);
          #  #  #  #  #  
                      # ]
     116         [ #  # ]:           0 :         CTransaction tx(mtx);
     117                 :           0 :         PrecomputedTransactionData txdata;
     118   [ #  #  #  # ]:           0 :         txdata.Init(tx, std::vector<CTxOut>(prevouts));
     119                 :           0 :         CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata);
     120                 :             : 
     121         [ #  # ]:           0 :         for (const auto flags : ALL_CONSENSUS_FLAGS) {
     122                 :             :             // "final": true tests are valid for all flags. Others are only valid with flags that are
     123                 :             :             // a subset of test_flags.
     124   [ #  #  #  # ]:           0 :             if (fin || ((flags & test_flags) == flags)) {
     125         [ #  # ]:           0 :                 bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr);
     126   [ #  #  #  # ]:           0 :                 BOOST_CHECK(ret);
     127                 :             :             }
     128                 :             :         }
     129                 :           0 :     }
     130                 :             : 
     131   [ #  #  #  # ]:           0 :     if (test.exists("failure")) {
     132   [ #  #  #  #  :           0 :         mtx.vin[idx].scriptSig = ScriptFromHex(test["failure"]["scriptSig"].get_str());
          #  #  #  #  #  
                #  #  # ]
     133   [ #  #  #  #  :           0 :         mtx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["failure"]["witness"]);
          #  #  #  #  #  
                      # ]
     134         [ #  # ]:           0 :         CTransaction tx(mtx);
     135                 :           0 :         PrecomputedTransactionData txdata;
     136   [ #  #  #  # ]:           0 :         txdata.Init(tx, std::vector<CTxOut>(prevouts));
     137                 :           0 :         CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata);
     138                 :             : 
     139         [ #  # ]:           0 :         for (const auto flags : ALL_CONSENSUS_FLAGS) {
     140                 :             :             // If a test is supposed to fail with test_flags, it should also fail with any superset thereof.
     141         [ #  # ]:           0 :             if ((flags & test_flags) == test_flags) {
     142         [ #  # ]:           0 :                 bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr);
     143   [ #  #  #  # ]:           0 :                 BOOST_CHECK(!ret);
     144                 :             :             }
     145                 :             :         }
     146                 :           0 :     }
     147                 :           0 : }
     148                 :             : 
     149   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(script_assets_test)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     150                 :             : {
     151                 :             :     // See src/test/fuzz/script_assets_test_minimizer.cpp for information on how to generate
     152                 :             :     // the script_assets_test.json file used by this test.
     153                 :           1 :     SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES};
     154                 :             : 
     155                 :           1 :     const char* dir = std::getenv("DIR_UNIT_TEST_DATA");
     156   [ +  -  +  -  :           2 :     BOOST_WARN_MESSAGE(dir != nullptr, "Variable DIR_UNIT_TEST_DATA unset, skipping script_assets_test");
                   -  + ]
     157         [ -  + ]:           1 :     if (dir == nullptr) return;
     158   [ #  #  #  # ]:           0 :     auto path = fs::path(dir) / "script_assets_test.json";
     159         [ #  # ]:           0 :     bool exists = fs::exists(path);
     160   [ #  #  #  #  :           0 :     BOOST_WARN_MESSAGE(exists, "File $DIR_UNIT_TEST_DATA/script_assets_test.json not found, skipping script_assets_test");
                   #  # ]
     161         [ #  # ]:           0 :     if (!exists) return;
     162         [ #  # ]:           0 :     std::ifstream file{path};
     163   [ #  #  #  #  :           0 :     BOOST_CHECK(file.is_open());
                   #  # ]
     164         [ #  # ]:           0 :     file.seekg(0, std::ios::end);
     165         [ #  # ]:           0 :     size_t length = file.tellg();
     166         [ #  # ]:           0 :     file.seekg(0, std::ios::beg);
     167   [ #  #  #  # ]:           0 :     std::string data(length, '\0');
     168         [ #  # ]:           0 :     file.read(data.data(), data.size());
     169         [ #  # ]:           0 :     UniValue tests = read_json(data);
     170   [ #  #  #  #  :           0 :     BOOST_CHECK(tests.isArray());
                   #  # ]
     171   [ #  #  #  # ]:           0 :     BOOST_CHECK(tests.size() > 0);
     172                 :             : 
     173         [ #  # ]:           0 :     for (size_t i = 0; i < tests.size(); i++) {
     174   [ #  #  #  # ]:           0 :         AssetTest(tests[i], signature_cache);
     175                 :             :     }
     176         [ #  # ]:           0 :     file.close();
     177                 :           1 : }
     178                 :             : 
     179                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1