-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
qt: Add a dialog to select the change output when bumping fee
In order to correctly choose the change output when doing fee bumping in the GUI, we need to ask the user which output is change. We can make a guess using our ScriptIsChange heuristic, however the user may have chosen to have a custom change address or have otherwise labeled their change address which makes our change detection fail. By asking the user when fee bumping, we can avoid adding additional change outputs that are unnecessary.
- Loading branch information
Showing
7 changed files
with
268 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) 2022 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or https://www.opensource.org/licenses/mit-license.php. | ||
|
||
#if defined(HAVE_CONFIG_H) | ||
#include <config/bitcoin-config.h> | ||
#endif | ||
|
||
#include <qt/bumpfeechoosechangedialog.h> | ||
#include <qt/forms/ui_bumpfeechoosechangedialog.h> | ||
|
||
#include <addresstype.h> | ||
#include <key_io.h> | ||
#include <qt/bitcoinunits.h> | ||
#include <qt/guiutil.h> | ||
#include <qt/optionsmodel.h> | ||
#include <qt/walletmodel.h> | ||
|
||
#include <QHBoxLayout> | ||
#include <QLabel> | ||
#include <QRadioButton> | ||
#include <QVBoxLayout> | ||
|
||
BumpfeeChooseChangeDialog::BumpfeeChooseChangeDialog(WalletModel *model, QWidget *parent, const uint256& txid) : | ||
QDialog(parent, GUIUtil::dialog_flags), | ||
ui(new Ui::BumpfeeChooseChangeDialog), | ||
model(model) | ||
{ | ||
ui->setupUi(this); | ||
|
||
bool found_change = false; | ||
CTransactionRef tx = model->wallet().getTx(txid); | ||
for (size_t i = 0; i < tx->vout.size(); ++i) { | ||
const CTxOut& txout = tx->vout.at(i); | ||
QString address_info = tr("No address decoded"); | ||
CTxDestination dest; | ||
if (ExtractDestination(txout.scriptPubKey, dest)) { | ||
std::string address = EncodeDestination(dest); | ||
std::string label; | ||
if (model->wallet().getAddress(dest, &label, nullptr, nullptr) && !label.empty()) { | ||
address_info = QString::fromStdString(label) + QString(" (") + QString::fromStdString(address) + QString(")"); | ||
} else { | ||
address_info = QString::fromStdString(address); | ||
} | ||
} | ||
QString output_info = tr("%1: %2 to %3").arg(i).arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), txout.nValue)).arg(address_info); | ||
|
||
QRadioButton *radio_button = new QRadioButton(output_info, nullptr); | ||
radio_button->setObjectName(QString::number(i) + QString("_radioButton")); | ||
ui->verticalLayout->addWidget(radio_button); | ||
|
||
if (!found_change && model->wallet().isChange(txout)) { | ||
radio_button->setChecked(true); | ||
ui->none_radioButton->setChecked(false); | ||
found_change = true; | ||
} | ||
} | ||
GUIUtil::handleCloseWindowShortcut(this); | ||
} | ||
|
||
std::optional<uint32_t> BumpfeeChooseChangeDialog::GetSelectedOutput() | ||
{ | ||
for (int i = 0; i < ui->verticalLayout->count(); ++i) { | ||
QRadioButton* child = dynamic_cast<QRadioButton*>(ui->verticalLayout->itemAt(i)->widget()); | ||
if (child->isChecked()) { | ||
if (i == 0) { | ||
// "None" option selected | ||
return std::nullopt; | ||
} | ||
// Return the output index, offset by one for the "None" option at index 0 | ||
return static_cast<uint32_t>(i - 1); | ||
} | ||
} | ||
return std::nullopt; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) 2022 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or https://www.opensource.org/licenses/mit-license.php. | ||
|
||
#ifndef BITCOIN_QT_BUMPFEECHOOSECHANGEDIALOG_H | ||
#define BITCOIN_QT_BUMPFEECHOOSECHANGEDIALOG_H | ||
|
||
#include <QDialog> | ||
#include <optional> | ||
|
||
#include <uint256.h> | ||
|
||
class WalletModel; | ||
class uint256; | ||
|
||
namespace Ui { | ||
class BumpfeeChooseChangeDialog; | ||
} | ||
|
||
/** Dialog for choosing the change output when bumping fee | ||
*/ | ||
class BumpfeeChooseChangeDialog : public QDialog | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
|
||
explicit BumpfeeChooseChangeDialog(WalletModel *model, QWidget *parent, const uint256& txid); | ||
std::optional<uint32_t> GetSelectedOutput(); | ||
|
||
private: | ||
Ui::BumpfeeChooseChangeDialog *ui; | ||
WalletModel *model; | ||
}; | ||
|
||
#endif // BITCOIN_QT_BUMPFEECHOOSECHANGEDIALOG_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ui version="4.0"> | ||
<class>BumpfeeChooseChangeDialog</class> | ||
<widget class="QDialog" name="BumpfeeChooseChangeDialog"> | ||
<property name="geometry"> | ||
<rect> | ||
<x>0</x> | ||
<y>0</y> | ||
<width>737</width> | ||
<height>422</height> | ||
</rect> | ||
</property> | ||
<property name="windowTitle"> | ||
<string>Choose Change Output</string> | ||
</property> | ||
<property name="sizeGripEnabled"> | ||
<bool>true</bool> | ||
</property> | ||
<layout class="QVBoxLayout" name="verticalLayout_2"> | ||
<item> | ||
<widget class="QLabel" name="label"> | ||
<property name="text"> | ||
<string><html><head/><body><p>Choose which output is change.</p><p>The additional transaction fee will be deducted from this output. If it is insufficient, new inputs may be added and the resulting change sent to the address of the selected output.</p></body></html></string> | ||
</property> | ||
<property name="textFormat"> | ||
<enum>Qt::RichText</enum> | ||
</property> | ||
<property name="wordWrap"> | ||
<bool>true</bool> | ||
</property> | ||
</widget> | ||
</item> | ||
<item> | ||
<widget class="QScrollArea" name="scrollArea"> | ||
<property name="widgetResizable"> | ||
<bool>true</bool> | ||
</property> | ||
<widget class="QWidget" name="scrollAreaWidgetContents"> | ||
<property name="geometry"> | ||
<rect> | ||
<x>0</x> | ||
<y>0</y> | ||
<width>711</width> | ||
<height>288</height> | ||
</rect> | ||
</property> | ||
<layout class="QVBoxLayout" name="verticalLayout"> | ||
<item> | ||
<widget class="QRadioButton" name="none_radioButton"> | ||
<property name="text"> | ||
<string>None</string> | ||
</property> | ||
<property name="checked"> | ||
<bool>true</bool> | ||
</property> | ||
</widget> | ||
</item> | ||
</layout> | ||
</widget> | ||
</widget> | ||
</item> | ||
<item> | ||
<widget class="QDialogButtonBox" name="buttonBox"> | ||
<property name="orientation"> | ||
<enum>Qt::Horizontal</enum> | ||
</property> | ||
<property name="standardButtons"> | ||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||
</property> | ||
</widget> | ||
</item> | ||
</layout> | ||
</widget> | ||
<resources/> | ||
<connections> | ||
<connection> | ||
<sender>buttonBox</sender> | ||
<signal>accepted()</signal> | ||
<receiver>BumpfeeChooseChangeDialog</receiver> | ||
<slot>accept()</slot> | ||
<hints> | ||
<hint type="sourcelabel"> | ||
<x>210</x> | ||
<y>395</y> | ||
</hint> | ||
<hint type="destinationlabel"> | ||
<x>200</x> | ||
<y>210</y> | ||
</hint> | ||
</hints> | ||
</connection> | ||
<connection> | ||
<sender>buttonBox</sender> | ||
<signal>rejected()</signal> | ||
<receiver>BumpfeeChooseChangeDialog</receiver> | ||
<slot>reject()</slot> | ||
<hints> | ||
<hint type="sourcelabel"> | ||
<x>210</x> | ||
<y>395</y> | ||
</hint> | ||
<hint type="destinationlabel"> | ||
<x>200</x> | ||
<y>210</y> | ||
</hint> | ||
</hints> | ||
</connection> | ||
</connections> | ||
</ui> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters