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.
251contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());252updateLabelLocked();253}255// copy label "Quantity" to clipboard256void CoinControlDialog::clipboardQuantity()257{258GUIUtil::setClipboard(ui->labelCoinControlQuantity->text());259}261// copy label "Amount" to clipboard262void CoinControlDialog::clipboardAmount()263{264GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));265}267// copy label "Fee" to clipboard268void CoinControlDialog::clipboardFee()269{270GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));271}273// copy label "After fee" to clipboard274void CoinControlDialog::clipboardAfterFee()275{276GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));277}279// copy label "Bytes" to clipboard280void CoinControlDialog::clipboardBytes()281{282GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));283}285// copy label "Change" to clipboard286void CoinControlDialog::clipboardChange()287{288GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, ""));289}291// treeview: sort292void CoinControlDialog::sortView(int column, Qt::SortOrder order)293{294sortColumn = column;295sortOrder = order;296ui->treeWidget->sortItems(column, order);297ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);298}300// treeview: clicked on header301void CoinControlDialog::headerSectionClicked(int logicalIndex)302{303if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing304{305ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);306}307else308{309if (sortColumn == logicalIndex)310sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);311else312{313sortColumn = logicalIndex;314sortOrder = ((sortColumn == COLUMN_LABEL || sortColumn == COLUMN_ADDRESS) ? Qt::AscendingOrder : Qt::DescendingOrder); // if label or address then default => asc, else default => desc315}317sortView(sortColumn, sortOrder);318}319}321// toggle tree mode322void CoinControlDialog::radioTreeMode(bool checked)323{324if (checked && model)325updateView();326}328// toggle list mode329void CoinControlDialog::radioListMode(bool checked)330{331if (checked && model)332updateView();333}335// checkbox clicked by user336void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)337{338if (column != COLUMN_CHECKBOX) return;339auto txid{Txid::FromHex(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString())};340if (txid) { // a valid txid means this is a child node, and not a parent node in tree mode341COutPoint outpt(*txid, item->data(COLUMN_ADDRESS, VOutRole).toUInt());343if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)344m_coin_control.UnSelect(outpt);345else if (item->isDisabled()) // locked (this happens if "check all" through parent node)346item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);347else348m_coin_control.Select(outpt);350// selection changed -> update labels351if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all352CoinControlDialog::updateLabels(m_coin_control, model, this);353}354}356// shows count of locked unspent outputs357void CoinControlDialog::updateLabelLocked()358{359std::vector<COutPoint> vOutpts;360model->wallet().listLockedCoins(vOutpts);361if (vOutpts.size() > 0)362{363ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));364ui->labelLocked->setVisible(true);365}366else ui->labelLocked->setVisible(false);367}369void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *model, QDialog* dialog)370{371if (!model)372return;374// nPayAmount375CAmount nPayAmount = 0;376for (const CAmount &amount : CoinControlDialog::payAmounts) {377nPayAmount += amount;378}380CAmount nAmount = 0;381CAmount nPayFee = 0;382CAmount nAfterFee = 0;383CAmount nChange = 0;384unsigned int nBytes = 0;385unsigned int nBytesInputs = 0;386unsigned int nQuantity = 0;387bool fWitness = false;389auto vCoinControl{m_coin_control.ListSelected()};391size_t i = 0;392for (const auto& out : model->wallet().getCoins(vCoinControl)) {393if (out.depth_in_main_chain < 0) continue;395// unselect already spent, very unlikely scenario, this could happen396// when selected are spent elsewhere, like rpc or another computer397const COutPoint& outpt = vCoinControl[i++];398if (out.is_spent)399{400m_coin_control.UnSelect(outpt);401continue;402}404// Quantity405nQuantity++;407// Amount408nAmount += out.txout.nValue;410// Bytes411CTxDestination address;412int witnessversion = 0;413std::vector<unsigned char> witnessprogram;414if (out.txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram))415{416// add input skeleton bytes (outpoint, scriptSig size, nSequence)417nBytesInputs += (32 + 4 + 1 + 4);419if (witnessversion == 0) { // P2WPKH420// 1 WU (witness item count) + 72 WU (ECDSA signature with len byte) + 34 WU (pubkey with len byte)421nBytesInputs += 107 / WITNESS_SCALE_FACTOR;422} else if (witnessversion == 1) { // P2TR key-path spend423// 1 WU (witness item count) + 65 WU (Schnorr signature with len byte)424nBytesInputs += 66 / WITNESS_SCALE_FACTOR;425} else {426// not supported, should be unreachable427throw std::runtime_error("Trying to spend future segwit version script");428}429fWitness = true;430}431else if(ExtractDestination(out.txout.scriptPubKey, address))432{433CPubKey pubkey;434PKHash* pkhash = std::get_if<PKHash>(&address);435if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, ToKeyID(*pkhash), pubkey))436{437nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);438}439else440nBytesInputs += 148; // in all error cases, simply assume 148 here441}442else nBytesInputs += 148;443}445// calculation446if (nQuantity > 0)447{448// Bytes449nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here450if (fWitness)451{452// there is some fudging in these numbers related to the actual virtual transaction size calculation that will keep this estimate from being exact.453// usually, the result will be an overestimate within a couple of satoshis so that the confirmation dialog ends up displaying a slightly smaller fee.454// also, the witness stack size value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit.455nBytes += 2; // account for the serialized marker and flag bytes456nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.457}459// in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate460if (CoinControlDialog::fSubtractFeeFromAmount)461if (nAmount - nPayAmount == 0)462nBytes -= 34;464// Fee465nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, /*returned_target=*/nullptr, /*reason=*/nullptr);467if (nPayAmount > 0)468{469nChange = nAmount - nPayAmount;470if (!CoinControlDialog::fSubtractFeeFromAmount)471nChange -= nPayFee;473if (nChange > 0) {474// Assumes a p2pkh script size475CTxOut txout(nChange, CScript() << std::vector<unsigned char>(24, 0));476// Never create dust outputs; if we would, just add the dust to the fee.477if (IsDust(txout, model->node().getDustRelayFee()))478{479nPayFee += nChange;480nChange = 0;481if (CoinControlDialog::fSubtractFeeFromAmount)482nBytes -= 34; // we didn't detect lack of change above483}484}486if (nChange == 0 && !CoinControlDialog::fSubtractFeeFromAmount)487nBytes -= 34;488}490// after fee491nAfterFee = std::max<CAmount>(nAmount - nPayFee, 0);492}494// actually update labels495BitcoinUnit nDisplayUnit = BitcoinUnit::BTC;496if (model && model->getOptionsModel())497nDisplayUnit = model->getOptionsModel()->getDisplayUnit();499QLabel *l1 = dialog->findChild<QLabel *>("labelCoinControlQuantity");500QLabel *l2 = dialog->findChild<QLabel *>("labelCoinControlAmount");
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.