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