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

          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      149498 : CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in)) {}
      19        1784 : CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast<uint160>(in)) {}
      20             : 
      21      136440 : ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in)) {}
      22          24 : ScriptHash::ScriptHash(const CScriptID& in) : BaseHash(static_cast<uint160>(in)) {}
      23             : 
      24      142840 : PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
      25      902976 : PKHash::PKHash(const CKeyID& pubkey_id) : BaseHash(pubkey_id) {}
      26             : 
      27       12465 : CKeyID ToKeyID(const PKHash& key_hash)
      28             : {
      29       12465 :     return CKeyID{static_cast<uint160>(key_hash)};
      30             : }
      31             : 
      32       69080 : std::string GetTxnOutputType(TxoutType t)
      33             : {
      34       69080 :     switch (t) {
      35        6237 :     case TxoutType::NONSTANDARD: return "nonstandard";
      36        6539 :     case TxoutType::PUBKEY: return "pubkey";
      37       26466 :     case TxoutType::PUBKEYHASH: return "pubkeyhash";
      38       17112 :     case TxoutType::SCRIPTHASH: return "scripthash";
      39        6272 :     case TxoutType::MULTISIG: return "multisig";
      40        6454 :     case TxoutType::NULL_DATA: return "nulldata";
      41             :     } // no default case, so the compiler can warn about missing cases
      42           0 :     assert(false);
      43       69080 : }
      44             : 
      45     4275341 : static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
      46             : {
      47     4275341 :     if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE && script.back() == OP_CHECKSIG) {
      48         883 :         pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1);
      49         883 :         return CPubKey::ValidSize(pubkey);
      50             :     }
      51     4274458 :     if (script.size() == CPubKey::COMPRESSED_SIZE + 2 && script[0] == CPubKey::COMPRESSED_SIZE && script.back() == OP_CHECKSIG) {
      52       44012 :         pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_SIZE + 1);
      53       44012 :         return CPubKey::ValidSize(pubkey);
      54             :     }
      55     4230446 :     return false;
      56     4275341 : }
      57             : 
      58     4230442 : static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
      59             : {
      60     4230442 :     if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
      61     4224095 :         pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
      62     4224095 :         return true;
      63             :     }
      64        6349 :     return false;
      65     4230444 : }
      66             : 
      67             : /** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
      68        3378 : static constexpr bool IsSmallInteger(opcodetype opcode)
      69             : {
      70        3378 :     return opcode >= OP_1 && opcode <= OP_16;
      71             : }
      72             : 
      73        3370 : static constexpr bool IsValidMultisigKeyCount(int n_keys)
      74             : {
      75        3370 :     return n_keys > 0 && n_keys <= MAX_PUBKEYS_PER_MULTISIG;
      76             : }
      77             : 
      78        3378 : static bool GetMultisigKeyCount(opcodetype opcode, valtype data, int& count)
      79             : {
      80        3378 :     if (IsSmallInteger(opcode)) {
      81        3370 :         count = CScript::DecodeOP_N(opcode);
      82        3370 :         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        3378 : }
      97             : 
      98        6349 : static bool MatchMultisig(const CScript& script, int& required_sigs, std::vector<valtype>& pubkeys)
      99             : {
     100             :     opcodetype opcode;
     101        6349 :     valtype data;
     102             :     int num_keys;
     103             : 
     104        6349 :     CScript::const_iterator it = script.begin();
     105        6349 :     if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
     106             : 
     107        1691 :     if (!script.GetOp(it, opcode, data) || !GetMultisigKeyCount(opcode, data, required_sigs)) return false;
     108        7735 :     while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
     109        6048 :         pubkeys.emplace_back(std::move(data));
     110             :     }
     111        1687 :     if (!GetMultisigKeyCount(opcode, data, num_keys)) return false;
     112             : 
     113        1683 :     if (pubkeys.size() != static_cast<unsigned long>(num_keys) || num_keys < required_sigs) return false;
     114             : 
     115        1678 :     return (it + 1 == script.end());
     116        6349 : }
     117             : 
     118     4568940 : TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
     119             : {
     120     4568940 :     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     4568940 :     if (scriptPubKey.IsPayToScriptHash())
     125             :     {
     126      200174 :         std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
     127      200174 :         vSolutionsRet.push_back(hashBytes);
     128      200174 :         return TxoutType::SCRIPTHASH;
     129      200174 :     }
     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     4368766 :     if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
     137       93424 :         return TxoutType::NULL_DATA;
     138             :     }
     139             : 
     140     4275342 :     std::vector<unsigned char> data;
     141     4275342 :     if (MatchPayToPubkey(scriptPubKey, data)) {
     142       44895 :         vSolutionsRet.push_back(std::move(data));
     143       44895 :         return TxoutType::PUBKEY;
     144             :     }
     145             : 
     146     4230445 :     if (MatchPayToPubkeyHash(scriptPubKey, data)) {
     147     4224095 :         vSolutionsRet.push_back(std::move(data));
     148     4224094 :         return TxoutType::PUBKEYHASH;
     149             :     }
     150             : 
     151             :     int required;
     152        6349 :     std::vector<std::vector<unsigned char>> keys;
     153        6349 :     if (MatchMultisig(scriptPubKey, required, keys)) {
     154        1678 :         vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..20
     155        1678 :         vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
     156        1678 :         vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..20
     157        1678 :         return TxoutType::MULTISIG;
     158             :     }
     159             : 
     160        4671 :     vSolutionsRet.clear();
     161        4671 :     return TxoutType::NONSTANDARD;
     162     4568940 : }
     163             : 
     164      313829 : bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
     165             : {
     166      313829 :     std::vector<valtype> vSolutions;
     167      313829 :     TxoutType whichType = Solver(scriptPubKey, vSolutions);
     168             : 
     169      313829 :     switch (whichType) {
     170             :     case TxoutType::PUBKEY: {
     171         896 :         CPubKey pubKey(vSolutions[0]);
     172         896 :         if (!pubKey.IsValid())
     173           0 :             return false;
     174             : 
     175         896 :         addressRet = PKHash(pubKey);
     176         896 :         return true;
     177             :     }
     178             :     case TxoutType::PUBKEYHASH: {
     179      261570 :         addressRet = PKHash(uint160(vSolutions[0]));
     180      261570 :         return true;
     181             :     }
     182             :     case TxoutType::SCRIPTHASH: {
     183       25757 :         addressRet = ScriptHash(uint160(vSolutions[0]));
     184       25757 :         return true;
     185             :     }
     186             :     case TxoutType::MULTISIG:
     187             :     case TxoutType::NULL_DATA:
     188             :     case TxoutType::NONSTANDARD:
     189       25606 :         return false;
     190             :     } // no default case, so the compiler can warn about missing cases
     191           0 :     assert(false);
     192      313829 : }
     193             : 
     194             : namespace {
     195             : class CScriptVisitor
     196             : {
     197             : public:
     198          16 :     CScript operator()(const CNoDestination& dest) const
     199             :     {
     200          16 :         return CScript();
     201             :     }
     202             : 
     203      575635 :     CScript operator()(const PKHash& keyID) const
     204             :     {
     205      575635 :         return CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
     206           0 :     }
     207             : 
     208       83469 :     CScript operator()(const ScriptHash& scriptID) const
     209             :     {
     210       83469 :         return CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
     211           0 :     }
     212             : };
     213             : } // namespace
     214             : 
     215      659120 : CScript GetScriptForDestination(const CTxDestination& dest)
     216             : {
     217      659120 :     return std::visit(CScriptVisitor(), dest);
     218             : }
     219             : 
     220       85197 : CScript GetScriptForRawPubKey(const CPubKey& pubKey)
     221             : {
     222       85197 :     return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
     223           0 : }
     224             : 
     225       30220 : CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
     226             : {
     227       30220 :     CScript script;
     228             : 
     229       30220 :     script << nRequired;
     230      168864 :     for (const CPubKey& key : keys)
     231      138644 :         script << ToByteVector(key);
     232       30220 :     script << keys.size() << OP_CHECKMULTISIG;
     233             : 
     234       30220 :     return script;
     235       30220 : }
     236             : 
     237       70451 : bool IsValidDestination(const CTxDestination& dest) {
     238       70451 :     return dest.index() != 0;
     239             : }

Generated by: LCOV version 1.16