LCOV - code coverage report
Current view: top level - src/script - standard.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 113 126 89.7 %
Date: 2026-06-25 07:23:51 Functions: 27 29 93.1 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <script/standard.h>
       7             : 
       8             : #include <pubkey.h>
       9             : #include <script/script.h>
      10             : 
      11             : #include <string>
      12             : 
      13             : typedef std::vector<unsigned char> valtype;
      14             : 
      15             : bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
      16             : unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
      17             : 
      18        1346 : CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in)) {}
      19           2 : CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast<uint160>(in)) {}
      20             : 
      21         764 : ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in)) {}
      22           0 : ScriptHash::ScriptHash(const CScriptID& in) : BaseHash(static_cast<uint160>(in)) {}
      23             : 
      24       32378 : PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
      25      169872 : PKHash::PKHash(const CKeyID& pubkey_id) : BaseHash(pubkey_id) {}
      26             : 
      27          14 : CKeyID ToKeyID(const PKHash& key_hash)
      28             : {
      29          14 :     return CKeyID{static_cast<uint160>(key_hash)};
      30             : }
      31             : 
      32         575 : std::string GetTxnOutputType(TxoutType t)
      33             : {
      34         575 :     switch (t) {
      35          95 :     case TxoutType::NONSTANDARD: return "nonstandard";
      36          93 :     case TxoutType::PUBKEY: return "pubkey";
      37         105 :     case TxoutType::PUBKEYHASH: return "pubkeyhash";
      38          94 :     case TxoutType::SCRIPTHASH: return "scripthash";
      39          94 :     case TxoutType::MULTISIG: return "multisig";
      40          94 :     case TxoutType::NULL_DATA: return "nulldata";
      41             :     } // no default case, so the compiler can warn about missing cases
      42           0 :     assert(false);
      43         575 : }
      44             : 
      45       28279 : static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
      46             : {
      47       28279 :     if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE && script.back() == OP_CHECKSIG) {
      48          61 :         pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1);
      49          61 :         return CPubKey::ValidSize(pubkey);
      50             :     }
      51       28218 :     if (script.size() == CPubKey::COMPRESSED_SIZE + 2 && script[0] == CPubKey::COMPRESSED_SIZE && script.back() == OP_CHECKSIG) {
      52        2147 :         pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_SIZE + 1);
      53        2147 :         return CPubKey::ValidSize(pubkey);
      54             :     }
      55       26071 :     return false;
      56       28279 : }
      57             : 
      58       26071 : static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
      59             : {
      60       26071 :     if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
      61       25772 :         pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
      62       25772 :         return true;
      63             :     }
      64         299 :     return false;
      65       26071 : }
      66             : 
      67             : /** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
      68         530 : static constexpr bool IsSmallInteger(opcodetype opcode)
      69             : {
      70         530 :     return opcode >= OP_1 && opcode <= OP_16;
      71             : }
      72             : 
      73         522 : static constexpr bool IsValidMultisigKeyCount(int n_keys)
      74             : {
      75         522 :     return n_keys > 0 && n_keys <= MAX_PUBKEYS_PER_MULTISIG;
      76             : }
      77             : 
      78         530 : static bool GetMultisigKeyCount(opcodetype opcode, valtype data, int& count)
      79             : {
      80         530 :     if (IsSmallInteger(opcode)) {
      81         522 :         count = CScript::DecodeOP_N(opcode);
      82         522 :         return IsValidMultisigKeyCount(count);
      83             :     }
      84             : 
      85           8 :     if (IsPushdataOp(opcode)) {
      86           4 :         if (!CheckMinimalPush(data, opcode)) return false;
      87             :         try {
      88           0 :             count = CScriptNum(data, /* fRequireMinimal = */ true).getint();
      89           0 :             return IsValidMultisigKeyCount(count);
      90           0 :         } catch (const scriptnum_error&) {
      91           0 :             return false;
      92           0 :         }
      93           0 :     }
      94             : 
      95           4 :     return false;
      96         530 : }
      97             : 
      98         299 : static bool MatchMultisig(const CScript& script, int& required_sigs, std::vector<valtype>& pubkeys)
      99             : {
     100             :     opcodetype opcode;
     101         299 :     valtype data;
     102             :     int num_keys;
     103             : 
     104         299 :     CScript::const_iterator it = script.begin();
     105         299 :     if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
     106             : 
     107         267 :     if (!script.GetOp(it, opcode, data) || !GetMultisigKeyCount(opcode, data, required_sigs)) return false;
     108         807 :     while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
     109         544 :         pubkeys.emplace_back(std::move(data));
     110             :     }
     111         263 :     if (!GetMultisigKeyCount(opcode, data, num_keys)) return false;
     112             : 
     113         259 :     if (pubkeys.size() != static_cast<unsigned long>(num_keys) || num_keys < required_sigs) return false;
     114             : 
     115         254 :     return (it + 1 == script.end());
     116         299 : }
     117             : 
     118       35260 : TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
     119             : {
     120       35260 :     vSolutionsRet.clear();
     121             : 
     122             :     // Shortcut for pay-to-script-hash, which are more constrained than the other types:
     123             :     // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
     124       35260 :     if (scriptPubKey.IsPayToScriptHash())
     125             :     {
     126         376 :         std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
     127         376 :         vSolutionsRet.push_back(hashBytes);
     128         376 :         return TxoutType::SCRIPTHASH;
     129         376 :     }
     130             : 
     131             :     // Provably prunable, data-carrying output
     132             :     //
     133             :     // So long as script passes the IsUnspendable() test and all but the first
     134             :     // byte passes the IsPushOnly() test we don't care what exactly is in the
     135             :     // script.
     136       34884 :     if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
     137        6605 :         return TxoutType::NULL_DATA;
     138             :     }
     139             : 
     140       28279 :     std::vector<unsigned char> data;
     141       28279 :     if (MatchPayToPubkey(scriptPubKey, data)) {
     142        2208 :         vSolutionsRet.push_back(std::move(data));
     143        2208 :         return TxoutType::PUBKEY;
     144             :     }
     145             : 
     146       26071 :     if (MatchPayToPubkeyHash(scriptPubKey, data)) {
     147       25772 :         vSolutionsRet.push_back(std::move(data));
     148       25772 :         return TxoutType::PUBKEYHASH;
     149             :     }
     150             : 
     151             :     int required;
     152         299 :     std::vector<std::vector<unsigned char>> keys;
     153         299 :     if (MatchMultisig(scriptPubKey, required, keys)) {
     154         254 :         vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..20
     155         254 :         vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
     156         254 :         vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..20
     157         254 :         return TxoutType::MULTISIG;
     158             :     }
     159             : 
     160          45 :     vSolutionsRet.clear();
     161          45 :     return TxoutType::NONSTANDARD;
     162       35260 : }
     163             : 
     164       14624 : bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
     165             : {
     166       14624 :     std::vector<valtype> vSolutions;
     167       14624 :     TxoutType whichType = Solver(scriptPubKey, vSolutions);
     168             : 
     169       14624 :     switch (whichType) {
     170             :     case TxoutType::PUBKEY: {
     171          27 :         CPubKey pubKey(vSolutions[0]);
     172          27 :         if (!pubKey.IsValid())
     173           0 :             return false;
     174             : 
     175          27 :         addressRet = PKHash(pubKey);
     176          27 :         return true;
     177             :     }
     178             :     case TxoutType::PUBKEYHASH: {
     179        7960 :         addressRet = PKHash(uint160(vSolutions[0]));
     180        7960 :         return true;
     181             :     }
     182             :     case TxoutType::SCRIPTHASH: {
     183          32 :         addressRet = ScriptHash(uint160(vSolutions[0]));
     184          32 :         return true;
     185             :     }
     186             :     case TxoutType::MULTISIG:
     187             :     case TxoutType::NULL_DATA:
     188             :     case TxoutType::NONSTANDARD:
     189        6605 :         return false;
     190             :     } // no default case, so the compiler can warn about missing cases
     191           0 :     assert(false);
     192       14624 : }
     193             : 
     194             : namespace {
     195             : class CScriptVisitor
     196             : {
     197             : public:
     198           1 :     CScript operator()(const CNoDestination& dest) const
     199             :     {
     200           1 :         return CScript();
     201             :     }
     202             : 
     203      118019 :     CScript operator()(const PKHash& keyID) const
     204             :     {
     205      118019 :         return CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
     206           0 :     }
     207             : 
     208         415 :     CScript operator()(const ScriptHash& scriptID) const
     209             :     {
     210         415 :         return CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
     211           0 :     }
     212             : };
     213             : } // namespace
     214             : 
     215      118435 : CScript GetScriptForDestination(const CTxDestination& dest)
     216             : {
     217      118435 :     return std::visit(CScriptVisitor(), dest);
     218             : }
     219             : 
     220       10254 : CScript GetScriptForRawPubKey(const CPubKey& pubKey)
     221             : {
     222       10254 :     return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
     223           0 : }
     224             : 
     225         319 : CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
     226             : {
     227         319 :     CScript script;
     228             : 
     229         319 :     script << nRequired;
     230         965 :     for (const CPubKey& key : keys)
     231         646 :         script << ToByteVector(key);
     232         319 :     script << keys.size() << OP_CHECKMULTISIG;
     233             : 
     234         319 :     return script;
     235         319 : }
     236             : 
     237         474 : bool IsValidDestination(const CTxDestination& dest) {
     238         474 :     return dest.index() != 0;
     239             : }

Generated by: LCOV version 1.16