LCOV - code coverage report
Current view: top level - src - external_signer.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 61 0
Test Date: 2026-02-04 04:43:42 Functions: 0.0 % 7 0
Branches: 0.0 % 152 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2018-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 <external_signer.h>
       6                 :             : 
       7                 :             : #include <chainparams.h>
       8                 :             : #include <common/run_command.h>
       9                 :             : #include <core_io.h>
      10                 :             : #include <psbt.h>
      11                 :             : #include <util/strencodings.h>
      12                 :             : 
      13                 :             : #include <algorithm>
      14                 :             : #include <stdexcept>
      15                 :             : #include <string>
      16                 :             : #include <vector>
      17                 :             : 
      18                 :           0 : ExternalSigner::ExternalSigner(std::string command, std::string chain, std::string fingerprint, std::string name)
      19                 :           0 :     : m_command{std::move(command)}, m_chain{std::move(chain)}, m_fingerprint{std::move(fingerprint)}, m_name{std::move(name)} {}
      20                 :             : 
      21                 :           0 : std::string ExternalSigner::NetworkArg() const
      22                 :             : {
      23                 :           0 :     return " --chain " + m_chain;
      24                 :             : }
      25                 :             : 
      26                 :           0 : bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, const std::string& chain)
      27                 :             : {
      28                 :             :     // Call <command> enumerate
      29   [ #  #  #  # ]:           0 :     const UniValue result = RunCommandParseJSON(command + " enumerate");
      30         [ #  # ]:           0 :     if (!result.isArray()) {
      31   [ #  #  #  # ]:           0 :         throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command));
      32                 :             :     }
      33   [ #  #  #  # ]:           0 :     for (const UniValue& signer : result.getValues()) {
      34                 :             :         // Check for error
      35         [ #  # ]:           0 :         const UniValue& error = signer.find_value("error");
      36         [ #  # ]:           0 :         if (!error.isNull()) {
      37         [ #  # ]:           0 :             if (!error.isStr()) {
      38   [ #  #  #  # ]:           0 :                 throw std::runtime_error(strprintf("'%s' error", command));
      39                 :             :             }
      40   [ #  #  #  # ]:           0 :             throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr()));
      41                 :             :         }
      42                 :             :         // Check if fingerprint is present
      43         [ #  # ]:           0 :         const UniValue& fingerprint = signer.find_value("fingerprint");
      44         [ #  # ]:           0 :         if (fingerprint.isNull()) {
      45   [ #  #  #  # ]:           0 :             throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command));
      46                 :             :         }
      47         [ #  # ]:           0 :         const std::string& fingerprintStr{fingerprint.get_str()};
      48                 :             :         // Skip duplicate signer
      49                 :           0 :         bool duplicate = false;
      50         [ #  # ]:           0 :         for (const ExternalSigner& signer : signers) {
      51         [ #  # ]:           0 :             if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
      52                 :             :         }
      53         [ #  # ]:           0 :         if (duplicate) break;
      54         [ #  # ]:           0 :         std::string name;
      55         [ #  # ]:           0 :         const UniValue& model_field = signer.find_value("model");
      56   [ #  #  #  # ]:           0 :         if (model_field.isStr() && model_field.getValStr() != "") {
      57         [ #  # ]:           0 :             name += model_field.getValStr();
      58                 :             :         }
      59         [ #  # ]:           0 :         signers.emplace_back(command, chain, fingerprintStr, name);
      60                 :           0 :     }
      61                 :           0 :     return true;
      62                 :           0 : }
      63                 :             : 
      64                 :           0 : UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const
      65                 :             : {
      66   [ #  #  #  #  :           0 :     return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " displayaddress --desc " + descriptor);
          #  #  #  #  #  
                #  #  # ]
      67                 :             : }
      68                 :             : 
      69                 :           0 : UniValue ExternalSigner::GetDescriptors(const int account)
      70                 :             : {
      71   [ #  #  #  #  :           0 :     return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " getdescriptors --account " + strprintf("%d", account));
          #  #  #  #  #  
             #  #  #  #  
                      # ]
      72                 :             : }
      73                 :             : 
      74                 :           0 : bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::string& error)
      75                 :             : {
      76                 :             :     // Serialize the PSBT
      77                 :           0 :     DataStream ssTx{};
      78         [ #  # ]:           0 :     ssTx << psbtx;
      79                 :             :     // parse ExternalSigner master fingerprint
      80   [ #  #  #  # ]:           0 :     std::vector<unsigned char> parsed_m_fingerprint = ParseHex(m_fingerprint);
      81                 :             :     // Check if signer fingerprint matches any input master key fingerprint
      82                 :           0 :     auto matches_signer_fingerprint = [&](const PSBTInput& input) {
      83         [ #  # ]:           0 :         for (const auto& entry : input.hd_keypaths) {
      84         [ #  # ]:           0 :             if (std::ranges::equal(parsed_m_fingerprint, entry.second.fingerprint)) return true;
      85                 :             :         }
      86         [ #  # ]:           0 :         for (const auto& entry : input.m_tap_bip32_paths) {
      87         [ #  # ]:           0 :             if (std::ranges::equal(parsed_m_fingerprint, entry.second.second.fingerprint)) return true;
      88                 :             :         }
      89                 :             :         return false;
      90                 :           0 :     };
      91                 :             : 
      92         [ #  # ]:           0 :     if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) {
      93   [ #  #  #  #  :           0 :         error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str());
             #  #  #  # ]
      94                 :           0 :         return false;
      95                 :             :     }
      96                 :             : 
      97   [ #  #  #  #  :           0 :     const std::string command = m_command + " --stdin --fingerprint " + m_fingerprint + NetworkArg();
             #  #  #  # ]
      98   [ #  #  #  #  :           0 :     const std::string stdinStr = "signtx " + EncodeBase64(ssTx.str());
                   #  # ]
      99                 :             : 
     100         [ #  # ]:           0 :     const UniValue signer_result = RunCommandParseJSON(command, stdinStr);
     101                 :             : 
     102   [ #  #  #  # ]:           0 :     if (signer_result.find_value("error").isStr()) {
     103   [ #  #  #  #  :           0 :         error = signer_result.find_value("error").get_str();
                   #  # ]
     104                 :             :         return false;
     105                 :             :     }
     106                 :             : 
     107   [ #  #  #  # ]:           0 :     if (!signer_result.find_value("psbt").isStr()) {
     108         [ #  # ]:           0 :         error = "Unexpected result from signer";
     109                 :             :         return false;
     110                 :             :     }
     111                 :             : 
     112                 :           0 :     PartiallySignedTransaction signer_psbtx;
     113         [ #  # ]:           0 :     std::string signer_psbt_error;
     114   [ #  #  #  #  :           0 :     if (!DecodeBase64PSBT(signer_psbtx, signer_result.find_value("psbt").get_str(), signer_psbt_error)) {
             #  #  #  # ]
     115         [ #  # ]:           0 :         error = strprintf("TX decode failed %s", signer_psbt_error);
     116                 :           0 :         return false;
     117                 :             :     }
     118                 :             : 
     119         [ #  # ]:           0 :     psbtx = signer_psbtx;
     120                 :             : 
     121                 :             :     return true;
     122                 :           0 : }
        

Generated by: LCOV version 2.0-1