LCOV - code coverage report
Current view: top level - src - psbt.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 69 240 28.8 %
Date: 2026-06-25 07:23:51 Functions: 9 29 31.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 <coins.h>
       6             : #include <consensus/tx_verify.h>
       7             : #include <policy/policy.h>
       8             : #include <policy/settings.h>
       9             : #include <psbt.h>
      10             : #include <tinyformat.h>
      11             : #include <util/check.h>
      12             : #include <util/strencodings.h>
      13             : 
      14             : #include <numeric>
      15             : 
      16           0 : PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
      17           0 : {
      18           0 :     inputs.resize(tx.vin.size());
      19           0 :     outputs.resize(tx.vout.size());
      20           0 : }
      21             : 
      22           0 : bool PartiallySignedTransaction::IsNull() const
      23             : {
      24           0 :     return !tx && inputs.empty() && outputs.empty() && unknown.empty();
      25             : }
      26             : 
      27           0 : bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt)
      28             : {
      29             :     // Prohibited to merge two PSBTs over different transactions
      30           0 :     if (tx->GetHash() != psbt.tx->GetHash()) {
      31           0 :         return false;
      32             :     }
      33             : 
      34           0 :     for (unsigned int i = 0; i < inputs.size(); ++i) {
      35           0 :         inputs[i].Merge(psbt.inputs[i]);
      36           0 :     }
      37           0 :     for (unsigned int i = 0; i < outputs.size(); ++i) {
      38           0 :         outputs[i].Merge(psbt.outputs[i]);
      39           0 :     }
      40           0 :     for (auto& xpub_pair : psbt.m_xpubs) {
      41           0 :         if (m_xpubs.count(xpub_pair.first) == 0) {
      42           0 :             m_xpubs[xpub_pair.first] = xpub_pair.second;
      43           0 :         } else {
      44           0 :             m_xpubs[xpub_pair.first].insert(xpub_pair.second.begin(), xpub_pair.second.end());
      45             :         }
      46             :     }
      47           0 :     unknown.insert(psbt.unknown.begin(), psbt.unknown.end());
      48             : 
      49           0 :     return true;
      50           0 : }
      51             : 
      52           0 : bool PartiallySignedTransaction::AddInput(const CTxIn& txin, PSBTInput& psbtin)
      53             : {
      54           0 :     if (std::find(tx->vin.begin(), tx->vin.end(), txin) != tx->vin.end()) {
      55           0 :         return false;
      56             :     }
      57           0 :     tx->vin.push_back(txin);
      58           0 :     psbtin.partial_sigs.clear();
      59           0 :     psbtin.final_script_sig.clear();
      60           0 :     inputs.push_back(psbtin);
      61           0 :     return true;
      62           0 : }
      63             : 
      64           0 : bool PartiallySignedTransaction::AddOutput(const CTxOut& txout, const PSBTOutput& psbtout)
      65             : {
      66           0 :     tx->vout.push_back(txout);
      67           0 :     outputs.push_back(psbtout);
      68           0 :     return true;
      69             : }
      70             : 
      71           4 : bool PartiallySignedTransaction::GetInputUTXO(CTxOut& utxo, int input_index) const
      72             : {
      73           4 :     const PSBTInput& input = inputs[input_index];
      74           4 :     uint32_t prevout_index = tx->vin[input_index].prevout.n;
      75           4 :     if (input.non_witness_utxo) {
      76           1 :         if (prevout_index >= input.non_witness_utxo->vout.size()) {
      77           1 :             return false;
      78             :         }
      79           0 :         if (input.non_witness_utxo->GetHash() != tx->vin[input_index].prevout.hash) {
      80           0 :             return false;
      81             :         }
      82           0 :         utxo = input.non_witness_utxo->vout[prevout_index];
      83           0 :     } else {
      84           3 :         return false;
      85             :     }
      86           0 :     return true;
      87           4 : }
      88             : 
      89           0 : bool PSBTInput::IsNull() const
      90             : {
      91           0 :     return !non_witness_utxo && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty();
      92             : }
      93             : 
      94           3 : void PSBTInput::FillSignatureData(SignatureData& sigdata) const
      95             : {
      96           3 :     if (!final_script_sig.empty()) {
      97           0 :         sigdata.scriptSig = final_script_sig;
      98           0 :         sigdata.complete = true;
      99           0 :     }
     100           3 :     if (sigdata.complete) {
     101           0 :         return;
     102             :     }
     103             : 
     104           3 :     sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end());
     105           3 :     if (!redeem_script.empty()) {
     106           2 :         sigdata.redeem_script = redeem_script;
     107           2 :     }
     108           7 :     for (const auto& key_pair : hd_keypaths) {
     109           4 :         sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
     110             :     }
     111           3 : }
     112             : 
     113           3 : void PSBTInput::FromSignatureData(const SignatureData& sigdata)
     114             : {
     115           3 :     if (sigdata.complete) {
     116           0 :         partial_sigs.clear();
     117           0 :         hd_keypaths.clear();
     118           0 :         redeem_script.clear();
     119             : 
     120           0 :         if (!sigdata.scriptSig.empty()) {
     121           0 :             final_script_sig = sigdata.scriptSig;
     122           0 :         }
     123           0 :         return;
     124             :     }
     125             : 
     126           3 :     partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end());
     127           3 :     if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
     128           1 :         redeem_script = sigdata.redeem_script;
     129           1 :     }
     130           9 :     for (const auto& entry : sigdata.misc_pubkeys) {
     131           6 :         hd_keypaths.emplace(entry.second);
     132             :     }
     133           3 : }
     134             : 
     135           0 : void PSBTInput::Merge(const PSBTInput& input)
     136             : {
     137           0 :     if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo;
     138             : 
     139           0 :     partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end());
     140           0 :     ripemd160_preimages.insert(input.ripemd160_preimages.begin(), input.ripemd160_preimages.end());
     141           0 :     sha256_preimages.insert(input.sha256_preimages.begin(), input.sha256_preimages.end());
     142           0 :     hash160_preimages.insert(input.hash160_preimages.begin(), input.hash160_preimages.end());
     143           0 :     hash256_preimages.insert(input.hash256_preimages.begin(), input.hash256_preimages.end());
     144           0 :     hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end());
     145           0 :     unknown.insert(input.unknown.begin(), input.unknown.end());
     146             : 
     147           0 :     if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script;
     148           0 :     if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig;
     149           0 : }
     150             : 
     151           0 : void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
     152             : {
     153           0 :     if (!redeem_script.empty()) {
     154           0 :         sigdata.redeem_script = redeem_script;
     155           0 :     }
     156           0 :     for (const auto& key_pair : hd_keypaths) {
     157           0 :         sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
     158             :     }
     159           0 : }
     160             : 
     161           0 : void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
     162             : {
     163           0 :     if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
     164           0 :         redeem_script = sigdata.redeem_script;
     165           0 :     }
     166           0 :     for (const auto& entry : sigdata.misc_pubkeys) {
     167           0 :         hd_keypaths.emplace(entry.second);
     168             :     }
     169           0 : }
     170             : 
     171           0 : bool PSBTOutput::IsNull() const
     172             : {
     173           0 :     return redeem_script.empty() && hd_keypaths.empty() && unknown.empty();
     174             : }
     175             : 
     176           0 : void PSBTOutput::Merge(const PSBTOutput& output)
     177             : {
     178           0 :     hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end());
     179           0 :     unknown.insert(output.unknown.begin(), output.unknown.end());
     180             : 
     181           0 :     if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
     182           0 : }
     183             : 
     184           0 : size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
     185           0 :     size_t count = 0;
     186           0 :     for (const auto& input : psbt.inputs) {
     187           0 :         if (!PSBTInputSigned(input)) {
     188           0 :             count++;
     189           0 :         }
     190             :     }
     191             : 
     192           0 :     return count;
     193             : }
     194             : 
     195           0 : void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index)
     196             : {
     197           0 :     CMutableTransaction& tx = *Assert(psbt.tx);
     198           0 :     const CTxOut& out = tx.vout.at(index);
     199           0 :     PSBTOutput& psbt_out = psbt.outputs.at(index);
     200             : 
     201             :     // Fill a SignatureData with output info
     202           0 :     SignatureData sigdata;
     203           0 :     psbt_out.FillSignatureData(sigdata);
     204             : 
     205             :     // Construct a would-be spend of this output, to update sigdata with.
     206             :     // Note that ProduceSignature is used to fill in metadata (not actual signatures),
     207             :     // so provider does not need to provide any private keys (it can be a HidingSigningProvider).
     208           0 :     MutableTransactionSignatureCreator creator(tx, /*input_idx=*/0, out.nValue, SIGHASH_ALL);
     209           0 :     ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
     210             : 
     211             :     // Put redeem_script, key paths, into PSBTOutput.
     212           0 :     psbt_out.FromSignatureData(sigdata);
     213           0 : }
     214          19 : bool PSBTInputSigned(const PSBTInput& input)
     215             : {
     216          19 :     return !input.final_script_sig.empty();
     217             : }
     218             : 
     219           2 : PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction& psbt)
     220             : {
     221           2 :     const CMutableTransaction& tx = *psbt.tx;
     222           2 :     bool have_all_spent_outputs = true;
     223           2 :     std::vector<CTxOut> utxos(tx.vin.size());
     224           6 :     for (size_t idx = 0; idx < tx.vin.size(); ++idx) {
     225           4 :         if (!psbt.GetInputUTXO(utxos[idx], idx)) have_all_spent_outputs = false;
     226           4 :     }
     227           2 :     PrecomputedTransactionData txdata;
     228           2 :     if (have_all_spent_outputs) {
     229           0 :         txdata.Init(tx, std::move(utxos), true);
     230           0 :     } else {
     231           2 :         txdata.Init(tx, {}, true);
     232             :     }
     233           2 :     return txdata;
     234           2 : }
     235             : 
     236           3 : bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash,  SignatureData* out_sigdata, bool finalize)
     237             : {
     238           3 :     PSBTInput& input = psbt.inputs.at(index);
     239           3 :     const CMutableTransaction& tx = *psbt.tx;
     240             : 
     241           3 :     if (PSBTInputSigned(input)) {
     242           0 :         return true;
     243             :     }
     244             : 
     245             :     // Fill SignatureData with input info
     246           3 :     SignatureData sigdata;
     247           3 :     input.FillSignatureData(sigdata);
     248             : 
     249             :     // Get UTXO
     250           3 :     CTxOut utxo;
     251             : 
     252           3 :     if (input.non_witness_utxo) {
     253             :         // If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
     254           3 :         COutPoint prevout = tx.vin[index].prevout;
     255           3 :         if (prevout.n >= input.non_witness_utxo->vout.size()) {
     256           0 :             return false;
     257             :         }
     258           3 :         if (input.non_witness_utxo->GetHash() != prevout.hash) {
     259           0 :             return false;
     260             :         }
     261           3 :         utxo = input.non_witness_utxo->vout[prevout.n];
     262           3 :     } else {
     263           0 :         return false;
     264             :     }
     265             : 
     266             :     bool sig_complete;
     267           3 :     if (txdata == nullptr) {
     268           0 :         sig_complete = ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, utxo.scriptPubKey, sigdata);
     269           0 :     } else {
     270           3 :         MutableTransactionSignatureCreator creator(tx, index, utxo.nValue, txdata, sighash);
     271           3 :         sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
     272           3 :     }
     273             : 
     274             :     // If we are not finalizing, set sigdata.complete to false to not set the scriptSig
     275           3 :     if (!finalize && sigdata.complete) sigdata.complete = false;
     276             : 
     277           3 :     input.FromSignatureData(sigdata);
     278             : 
     279             :     // Fill in the missing info
     280           3 :     if (out_sigdata) {
     281           0 :         out_sigdata->missing_pubkeys = sigdata.missing_pubkeys;
     282           0 :         out_sigdata->missing_sigs = sigdata.missing_sigs;
     283           0 :         out_sigdata->missing_redeem_script = sigdata.missing_redeem_script;
     284           0 :     }
     285             : 
     286           3 :     return sig_complete;
     287           3 : }
     288             : 
     289           1 : void RemoveUnnecessaryTransactions(PartiallySignedTransaction& /* psbtx */, const int& /* sighash_type */)
     290             : {
     291             :     // Dash does not support segwit, so there are no witness_utxos to consider.
     292             :     // In Bitcoin, this function drops non_witness_utxos when all inputs are
     293             :     // segwit v1+, which cannot occur in Dash.
     294           1 : }
     295             : 
     296           0 : bool FinalizePSBT(PartiallySignedTransaction& psbtx)
     297             : {
     298             :     // Finalize input signatures -- in case we have partial signatures that add up to a complete
     299             :     //   signature, but have not combined them yet (e.g. because the combiner that created this
     300             :     //   PartiallySignedTransaction did not understand them), this will combine them into a final
     301             :     //   script.
     302           0 :     bool complete = true;
     303           0 :     const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
     304           0 :     for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
     305           0 :         complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
     306           0 :     }
     307             : 
     308           0 :     return complete;
     309           0 : }
     310             : 
     311           0 : bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransaction& result)
     312             : {
     313             :     // It's not safe to extract a PSBT that isn't finalized, and there's no easy way to check
     314             :     //   whether a PSBT is finalized without finalizing it, so we just do this.
     315           0 :     if (!FinalizePSBT(psbtx)) {
     316           0 :         return false;
     317             :     }
     318             : 
     319           0 :     result = *psbtx.tx;
     320           0 :     for (unsigned int i = 0; i < result.vin.size(); ++i) {
     321           0 :         result.vin[i].scriptSig = psbtx.inputs[i].final_script_sig;
     322           0 :     }
     323           0 :     return true;
     324           0 : }
     325             : 
     326           0 : TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs)
     327             : {
     328           0 :     out = psbtxs[0]; // Copy the first one
     329             : 
     330             :     // Merge
     331           0 :     for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) {
     332           0 :         if (!out.Merge(*it)) {
     333           0 :             return TransactionError::PSBT_MISMATCH;
     334             :         }
     335           0 :     }
     336           0 :     return TransactionError::OK;
     337           0 : }
     338             : 
     339           0 : std::string PSBTRoleName(PSBTRole role) {
     340           0 :     switch (role) {
     341           0 :     case PSBTRole::CREATOR: return "creator";
     342           0 :     case PSBTRole::UPDATER: return "updater";
     343           0 :     case PSBTRole::SIGNER: return "signer";
     344           0 :     case PSBTRole::FINALIZER: return "finalizer";
     345           0 :     case PSBTRole::EXTRACTOR: return "extractor";
     346             :         // no default case, so the compiler can warn about missing cases
     347             :     }
     348           0 :     assert(false);
     349           0 : }
     350             : 
     351           0 : bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
     352             : {
     353           0 :     auto tx_data = DecodeBase64(base64_tx);
     354           0 :     if (!tx_data) {
     355           0 :         error = "invalid base64";
     356           0 :         return false;
     357             :     }
     358           0 :     return DecodeRawPSBT(psbt, MakeByteSpan(*tx_data), error);
     359           0 : }
     360             : 
     361           0 : bool DecodeRawPSBT(PartiallySignedTransaction& psbt, Span<const std::byte> tx_data, std::string& error)
     362             : {
     363           0 :     CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION);
     364             :     try {
     365           0 :         ss_data >> psbt;
     366           0 :         if (!ss_data.empty()) {
     367           0 :             error = "extra data after PSBT";
     368           0 :             return false;
     369             :         }
     370           0 :     } catch (const std::exception& e) {
     371           0 :         error = e.what();
     372           0 :         return false;
     373           0 :     }
     374           0 :     return true;
     375           0 : }
     376             : 
     377           1 : uint32_t PartiallySignedTransaction::GetVersion() const
     378             : {
     379           1 :     if (m_version != std::nullopt) {
     380           0 :         return *m_version;
     381             :     }
     382           1 :     return 0;
     383           1 : }

Generated by: LCOV version 1.16