Inside Bitcoin
Opening the selected file…
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.
251std::vector<CRecipient> recipients;252CAmount new_outputs_value = 0;253const auto& txouts = outputs.empty() ? tx->vout : outputs;254for (size_t i = 0; i < txouts.size(); ++i) {255const CTxOut& output = txouts.at(i);256CTxDestination dest;257ExtractDestination(output.scriptPubKey, dest);258if (original_change_index.has_value() ? original_change_index.value() == i : OutputIsChange(wallet, output)) {259new_coin_control.destChange = dest;260} else {261CRecipient recipient = {dest, output.nValue, false};262recipients.push_back(recipient);263}264new_outputs_value += output.nValue;265}267// If no recipients, means that we are sending coins to a change address268if (recipients.empty()) {269// Just as a sanity check, ensure that the change address exist270if (std::get_if<CNoDestination>(&new_coin_control.destChange)) {271errors.emplace_back(Untranslated("Unable to create transaction. Transaction must have at least one recipient"));272return Result::INVALID_PARAMETER;273}275// Add change as recipient with SFFO flag enabled, so fees are deduced from it.276// If the output differs from the original tx output (because the user customized it) a new change output will be created.277recipients.emplace_back(CRecipient{new_coin_control.destChange, new_outputs_value, /*fSubtractFeeFromAmount=*/true});278new_coin_control.destChange = CNoDestination();279}281if (coin_control.m_feerate) {282// The user provided a feeRate argument.283// We calculate this here to avoid compiler warning on the cs_wallet lock284// We need to make a temporary transaction with no input witnesses as the dummy signer expects them to be empty for external inputs285CMutableTransaction temp_mtx{*tx};286for (auto& txin : temp_mtx.vin) {287txin.scriptSig.clear();288txin.scriptWitness.SetNull();289}290temp_mtx.vout = txouts;291const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(temp_mtx), &wallet, &new_coin_control).vsize};292Result res = CheckFeeRate(wallet, temp_mtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);293if (res != Result::OK) {294return res;295}296} else {297// The user did not provide a feeRate argument298new_coin_control.m_feerate = EstimateFeeRate(wallet, wtx, old_fee, new_coin_control);299}301// Fill in required inputs we are double-spending(all of them)302// N.B.: bip125 doesn't require all the inputs in the replaced transaction to be303// used in the replacement transaction, but it's very important for wallets to make304// sure that happens. If not, it would be possible to bump a transaction A twice to305// A2 and A3 where A2 and A3 don't conflict (or alternatively bump A to A2 and A2306// to A3 where A and A3 don't conflict). If both later get confirmed then the sender307// has accidentally double paid.308for (const auto& inputs : tx->vin) {309new_coin_control.Select(COutPoint(inputs.prevout));310}311new_coin_control.m_allow_other_inputs = true;313// We cannot source new unconfirmed inputs(bip125 rule 2)314new_coin_control.m_min_depth = 1;316auto res = CreateTransaction(wallet, recipients, /*change_pos=*/std::nullopt, new_coin_control, false);317if (!res) {318errors.emplace_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + util::ErrorString(res));319return Result::WALLET_ERROR;320}322const auto& txr = *res;323// Write back new fee if successful324new_fee = txr.fee;326// Write back transaction327mtx = CMutableTransaction(*txr.tx);329return Result::OK;330}332bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {333LOCK(wallet.cs_wallet);335if (wallet.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {336// Make a blank psbt337PartiallySignedTransaction psbtx(mtx);339// First fill transaction with our data without signing,340// so external signers are not asked to sign more than once.341bool complete;342wallet.FillPSBT(psbtx, {.sign = false, .bip32_derivs = true}, complete);343auto err{wallet.FillPSBT(psbtx, {.sign = true, .bip32_derivs = false}, complete)};344if (err) return false;345complete = FinalizeAndExtractPSBT(psbtx, mtx);346return complete;347} else {348return wallet.SignTransaction(mtx);349}350}352Result CommitTransaction(CWallet& wallet, const Txid& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, Txid& bumped_txid)353{354LOCK(wallet.cs_wallet);355if (!errors.empty()) {356return Result::MISC_ERROR;357}358auto it = txid.IsNull() ? wallet.mapWallet.end() : wallet.mapWallet.find(txid);359if (it == wallet.mapWallet.end()) {360errors.emplace_back(Untranslated("Invalid or non-wallet transaction id"));361return Result::MISC_ERROR;362}363const CWalletTx& oldWtx = it->second;365// make sure the transaction still has no descendants and hasn't been mined in the meantime366Result result = PreconditionChecks(wallet, oldWtx, /* require_mine=*/ false, errors);367if (result != Result::OK) {368return result;369}371// commit/broadcast the tx372CTransactionRef tx = MakeTransactionRef(std::move(mtx));373wallet.CommitTransaction(tx, oldWtx.GetHash(), oldWtx.m_comment, oldWtx.m_comment_to, oldWtx.m_messages, oldWtx.m_payment_requests);375// mark the original tx as bumped376bumped_txid = tx->GetHash();377if (!wallet.MarkReplaced(oldWtx.GetHash(), bumped_txid)) {378errors.emplace_back(Untranslated("Created new bumpfee transaction but could not mark the original transaction as replaced"));379}380return Result::OK;381}383} // namespace feebumper384} // namespace wallet