aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schnelli <dev@jonasschnelli.ch>2017-02-03 22:04:39 +0100
committerJonas Schnelli <dev@jonasschnelli.ch>2017-05-11 15:27:04 +0200
commitfbf385cc830df2aec7cdcbab0c2b09b46569e8c1 (patch)
tree82d308f1ac0bc8eddb4dbbf07da2ff3b971f8d25
parent7f2b9e0868f5759187e63df4f2cbd5f4fc9c81d7 (diff)
[Qt] simple fee bumper with user verification
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/transactionview.cpp22
-rw-r--r--src/qt/transactionview.h2
-rw-r--r--src/qt/walletmodel.cpp70
-rw-r--r--src/qt/walletmodel.h3
6 files changed, 98 insertions, 4 deletions
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 098cda6d32..8dcb0fd016 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -31,8 +31,6 @@
#include <QTextDocument>
#include <QTimer>
-#define SEND_CONFIRM_DELAY 3
-
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index a402edc961..a932f129be 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -100,13 +100,14 @@ Q_SIGNALS:
};
+#define SEND_CONFIRM_DELAY 3
class SendConfirmationDialog : public QMessageBox
{
Q_OBJECT
public:
- SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
+ SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = 0);
int exec();
private Q_SLOTS:
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 30f4db9450..af48f13c24 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -11,6 +11,7 @@
#include "guiutil.h"
#include "optionsmodel.h"
#include "platformstyle.h"
+#include "sendcoinsdialog.h"
#include "transactiondescdialog.h"
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
@@ -37,7 +38,7 @@
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
- transactionView(0), abandonAction(0), columnResizingFixer(0)
+ transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0)
{
// Build filter row
setContentsMargins(0,0,0,0);
@@ -138,6 +139,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
// Actions
abandonAction = new QAction(tr("Abandon transaction"), this);
+ bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
@@ -156,6 +158,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
contextMenu->addAction(copyTxPlainText);
contextMenu->addAction(showDetailsAction);
contextMenu->addSeparator();
+ contextMenu->addAction(bumpFeeAction);
contextMenu->addAction(abandonAction);
contextMenu->addAction(editLabelAction);
@@ -173,6 +176,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
+ connect(bumpFeeAction, SIGNAL(triggered()), this, SLOT(bumpFee()));
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
@@ -372,6 +376,7 @@ void TransactionView::contextualMenu(const QPoint &point)
uint256 hash;
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
+ bumpFeeAction->setEnabled(model->transactionSignalsRBF(hash));
if(index.isValid())
{
@@ -397,6 +402,21 @@ void TransactionView::abandonTx()
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
}
+void TransactionView::bumpFee()
+{
+ if(!transactionView || !transactionView->selectionModel())
+ return;
+ QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
+
+ // get the hash from the TxHashRole (QVariant / QString)
+ uint256 hash;
+ QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
+ hash.SetHex(hashQStr.toStdString());
+
+ // Bump tx fee over the walletModel
+ model->bumpFee(hash);
+}
+
void TransactionView::copyAddress()
{
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 595701cdd9..52e57cae4c 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -76,6 +76,7 @@ private:
QDateTimeEdit *dateFrom;
QDateTimeEdit *dateTo;
QAction *abandonAction;
+ QAction *bumpFeeAction;
QWidget *createDateRangeWidget();
@@ -99,6 +100,7 @@ private Q_SLOTS:
void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
void abandonTx();
+ void bumpFee();
Q_SIGNALS:
void doubleClicked(const QModelIndex&);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index a2a9271904..bcf8d5cab3 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -8,8 +8,10 @@
#include "consensus/validation.h"
#include "guiconstants.h"
#include "guiutil.h"
+#include "optionsmodel.h"
#include "paymentserver.h"
#include "recentrequeststablemodel.h"
+#include "sendcoinsdialog.h"
#include "transactiontablemodel.h"
#include "base58.h"
@@ -17,15 +19,18 @@
#include "keystore.h"
#include "validation.h"
#include "net.h" // for g_connman
+#include "policy/rbf.h"
#include "sync.h"
#include "ui_interface.h"
#include "util.h" // for GetBoolArg
+#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h" // for BackupWallet
#include <stdint.h>
#include <QDebug>
+#include <QMessageBox>
#include <QSet>
#include <QTimer>
@@ -693,6 +698,71 @@ bool WalletModel::abandonTransaction(uint256 hash) const
return wallet->AbandonTransaction(hash);
}
+bool WalletModel::transactionSignalsRBF(uint256 hash) const
+{
+ LOCK2(cs_main, wallet->cs_wallet);
+ const CWalletTx *wtx = wallet->GetWalletTx(hash);
+ if (wtx && SignalsOptInRBF(*wtx))
+ return true;
+ return false;
+}
+
+bool WalletModel::bumpFee(uint256 hash)
+{
+ std::unique_ptr<CFeeBumper> feeBump;
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ feeBump.reset(new CFeeBumper(wallet, hash, 0, false, 0, true));
+ }
+ if (feeBump->getResult() != BumpFeeResult::OK)
+ {
+ QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
+ (feeBump->getErrors().size() ? QString::fromStdString(feeBump->getErrors()[0]) : "") +")");
+ return false;
+ }
+
+ // allow a user based fee verification
+ QString questionString = tr("Do you want to increase the fee from %1 to %2").arg(
+ BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), feeBump->getOldFee()),
+ BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), feeBump->getNewFee()));
+ SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
+ confirmationDialog.exec();
+ QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
+
+ // cancel sign&broadcast if users doesn't want to bump the fee
+ if (retval != QMessageBox::Yes) {
+ return false;
+ }
+
+ WalletModel::UnlockContext ctx(requestUnlock());
+ if(!ctx.isValid())
+ {
+ return false;
+ }
+
+ // sign bumped transaction
+ bool res = false;
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ res = feeBump->signTransaction(wallet);
+ }
+ if (!res) {
+ QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
+ return false;
+ }
+ // commit the bumped transaction
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ res = feeBump->commit(wallet);
+ }
+ if(!res) {
+ QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
+ QString::fromStdString(feeBump->getErrors()[0])+")");
+ return false;
+ }
+ return true;
+}
+
bool WalletModel::isWalletEnabled()
{
return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 78e45dc369..df5acaf684 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -207,6 +207,9 @@ public:
bool transactionCanBeAbandoned(uint256 hash) const;
bool abandonTransaction(uint256 hash) const;
+ bool transactionSignalsRBF(uint256 hash) const;
+ bool bumpFee(uint256 hash);
+
static bool isWalletEnabled();
bool hdEnabled() const;