LCOV - code coverage report
Current view: top level - src/wallet - external_signer_scriptpubkeyman.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 94.5 % 55 52
Test Date: 2026-09-29 06:14:05 Functions: 100.0 % 5 5
Branches: 50.9 % 116 59

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2020-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 <chainparams.h>
       6                 :             : #include <common/args.h>
       7                 :             : #include <common/system.h>
       8                 :             : #include <external_signer.h>
       9                 :             : #include <node/types.h>
      10                 :             : #include <wallet/external_signer_scriptpubkeyman.h>
      11                 :             : 
      12                 :             : #include <iostream>
      13                 :             : #include <key_io.h>
      14                 :             : #include <memory>
      15                 :             : #include <stdexcept>
      16                 :             : #include <string>
      17                 :             : #include <univalue.h>
      18                 :             : #include <utility>
      19                 :             : #include <vector>
      20                 :             : 
      21                 :             : using common::PSBTError;
      22                 :             : 
      23                 :             : namespace wallet {
      24                 :           8 : std::unique_ptr<ExternalSignerScriptPubKeyMan> ExternalSignerScriptPubKeyMan::LoadFromStorage(WalletStorage& storage, const uint256& id, WalletDescriptor& descriptor, int64_t keypool_size, const KeyMap& keys, const CryptedKeyMap& ckeys)
      25                 :             : {
      26         [ +  - ]:           8 :     return std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(storage, id, descriptor, keypool_size, keys, ckeys));
      27                 :             : }
      28                 :             : 
      29                 :          16 : std::unique_ptr<ExternalSignerScriptPubKeyMan> ExternalSignerScriptPubKeyMan::CreateNew(WalletStorage& storage, WalletBatch& batch, int64_t keypool_size, std::unique_ptr<Descriptor> desc)
      30                 :             : {
      31                 :          16 :     int64_t creation_time = GetTime();
      32                 :             : 
      33                 :             :     // Make the descriptor
      34         [ +  - ]:          16 :     WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
      35                 :             : 
      36   [ +  -  +  -  :          16 :     auto spkm = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(storage, w_desc, keypool_size));
                   +  - ]
      37                 :             : 
      38         [ +  - ]:          16 :     LOCK(spkm->cs_desc_man);
      39   [ +  -  -  + ]:          16 :     assert(storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
      40   [ +  -  -  + ]:          16 :     assert(storage.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
      41                 :             : 
      42                 :             :     // Store the descriptor
      43   [ +  -  +  -  :          16 :     if (!batch.WriteDescriptor(spkm->GetID(), spkm->m_wallet_descriptor)) {
                   -  + ]
      44   [ #  #  #  # ]:           0 :         throw std::runtime_error(std::string(__func__) + ": writing descriptor failed");
      45                 :             :     }
      46                 :             : 
      47                 :             :     // TopUp
      48         [ +  - ]:          16 :     spkm->TopUpWithDB(batch);
      49                 :             : 
      50         [ +  - ]:          16 :     storage.UnsetBlankWalletFlag(batch);
      51         [ +  - ]:          32 :     return spkm;
      52                 :          16 : }
      53                 :             : 
      54                 :          14 :  util::Result<ExternalSigner> ExternalSignerScriptPubKeyMan::GetExternalSigner() {
      55   [ +  -  +  - ]:          28 :     const std::string command = gArgs.GetArg("-signer", "");
      56   [ -  +  -  -  :          14 :     if (command == "") return util::Error{Untranslated("restart bitcoind with -signer=<cmd>")};
                   -  - ]
      57                 :          14 :     std::vector<ExternalSigner> signers;
      58   [ +  -  +  -  :          16 :     ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString());
                   +  + ]
      59   [ +  +  +  -  :          14 :     if (signers.empty()) return util::Error{Untranslated("No external signers found")};
                   +  - ]
      60                 :             :     // TODO: add fingerprint argument instead of failing in case of multiple signers.
      61   [ -  +  +  +  :          13 :     if (signers.size() > 1) return util::Error{Untranslated("More than one external signer found. Please connect only one at a time.")};
             +  -  +  - ]
      62         [ +  - ]:          20 :     return signers[0];
      63                 :          26 : }
      64                 :             : 
      65                 :           4 : util::Result<void> ExternalSignerScriptPubKeyMan::DisplayAddress(const CTxDestination& dest, const ExternalSigner &signer) const
      66                 :             : {
      67                 :             :     // TODO: avoid the need to infer a descriptor from inside a descriptor wallet
      68                 :           8 :     const CScript& scriptPubKey = GetScriptForDestination(dest);
      69         [ +  - ]:           4 :     auto provider = GetSolvingProvider(scriptPubKey);
      70         [ +  - ]:           4 :     auto descriptor = InferDescriptor(scriptPubKey, *provider);
      71                 :             : 
      72   [ +  -  +  - ]:           8 :     const UniValue& result = signer.DisplayAddress(descriptor->ToString());
      73                 :             : 
      74         [ +  - ]:           4 :     const UniValue& error = result.find_value("error");
      75   [ -  +  -  - ]:           4 :     if (error.isStr()) return util::Error{strprintf(_("Signer returned error: %s"), error.getValStr())};
      76                 :             : 
      77         [ +  - ]:           4 :     const UniValue& ret_address = result.find_value("address");
      78   [ -  +  -  - ]:           4 :     if (!ret_address.isStr()) return util::Error{_("Signer did not echo address")};
      79                 :             : 
      80   [ +  -  +  + ]:           4 :     if (ret_address.getValStr() != EncodeDestination(dest)) {
      81         [ +  - ]:           3 :         return util::Error{strprintf(_("Signer echoed unexpected address %s"), ret_address.getValStr())};
      82                 :             :     }
      83                 :             : 
      84                 :           3 :     return util::Result<void>();
      85                 :           4 : }
      86                 :             : 
      87                 :             : // If sign is true, transaction must previously have been filled
      88                 :          57 : std::optional<PSBTError> ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, const common::PSBTFillOptions& options, int* n_signed) const
      89                 :             : {
      90         [ +  + ]:          57 :     if (!options.sign) {
      91                 :          32 :         return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, options, n_signed);
      92                 :             :     }
      93                 :             : 
      94                 :             :     // Already complete if every input is now signed
      95                 :          25 :     bool complete = true;
      96         [ +  + ]:          50 :     for (const auto& input : psbt.inputs) {
      97                 :          25 :         complete &= PSBTInputSigned(input);
      98                 :             :     }
      99         [ +  + ]:          25 :     if (complete) return {};
     100                 :             : 
     101                 :           4 :     auto signer{GetExternalSigner()};
     102         [ +  + ]:           4 :     if (!signer) {
     103   [ +  -  +  - ]:           1 :         LogWarning("%s", util::ErrorString(signer).original);
     104                 :           1 :         return PSBTError::EXTERNAL_SIGNER_NOT_FOUND;
     105                 :             :     }
     106                 :             : 
     107                 :           3 :     std::string failure_reason;
     108   [ +  -  -  + ]:           3 :     if(!signer->SignTransaction(psbt, failure_reason)) {
     109         [ #  # ]:           0 :         LogWarning("Failed to sign: %s\n", failure_reason);
     110                 :           0 :         return PSBTError::EXTERNAL_SIGNER_FAILED;
     111                 :             :     }
     112   [ +  -  +  - ]:           3 :     if (options.finalize) FinalizePSBT(psbt); // This won't work in a multisig setup
     113                 :           3 :     return {};
     114                 :           7 : }
     115                 :             : } // namespace wallet
        

Generated by: LCOV version 2.0-1