LCOV - code coverage report
Current view: top level - src/node - psbt.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 86 0
Test Date: 2026-05-17 07:09:40 Functions: 0.0 % 1 0
Branches: 0.0 % 132 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2009-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 <coins.h>
       6                 :             : #include <consensus/amount.h>
       7                 :             : #include <consensus/tx_verify.h>
       8                 :             : #include <node/psbt.h>
       9                 :             : #include <policy/policy.h>
      10                 :             : #include <policy/settings.h>
      11                 :             : #include <tinyformat.h>
      12                 :             : 
      13                 :             : #include <numeric>
      14                 :             : 
      15                 :             : namespace node {
      16                 :           0 : PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
      17                 :             : {
      18                 :             :     // Go through each input and build status
      19         [ #  # ]:           0 :     PSBTAnalysis result;
      20                 :             : 
      21         [ #  # ]:           0 :     std::optional<CMutableTransaction> unsigned_tx = psbtx.GetUnsignedTx();
      22         [ #  # ]:           0 :     if (!unsigned_tx) {
      23   [ #  #  #  # ]:           0 :         result.SetInvalid("PSBT cannot be made into a valid transaction");
      24                 :           0 :         return result;
      25                 :             :     }
      26         [ #  # ]:           0 :     CMutableTransaction& mtx = *unsigned_tx;
      27                 :             : 
      28                 :           0 :     bool calc_fee = true;
      29                 :             : 
      30                 :           0 :     CAmount in_amt = 0;
      31                 :             : 
      32   [ #  #  #  # ]:           0 :     result.inputs.resize(psbtx.inputs.size());
      33                 :             : 
      34                 :             :     // PrecomputePSBTData calls GetUnsignedTx() which we checked already works
      35         [ #  # ]:           0 :     const PrecomputedTransactionData txdata = *PrecomputePSBTData(psbtx);
      36                 :             : 
      37   [ #  #  #  # ]:           0 :     for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
      38                 :           0 :         PSBTInput& input = psbtx.inputs[i];
      39                 :           0 :         PSBTInputAnalysis& input_analysis = result.inputs[i];
      40                 :             : 
      41                 :             :         // We set next role here and ratchet backwards as required
      42                 :           0 :         input_analysis.next = PSBTRole::EXTRACTOR;
      43                 :             : 
      44                 :             :         // Check for a UTXO
      45                 :           0 :         CTxOut utxo;
      46   [ #  #  #  # ]:           0 :         if (input.GetUTXO(utxo)) {
      47   [ #  #  #  # ]:           0 :             if (!MoneyRange(utxo.nValue) || !MoneyRange(in_amt + utxo.nValue)) {
      48   [ #  #  #  # ]:           0 :                 result.SetInvalid(strprintf("PSBT is not valid. Input %u has invalid value", i));
      49                 :           0 :                 return result;
      50                 :             :             }
      51                 :           0 :             in_amt += utxo.nValue;
      52                 :           0 :             input_analysis.has_utxo = true;
      53                 :             :         } else {
      54   [ #  #  #  #  :           0 :             if (input.non_witness_utxo && input.prev_out >= input.non_witness_utxo->vout.size()) {
                   #  # ]
      55   [ #  #  #  # ]:           0 :                 result.SetInvalid(strprintf("PSBT is not valid. Input %u specifies invalid prevout", i));
      56                 :           0 :                 return result;
      57                 :             :             }
      58                 :           0 :             input_analysis.has_utxo = false;
      59                 :           0 :             input_analysis.is_final = false;
      60                 :           0 :             input_analysis.next = PSBTRole::UPDATER;
      61                 :           0 :             calc_fee = false;
      62                 :             :         }
      63                 :             : 
      64   [ #  #  #  # ]:           0 :         if (!utxo.IsNull() && utxo.scriptPubKey.IsUnspendable()) {
      65   [ #  #  #  # ]:           0 :             result.SetInvalid(strprintf("PSBT is not valid. Input %u spends unspendable output", i));
      66                 :           0 :             return result;
      67                 :             :         }
      68                 :             : 
      69                 :             :         // Check if it is final
      70   [ #  #  #  # ]:           0 :         if (!PSBTInputSignedAndVerified(psbtx, i, &txdata)) {
      71                 :           0 :             input_analysis.is_final = false;
      72                 :             : 
      73                 :             :             // Figure out what is missing
      74                 :           0 :             SignatureData outdata;
      75         [ #  # ]:           0 :             bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, /*options=*/{}, &outdata) == PSBTError::OK;
      76                 :             : 
      77                 :             :             // Things are missing
      78         [ #  # ]:           0 :             if (!complete) {
      79         [ #  # ]:           0 :                 input_analysis.missing_pubkeys = outdata.missing_pubkeys;
      80                 :           0 :                 input_analysis.missing_redeem_script = outdata.missing_redeem_script;
      81                 :           0 :                 input_analysis.missing_witness_script = outdata.missing_witness_script;
      82         [ #  # ]:           0 :                 input_analysis.missing_sigs = outdata.missing_sigs;
      83                 :             : 
      84                 :             :                 // If we are only missing signatures and nothing else, then next is signer
      85   [ #  #  #  #  :           0 :                 if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
             #  #  #  # ]
      86                 :           0 :                     input_analysis.next = PSBTRole::SIGNER;
      87                 :             :                 } else {
      88                 :           0 :                     input_analysis.next = PSBTRole::UPDATER;
      89                 :             :                 }
      90                 :             :             } else {
      91                 :           0 :                 input_analysis.next = PSBTRole::FINALIZER;
      92                 :             :             }
      93         [ #  # ]:           0 :         } else if (!utxo.IsNull()){
      94                 :           0 :             input_analysis.is_final = true;
      95                 :             :         }
      96                 :           0 :     }
      97                 :             : 
      98                 :             :     // Calculate next role for PSBT by grabbing "minimum" PSBTInput next role
      99                 :           0 :     result.next = PSBTRole::EXTRACTOR;
     100   [ #  #  #  # ]:           0 :     for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
     101         [ #  # ]:           0 :         PSBTInputAnalysis& input_analysis = result.inputs[i];
     102         [ #  # ]:           0 :         result.next = std::min(result.next, input_analysis.next);
     103                 :             :     }
     104         [ #  # ]:           0 :     assert(result.next > PSBTRole::CREATOR);
     105                 :             : 
     106         [ #  # ]:           0 :     if (calc_fee) {
     107                 :             :         // Get the output amount
     108                 :           0 :         CAmount out_amt = std::accumulate(psbtx.outputs.begin(), psbtx.outputs.end(), CAmount(0),
     109                 :           0 :             [](CAmount a, const PSBTOutput& b) {
     110   [ #  #  #  #  :           0 :                 if (!MoneyRange(a) || !MoneyRange(b.amount) || !MoneyRange(a + b.amount)) {
                   #  # ]
     111                 :           0 :                     return CAmount(-1);
     112                 :             :                 }
     113                 :             :                 return a += b.amount;
     114                 :             :             }
     115                 :           0 :         );
     116         [ #  # ]:           0 :         if (!MoneyRange(out_amt)) {
     117   [ #  #  #  # ]:           0 :             result.SetInvalid("PSBT is not valid. Output amount invalid");
     118                 :           0 :             return result;
     119                 :             :         }
     120                 :             : 
     121                 :             :         // Get the fee
     122                 :           0 :         CAmount fee = in_amt - out_amt;
     123         [ #  # ]:           0 :         result.fee = fee;
     124                 :             : 
     125                 :             :         // Estimate the size
     126         [ #  # ]:           0 :         CCoinsViewCache view{&CoinsViewEmpty::Get()};
     127                 :           0 :         bool success = true;
     128                 :             : 
     129   [ #  #  #  # ]:           0 :         for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
     130                 :           0 :             PSBTInput& input = psbtx.inputs[i];
     131                 :           0 :             Coin newcoin;
     132                 :             : 
     133   [ #  #  #  #  :           0 :             if (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, /*options=*/{}) != PSBTError::OK || !input.GetUTXO(newcoin.out)) {
             #  #  #  # ]
     134                 :           0 :                 success = false;
     135                 :           0 :                 break;
     136                 :             :             } else {
     137                 :           0 :                 mtx.vin[i].scriptSig = input.final_script_sig;
     138         [ #  # ]:           0 :                 mtx.vin[i].scriptWitness = input.final_script_witness;
     139                 :           0 :                 newcoin.nHeight = 1;
     140   [ #  #  #  # ]:           0 :                 view.AddCoin(input.GetOutPoint(), std::move(newcoin), true);
     141                 :             :             }
     142                 :           0 :         }
     143                 :             : 
     144                 :           0 :         if (success) {
     145         [ #  # ]:           0 :             CTransaction ctx = CTransaction(mtx);
     146   [ #  #  #  # ]:           0 :             size_t size(GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS), ::nBytesPerSigOp));
     147         [ #  # ]:           0 :             result.estimated_vsize = size;
     148                 :             :             // Estimate fee rate
     149         [ #  # ]:           0 :             CFeeRate feerate(fee, size);
     150         [ #  # ]:           0 :             result.estimated_feerate = feerate;
     151                 :           0 :         }
     152                 :             : 
     153                 :           0 :     }
     154                 :             : 
     155                 :             :     return result;
     156                 :           0 : }
     157                 :             : } // namespace node
        

Generated by: LCOV version 2.0-1