Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.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>13#include <numeric>15namespace node {16PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)17{18// Go through each input and build status19PSBTAnalysis result;21std::optional<CMutableTransaction> unsigned_tx = psbtx.GetUnsignedTx();22if (!unsigned_tx) {23result.SetInvalid("PSBT cannot be made into a valid transaction");24return result;25}26CMutableTransaction& mtx = *unsigned_tx;28bool calc_fee = true;30CAmount in_amt = 0;32result.inputs.resize(psbtx.inputs.size());34// PrecomputePSBTData calls GetUnsignedTx() which we checked already works35const PrecomputedTransactionData txdata = *PrecomputePSBTData(psbtx);37for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {38PSBTInput& input = psbtx.inputs[i];39PSBTInputAnalysis& input_analysis = result.inputs[i];41// We set next role here and ratchet backwards as required42input_analysis.next = PSBTRole::EXTRACTOR;44// Check for a UTXO45CTxOut utxo;46if (input.GetUTXO(utxo)) {47if (!MoneyRange(utxo.nValue) || !MoneyRange(in_amt + utxo.nValue)) {48result.SetInvalid(strprintf("PSBT is not valid. Input %u has invalid value", i));49return result;50}51in_amt += utxo.nValue;52input_analysis.has_utxo = true;53} else {54if (input.non_witness_utxo && input.prev_out >= input.non_witness_utxo->vout.size()) {55result.SetInvalid(strprintf("PSBT is not valid. Input %u specifies invalid prevout", i));56return result;57}58input_analysis.has_utxo = false;59input_analysis.is_final = false;60input_analysis.next = PSBTRole::UPDATER;61calc_fee = false;62}64if (!utxo.IsNull() && utxo.scriptPubKey.IsUnspendable()) {65result.SetInvalid(strprintf("PSBT is not valid. Input %u spends unspendable output", i));66return result;67}69// Check if it is final70if (!PSBTInputSignedAndVerified(psbtx, i, &txdata)) {71input_analysis.is_final = false;73// Figure out what is missing74SignatureData outdata;75const auto sign_result = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, /*options*/{}, &outdata);76bool complete = sign_result.has_value();78// Things are missing79if (!complete) {80input_analysis.missing_pubkeys = outdata.missing_pubkeys;81input_analysis.missing_redeem_script = outdata.missing_redeem_script;82input_analysis.missing_witness_script = outdata.missing_witness_script;83input_analysis.missing_sigs = outdata.missing_sigs;85// If we are only missing signatures and nothing else, then next is signer86if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {87input_analysis.next = PSBTRole::SIGNER;88} else {89input_analysis.next = PSBTRole::UPDATER;90}91} else {92input_analysis.next = PSBTRole::FINALIZER;93}94} else if (!utxo.IsNull()){95input_analysis.is_final = true;96}97}99// Calculate next role for PSBT by grabbing "minimum" PSBTInput next role100result.next = PSBTRole::EXTRACTOR;101for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {102PSBTInputAnalysis& input_analysis = result.inputs[i];103result.next = std::min(result.next, input_analysis.next);104}105assert(result.next > PSBTRole::CREATOR);107if (calc_fee) {108// Get the output amount109CAmount out_amt = std::accumulate(psbtx.outputs.begin(), psbtx.outputs.end(), CAmount(0),110[](CAmount a, const PSBTOutput& b) {111if (!MoneyRange(a) || !MoneyRange(b.amount) || !MoneyRange(a + b.amount)) {112return CAmount(-1);113}114return a += b.amount;115}116);117if (!MoneyRange(out_amt)) {118result.SetInvalid("PSBT is not valid. Output amount invalid");119return result;120}122// Get the fee123CAmount fee = in_amt - out_amt;124result.fee = fee;126// Estimate the size127CCoinsViewCache view{&CoinsViewEmpty::Get()};128bool success = true;130for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {131PSBTInput& input = psbtx.inputs[i];132Coin newcoin;134const auto sign_result = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, /*options=*/{});135if (!sign_result.has_value() || !input.GetUTXO(newcoin.out)) {136success = false;137break;138} else {139mtx.vin[i].scriptSig = input.final_script_sig;140mtx.vin[i].scriptWitness = input.final_script_witness;141newcoin.nHeight = 1;142view.AddCoin(input.GetOutPoint(), std::move(newcoin), true);143}144}146if (success) {147CTransaction ctx = CTransaction(mtx);148size_t size(GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS), ::nBytesPerSigOp));149result.estimated_vsize = size;150// Estimate fee rate151CFeeRate feerate(fee, size);152result.estimated_feerate = feerate;153}155}157return result;158}159} // namespace node
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.