LCOV - code coverage report
Current view: top level - src - core_read.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 107 114 93.9 %
Date: 2026-06-25 07:23:43 Functions: 14 14 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2009-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 <core_io.h>
       6             : 
       7             : #include <primitives/block.h>
       8             : #include <primitives/transaction.h>
       9             : #include <script/script.h>
      10             : #include <script/sign.h>
      11             : #include <serialize.h>
      12             : #include <streams.h>
      13             : #include <univalue.h>
      14             : #include <util/string.h>
      15             : #include <util/strencodings.h>
      16             : #include <version.h>
      17             : 
      18             : #include <algorithm>
      19             : #include <string>
      20             : 
      21             : namespace {
      22             : class OpCodeParser
      23             : {
      24             : private:
      25             :     std::map<std::string, opcodetype> mapOpNames;
      26             : 
      27             : public:
      28          16 :     OpCodeParser()
      29           8 :     {
      30        1512 :         for (unsigned int op = 0; op <= MAX_OPCODE; ++op) {
      31             :             // Allow OP_RESERVED to get into mapOpNames
      32        1504 :             if (op < OP_NOP && op != OP_RESERVED) {
      33         768 :                 continue;
      34             :             }
      35             : 
      36         736 :             std::string strName = GetOpName(static_cast<opcodetype>(op));
      37         736 :             if (strName == "OP_UNKNOWN") {
      38           0 :                 continue;
      39             :             }
      40         736 :             mapOpNames[strName] = static_cast<opcodetype>(op);
      41             :             // Convenience: OP_ADD and just ADD are both recognized:
      42         736 :             if (strName.starts_with("OP_")) {
      43         736 :                 mapOpNames[strName.substr(3)] = static_cast<opcodetype>(op);
      44         736 :             }
      45         736 :         }
      46          16 :     }
      47        4015 :     opcodetype Parse(const std::string& s) const
      48             :     {
      49        4015 :         auto it = mapOpNames.find(s);
      50        4015 :         if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode");
      51        4013 :         return it->second;
      52           0 :     }
      53             : };
      54             : 
      55        4015 : opcodetype ParseOpCode(const std::string& s)
      56             : {
      57        4015 :     static const OpCodeParser ocp;
      58        4015 :     return ocp.Parse(s);
      59           0 : }
      60             : 
      61             : } // namespace
      62             : 
      63        2779 : CScript ParseScript(const std::string& s)
      64             : {
      65        2779 :     CScript result;
      66             : 
      67             : 
      68        2779 :     std::vector<std::string> words = SplitString(s, " \t\n");
      69             : 
      70       15184 :     for (const std::string& w : words) {
      71       12414 :         if (w.empty()) {
      72             :             // Empty string, ignore. (SplitString doesn't combine multiple separators)
      73       19991 :         } else if (std::all_of(w.begin(), w.end(), ::IsDigit) ||
      74        7577 :                    (w.front() == '-' && w.size() > 1 && std::all_of(w.begin() + 1, w.end(), ::IsDigit)))
      75             :         {
      76             :             // Number
      77        4793 :             const auto num{ToIntegral<int64_t>(w)};
      78             : 
      79             :             // limit the range of numbers ParseScript accepts in decimal
      80             :             // since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts
      81        4793 :             if (!num.has_value() || num > int64_t{0xffffffff} || num < -1 * int64_t{0xffffffff}) {
      82           7 :                 throw std::runtime_error("script parse error: decimal numeric value only allowed in the "
      83             :                                          "range -0xFFFFFFFF...0xFFFFFFFF");
      84             :             }
      85             : 
      86        4786 :             result << num.value();
      87       14393 :         } else if (w.substr(0, 2) == "0x" && w.size() > 2 && IsHex(std::string(w.begin() + 2, w.end()))) {
      88             :             // Raw hex data, inserted NOT pushed onto stack:
      89        2151 :             std::vector<unsigned char> raw = ParseHex(std::string(w.begin() + 2, w.end()));
      90        2151 :             result.insert(result.end(), raw.begin(), raw.end());
      91        7456 :         } else if (w.size() >= 2 && w.front() == '\'' && w.back() == '\'') {
      92             :             // Single-quoted string, pushed as data. NOTE: this is poor-man's
      93             :             // parsing, spaces/tabs/newlines in single-quoted strings won't work.
      94        1290 :             std::vector<unsigned char> value(w.begin() + 1, w.end() - 1);
      95        1290 :             result << value;
      96        1290 :         } else {
      97             :             // opcode, e.g. OP_ADD or ADD:
      98        4015 :             result << ParseOpCode(w);
      99             :         }
     100             :     }
     101             : 
     102        2770 :     return result;
     103        2779 : }
     104             : 
     105       19733 : static bool DecodeTx(CMutableTransaction& tx, const std::vector<unsigned char>& tx_data)
     106             : {
     107       19733 :     CDataStream ssData(tx_data, SER_NETWORK, PROTOCOL_VERSION);
     108             :     try {
     109       19733 :         ssData >> tx;
     110       19725 :         if (!ssData.empty()) {
     111           4 :             return false;
     112             :         }
     113       19729 :     } catch (const std::exception&) {
     114           8 :         return false;
     115           8 :     }
     116             : 
     117       19721 :     return true;
     118       19741 : }
     119             : 
     120       19737 : bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx)
     121             : {
     122       19737 :     if (!IsHex(hex_tx)) {
     123           4 :         return false;
     124             :     }
     125             : 
     126       19733 :     std::vector<unsigned char> txData(ParseHex(hex_tx));
     127       19733 :     return DecodeTx(tx, txData);
     128       19737 : }
     129             : 
     130          27 : bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
     131             : {
     132          27 :     if (!IsHex(hex_header)) return false;
     133             : 
     134          25 :     const std::vector<unsigned char> header_data{ParseHex(hex_header)};
     135          25 :     CDataStream ser_header(header_data, SER_NETWORK, PROTOCOL_VERSION);
     136             :     try {
     137          25 :         ser_header >> header;
     138          25 :     } catch (const std::exception&) {
     139           3 :         return false;
     140           3 :     }
     141          22 :     return true;
     142          30 : }
     143             : 
     144         921 : bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
     145             : {
     146         921 :     if (!IsHex(strHexBlk))
     147           0 :         return false;
     148             : 
     149         921 :     std::vector<unsigned char> blockData(ParseHex(strHexBlk));
     150         921 :     CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
     151             :     try {
     152         921 :         ssBlock >> block;
     153         921 :     }
     154             :     catch (const std::exception&) {
     155           6 :         return false;
     156           6 :     }
     157             : 
     158         915 :     return true;
     159         927 : }
     160             : 
     161         502 : bool ParseHashStr(const std::string& strHex, uint256& result)
     162             : {
     163         502 :     if ((strHex.size() != 64) || !IsHex(strHex))
     164          18 :         return false;
     165             : 
     166         484 :     result.SetHex(strHex);
     167         484 :     return true;
     168         502 : }
     169             : 
     170           3 : std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
     171             : {
     172           3 :     std::string strHex;
     173           3 :     if (v.isStr())
     174           3 :         strHex = v.getValStr();
     175           3 :     if (!IsHex(strHex))
     176           0 :         throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
     177           3 :     return ParseHex(strHex);
     178           3 : }
     179             : 
     180        2163 : int ParseSighashString(const UniValue& sighash)
     181             : {
     182        2163 :     int hash_type = SIGHASH_ALL;
     183        2163 :     if (!sighash.isNull()) {
     184          18 :         static std::map<std::string, int> map_sighash_values = {
     185          14 :             {std::string("ALL"), int(SIGHASH_ALL)},
     186          14 :             {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
     187          14 :             {std::string("NONE"), int(SIGHASH_NONE)},
     188          14 :             {std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
     189          14 :             {std::string("SINGLE"), int(SIGHASH_SINGLE)},
     190          14 :             {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
     191             :         };
     192          18 :         const std::string& strHashType = sighash.get_str();
     193          18 :         const auto& it = map_sighash_values.find(strHashType);
     194          18 :         if (it != map_sighash_values.end()) {
     195          18 :             hash_type = it->second;
     196          18 :         } else {
     197           0 :             throw std::runtime_error(strHashType + " is not a valid sighash parameter.");
     198             :         }
     199          18 :     }
     200        2163 :     return hash_type;
     201           0 : }

Generated by: LCOV version 1.16