psbt.cpp raw

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