Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 6: [PATCH 06/17] feat(wallet): preserve Roots signing and spend controls on v31

src/qt/sendcoinsdialog.cpp

Before: src/qt/sendcoinsdialog.cpp · After: src/qt/sendcoinsdialog.cpp

File metadata
index 50b0c4cf74f2ea8e3b533d8561a4fb9ce69e75bb..3da3b377ed3244bfe83367f474e2d510742f40e9 100644

Download original patch · Release notes

Diff rows 1–128 of 128. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/qt/sendcoinsdialog.cpp CHANGED
@@ -23,6 +23,7 @@
23
  #include <node/types.h>
24
  #include <policy/fees/block_policy_estimator.h>
25
  #include <txmempool.h>
 
26
  #include <validation.h>
27
  #include <wallet/coincontrol.h>
28
  #include <wallet/fees.h>
@@ -160,6 +161,8 @@ void SendCoinsDialog::setModel(WalletModel *_model)
160
  }
161
 
162
  connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance);
 
 
163
  connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::refreshBalance);
164
  refreshBalance();
165
 
@@ -197,7 +200,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
197
  updateSmartFeeLabel();
198
 
199
  // set default rbf checkbox state
200
- ui->optInRBF->setCheckState(Qt::Checked);
201
 
202
  if (model->wallet().hasExternalSigner()) {
203
  //: "device" usually means a hardware wallet.
@@ -361,16 +364,20 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
361
  question_string.append("<span style='color:#aa0000; font-weight:bold;'>");
362
  question_string.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
363
  question_string.append("</span><br />");
 
364
 
365
- // append RBF message according to transaction's signalling
366
- question_string.append("<span style='font-size:10pt; font-weight:normal;'>");
367
- if (ui->optInRBF->isChecked()) {
368
- question_string.append(tr("You can increase the fee later (signals Replace-By-Fee, BIP-125)."));
369
- } else {
370
- question_string.append(tr("Not signalling Replace-By-Fee, BIP-125."));
371
- }
372
- question_string.append("</span>");
 
 
373
  }
 
374
 
375
  // add total amount in all subdivision units
376
  question_string.append("<hr />");
@@ -475,6 +482,45 @@ bool SendCoinsDialog::signWithExternalSigner(PartiallySignedTransaction& psbtx,
475
  return true;
476
  }
477
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
479
  {
480
  if(!model || !model->getOptionsModel())
@@ -497,6 +543,11 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
497
  fNewRecipientAllowed = true;
498
  return;
499
  }
 
 
 
 
 
500
 
501
  bool send_failure = false;
502
  if (retval == QMessageBox::Save) {
@@ -543,9 +594,18 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
543
  // Broadcast the transaction, unless an external signer was used and it
544
  // failed, or more signatures are needed.
545
  if (broadcast) {
546
- // now send the prepared transaction
547
- model->sendCoins(*m_current_transaction);
548
- Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash());
 
 
 
 
 
 
 
 
 
549
  }
550
  }
551
  if (!send_failure) {
 
23
  #include <node/types.h>
24
  #include <policy/fees/block_policy_estimator.h>
25
  #include <txmempool.h>
26
+ #include <util/rbf.h>
27
  #include <validation.h>
28
  #include <wallet/coincontrol.h>
29
  #include <wallet/fees.h>
 
161
  }
162
 
163
  connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance);
164
+ connect(_model, &WalletModel::walletStateChanged, this, &SendCoinsDialog::walletChanged);
165
+ connect(_model, &WalletModel::unload, this, &SendCoinsDialog::reject);
166
  connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::refreshBalance);
167
  refreshBalance();
168
 
 
200
  updateSmartFeeLabel();
201
 
202
  // set default rbf checkbox state
203
+ ui->optInRBF->setChecked(model->wallet().getDefaultRbf());
204
 
205
  if (model->wallet().hasExternalSigner()) {
206
  //: "device" usually means a hardware wallet.
 
364
  question_string.append("<span style='color:#aa0000; font-weight:bold;'>");
365
  question_string.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
366
  question_string.append("</span><br />");
367
+ }
368
 
369
+ appendCoinControlSummary(question_string);
370
+
371
+ // Show the signaling in the prepared transaction, rather than the
372
+ // requested value, so the confirmation states the effective result even
373
+ // when no fee is required.
374
+ question_string.append("<span style='font-size:10pt; font-weight:normal;'>");
375
+ if (SignalsOptInRBF(*m_current_transaction->getWtx())) {
376
+ question_string.append(tr("This transaction signals Replace-By-Fee (BIP-125). Replacement acceptance depends on network policy."));
377
+ } else {
378
+ question_string.append(tr("Not signalling Replace-By-Fee, BIP-125."));
379
  }
380
+ question_string.append("</span>");
381
 
382
  // add total amount in all subdivision units
383
  question_string.append("<hr />");
 
482
  return true;
483
  }
484
 
485
+ void SendCoinsDialog::appendCoinControlSummary(QString& text) const
486
+ {
487
+ if (!m_current_transaction || !m_current_transaction->getWtx()) return;
488
+
489
+ const CTransaction& tx{*m_current_transaction->getWtx()};
490
+ std::vector<COutPoint> outpoints;
491
+ outpoints.reserve(tx.vin.size());
492
+ for (const CTxIn& input : tx.vin) outpoints.push_back(input.prevout);
493
+
494
+ CAmount input_amount{0};
495
+ for (const auto& coin : model->wallet().getCoins(outpoints)) input_amount += coin.txout.nValue;
496
+ const CAmount fee{m_current_transaction->getTransactionFee()};
497
+ const CAmount change{input_amount - m_current_transaction->getTotalTransactionAmount() - fee};
498
+ const BitcoinUnit unit{model->getOptionsModel()->getDisplayUnit()};
499
+
500
+ text.append("<hr /><b>" + tr("Effective coin control") + "</b><br />");
501
+ text.append(tr("Inputs: %1 (%2)")
502
+ .arg(tx.vin.size())
503
+ .arg(BitcoinUnits::formatHtmlWithUnit(unit, input_amount)) + "<br />");
504
+ text.append(tr("Estimated virtual size: %1 vB").arg(m_current_transaction->getTransactionSize()) + "<br />");
505
+ const unsigned int vsize{m_current_transaction->getTransactionSize()};
506
+ text.append(tr("Fee rate: %1 sat/vB")
507
+ .arg(QString::number(vsize > 0 ? static_cast<double>(fee) / vsize : 0, 'f', 1)) + "<br />");
508
+ text.append(tr("Change: %1").arg(BitcoinUnits::formatHtmlWithUnit(unit, std::max<CAmount>(change, 0))) + "<br />");
509
+ }
510
+
511
+ void SendCoinsDialog::invalidateSendPreview()
512
+ {
513
+ if (m_sending) return;
514
+ m_current_transaction.reset();
515
+ m_coin_control->UnSelectAll();
516
+ coinControlUpdateLabels();
517
+ }
518
+
519
+ void SendCoinsDialog::walletChanged()
520
+ {
521
+ invalidateSendPreview();
522
+ }
523
+
524
  void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
525
  {
526
  if(!model || !model->getOptionsModel())
 
543
  fNewRecipientAllowed = true;
544
  return;
545
  }
546
+ if (!m_current_transaction) {
547
+ Q_EMIT message(tr("Send Coins"), tr("Wallet state changed. Review the current inputs and create a new preview."), CClientUIInterface::MSG_WARNING);
548
+ fNewRecipientAllowed = true;
549
+ return;
550
+ }
551
 
552
  bool send_failure = false;
553
  if (retval == QMessageBox::Save) {
 
594
  // Broadcast the transaction, unless an external signer was used and it
595
  // failed, or more signatures are needed.
596
  if (broadcast) {
597
+ // Keep the prepared choice valid through the synchronous commit.
598
+ // Wallet balance notifications from the successful commit must not
599
+ // invalidate its own transaction before it is announced.
600
+ m_sending = true;
601
+ try {
602
+ model->sendCoins(*m_current_transaction);
603
+ Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash());
604
+ } catch (const std::runtime_error& e) {
605
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(e.what()), CClientUIInterface::MSG_ERROR);
606
+ send_failure = true;
607
+ }
608
+ m_sending = false;
609
  }
610
  }
611
  if (!send_failure) {