Skip to content

Commit fbf385c

Browse files
committed
[Qt] simple fee bumper with user verification
1 parent 7f2b9e0 commit fbf385c

File tree

6 files changed

+98
-4
lines changed

6 files changed

+98
-4
lines changed

src/qt/sendcoinsdialog.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
#include <QTextDocument>
3232
#include <QTimer>
3333

34-
#define SEND_CONFIRM_DELAY 3
35-
3634
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
3735
QDialog(parent),
3836
ui(new Ui::SendCoinsDialog),

src/qt/sendcoinsdialog.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ private Q_SLOTS:
100100
};
101101

102102

103+
#define SEND_CONFIRM_DELAY 3
103104

104105
class SendConfirmationDialog : public QMessageBox
105106
{
106107
Q_OBJECT
107108

108109
public:
109-
SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
110+
SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = 0);
110111
int exec();
111112

112113
private Q_SLOTS:

src/qt/transactionview.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "guiutil.h"
1212
#include "optionsmodel.h"
1313
#include "platformstyle.h"
14+
#include "sendcoinsdialog.h"
1415
#include "transactiondescdialog.h"
1516
#include "transactionfilterproxy.h"
1617
#include "transactionrecord.h"
@@ -37,7 +38,7 @@
3738

3839
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
3940
QWidget(parent), model(0), transactionProxyModel(0),
40-
transactionView(0), abandonAction(0), columnResizingFixer(0)
41+
transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0)
4142
{
4243
// Build filter row
4344
setContentsMargins(0,0,0,0);
@@ -138,6 +139,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
138139

139140
// Actions
140141
abandonAction = new QAction(tr("Abandon transaction"), this);
142+
bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
141143
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
142144
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
143145
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
@@ -156,6 +158,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
156158
contextMenu->addAction(copyTxPlainText);
157159
contextMenu->addAction(showDetailsAction);
158160
contextMenu->addSeparator();
161+
contextMenu->addAction(bumpFeeAction);
159162
contextMenu->addAction(abandonAction);
160163
contextMenu->addAction(editLabelAction);
161164

@@ -173,6 +176,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
173176
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
174177
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
175178

179+
connect(bumpFeeAction, SIGNAL(triggered()), this, SLOT(bumpFee()));
176180
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
177181
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
178182
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
@@ -372,6 +376,7 @@ void TransactionView::contextualMenu(const QPoint &point)
372376
uint256 hash;
373377
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
374378
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
379+
bumpFeeAction->setEnabled(model->transactionSignalsRBF(hash));
375380

376381
if(index.isValid())
377382
{
@@ -397,6 +402,21 @@ void TransactionView::abandonTx()
397402
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
398403
}
399404

405+
void TransactionView::bumpFee()
406+
{
407+
if(!transactionView || !transactionView->selectionModel())
408+
return;
409+
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
410+
411+
// get the hash from the TxHashRole (QVariant / QString)
412+
uint256 hash;
413+
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
414+
hash.SetHex(hashQStr.toStdString());
415+
416+
// Bump tx fee over the walletModel
417+
model->bumpFee(hash);
418+
}
419+
400420
void TransactionView::copyAddress()
401421
{
402422
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);

src/qt/transactionview.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class TransactionView : public QWidget
7676
QDateTimeEdit *dateFrom;
7777
QDateTimeEdit *dateTo;
7878
QAction *abandonAction;
79+
QAction *bumpFeeAction;
7980

8081
QWidget *createDateRangeWidget();
8182

@@ -99,6 +100,7 @@ private Q_SLOTS:
99100
void openThirdPartyTxUrl(QString url);
100101
void updateWatchOnlyColumn(bool fHaveWatchOnly);
101102
void abandonTx();
103+
void bumpFee();
102104

103105
Q_SIGNALS:
104106
void doubleClicked(const QModelIndex&);

src/qt/walletmodel.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,29 @@
88
#include "consensus/validation.h"
99
#include "guiconstants.h"
1010
#include "guiutil.h"
11+
#include "optionsmodel.h"
1112
#include "paymentserver.h"
1213
#include "recentrequeststablemodel.h"
14+
#include "sendcoinsdialog.h"
1315
#include "transactiontablemodel.h"
1416

1517
#include "base58.h"
1618
#include "chain.h"
1719
#include "keystore.h"
1820
#include "validation.h"
1921
#include "net.h" // for g_connman
22+
#include "policy/rbf.h"
2023
#include "sync.h"
2124
#include "ui_interface.h"
2225
#include "util.h" // for GetBoolArg
26+
#include "wallet/feebumper.h"
2327
#include "wallet/wallet.h"
2428
#include "wallet/walletdb.h" // for BackupWallet
2529

2630
#include <stdint.h>
2731

2832
#include <QDebug>
33+
#include <QMessageBox>
2934
#include <QSet>
3035
#include <QTimer>
3136

@@ -693,6 +698,71 @@ bool WalletModel::abandonTransaction(uint256 hash) const
693698
return wallet->AbandonTransaction(hash);
694699
}
695700

701+
bool WalletModel::transactionSignalsRBF(uint256 hash) const
702+
{
703+
LOCK2(cs_main, wallet->cs_wallet);
704+
const CWalletTx *wtx = wallet->GetWalletTx(hash);
705+
if (wtx && SignalsOptInRBF(*wtx))
706+
return true;
707+
return false;
708+
}
709+
710+
bool WalletModel::bumpFee(uint256 hash)
711+
{
712+
std::unique_ptr<CFeeBumper> feeBump;
713+
{
714+
LOCK2(cs_main, wallet->cs_wallet);
715+
feeBump.reset(new CFeeBumper(wallet, hash, 0, false, 0, true));
716+
}
717+
if (feeBump->getResult() != BumpFeeResult::OK)
718+
{
719+
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
720+
(feeBump->getErrors().size() ? QString::fromStdString(feeBump->getErrors()[0]) : "") +")");
721+
return false;
722+
}
723+
724+
// allow a user based fee verification
725+
QString questionString = tr("Do you want to increase the fee from %1 to %2").arg(
726+
BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), feeBump->getOldFee()),
727+
BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), feeBump->getNewFee()));
728+
SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
729+
confirmationDialog.exec();
730+
QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
731+
732+
// cancel sign&broadcast if users doesn't want to bump the fee
733+
if (retval != QMessageBox::Yes) {
734+
return false;
735+
}
736+
737+
WalletModel::UnlockContext ctx(requestUnlock());
738+
if(!ctx.isValid())
739+
{
740+
return false;
741+
}
742+
743+
// sign bumped transaction
744+
bool res = false;
745+
{
746+
LOCK2(cs_main, wallet->cs_wallet);
747+
res = feeBump->signTransaction(wallet);
748+
}
749+
if (!res) {
750+
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
751+
return false;
752+
}
753+
// commit the bumped transaction
754+
{
755+
LOCK2(cs_main, wallet->cs_wallet);
756+
res = feeBump->commit(wallet);
757+
}
758+
if(!res) {
759+
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
760+
QString::fromStdString(feeBump->getErrors()[0])+")");
761+
return false;
762+
}
763+
return true;
764+
}
765+
696766
bool WalletModel::isWalletEnabled()
697767
{
698768
return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);

src/qt/walletmodel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ class WalletModel : public QObject
207207
bool transactionCanBeAbandoned(uint256 hash) const;
208208
bool abandonTransaction(uint256 hash) const;
209209

210+
bool transactionSignalsRBF(uint256 hash) const;
211+
bool bumpFee(uint256 hash);
212+
210213
static bool isWalletEnabled();
211214

212215
bool hdEnabled() const;

0 commit comments

Comments
 (0)