Skip to content

Commit

Permalink
Merge pull request #5200
Browse files Browse the repository at this point in the history
c1c9d5b [Qt] Add Smartfee to GUI (Cozz Lovan)
e7876b2 [Wallet] Prevent user from paying a non-sense fee (Cozz Lovan)
ed3e5e4 [Wallet] Add global boolean whether to pay at least the custom fee (default=true) (Cozz Lovan)
0ed9675 [Wallet] Add global boolean whether to send free transactions (default=true) (Cozz Lovan)
  • Loading branch information
laanwj committed Nov 19, 2014
2 parents 8c41853 + c1c9d5b commit b7fe9cd
Show file tree
Hide file tree
Showing 21 changed files with 911 additions and 164 deletions.
2 changes: 2 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -paytxfee=<amt> " + strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())) + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
strUsage += " -sendfreetransactions " + strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0) + "\n";
strUsage += " -spendzeroconfchange " + strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1) + "\n";
strUsage += " -txconfirmtarget=<n> " + strprintf(_("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: %u)"), 1) + "\n";
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
Expand Down Expand Up @@ -704,6 +705,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
fSendFreeTransactions = GetArg("-sendfreetransactions", false);

std::string strWalletFile = GetArg("-wallet", "wallet.dat");
#endif // ENABLE_WALLET
Expand Down
6 changes: 6 additions & 0 deletions src/qt/bitcoinamountfield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ void BitcoinAmountField::clear()
unit->setCurrentIndex(0);
}

void BitcoinAmountField::setEnabled(bool fEnabled)
{
amount->setEnabled(fEnabled);
unit->setEnabled(fEnabled);
}

bool BitcoinAmountField::validate()
{
bool valid = false;
Expand Down
3 changes: 3 additions & 0 deletions src/qt/bitcoinamountfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class BitcoinAmountField: public QWidget
/** Make field empty and ready for new input. */
void clear();

/** Enable/Disable. */
void setEnabled(bool fEnabled);

/** Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907),
in these cases we have to set it up manually.
*/
Expand Down
95 changes: 54 additions & 41 deletions src/qt/coincontroldialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <QDialogButtonBox>
#include <QFlags>
#include <QIcon>
#include <QSettings>
#include <QString>
#include <QTreeWidget>
#include <QTreeWidgetItem>
Expand Down Expand Up @@ -130,10 +131,22 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) :

// default view is sorted by amount desc
sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);

// restore list mode and sortorder as a convenience feature
QSettings settings;
if (settings.contains("nCoinControlMode") && !settings.value("nCoinControlMode").toBool())
ui->radioTreeMode->click();
if (settings.contains("nCoinControlSortColumn") && settings.contains("nCoinControlSortOrder"))
sortView(settings.value("nCoinControlSortColumn").toInt(), ((Qt::SortOrder)settings.value("nCoinControlSortOrder").toInt()));
}

CoinControlDialog::~CoinControlDialog()
{
QSettings settings;
settings.setValue("nCoinControlMode", ui->radioListMode->isChecked());
settings.setValue("nCoinControlSortColumn", sortColumn);
settings.setValue("nCoinControlSortOrder", (int)sortOrder);

delete ui;
}

Expand Down Expand Up @@ -290,19 +303,19 @@ void CoinControlDialog::clipboardAmount()
// copy label "Fee" to clipboard
void CoinControlDialog::clipboardFee()
{
GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")));
GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", ""));
}

// copy label "After fee" to clipboard
void CoinControlDialog::clipboardAfterFee()
{
GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")));
GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", ""));
}

// copy label "Bytes" to clipboard
void CoinControlDialog::clipboardBytes()
{
GUIUtil::setClipboard(ui->labelCoinControlBytes->text());
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", ""));
}

// copy label "Priority" to clipboard
Expand All @@ -320,7 +333,7 @@ void CoinControlDialog::clipboardLowOutput()
// copy label "Change" to clipboard
void CoinControlDialog::clipboardChange()
{
GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")));
GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", ""));
}

// treeview: sort
Expand Down Expand Up @@ -402,26 +415,22 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
}

// return human readable label for priority number
QString CoinControlDialog::getPriorityLabel(const CTxMemPool& pool, double dPriority)
QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEstimatePriority)
{
// confirmations -> textual description
typedef std::map<unsigned int, QString> PriorityDescription;
const static PriorityDescription priorityDescriptions = boost::assign::map_list_of
(1, tr("highest"))(2, tr("higher"))(3, tr("high"))
(5, tr("medium-high"))(6, tr("medium"))
(10, tr("low-medium"))(15, tr("low"))
(20, tr("lower"));

BOOST_FOREACH(const PriorityDescription::value_type& i, priorityDescriptions)
{
double p = mempool.estimatePriority(i.first);
if (p > 0 && dPriority >= p) return i.second;
}
// Note: if mempool hasn't accumulated enough history (estimatePriority
// returns -1) we're conservative and classify as "lowest"
if (mempool.estimatePriority(nTxConfirmTarget) <= 0 && AllowFree(dPriority))
return ">=" + tr("medium");
return tr("lowest");
double dPriorityMedium = mempoolEstimatePriority;

if (dPriorityMedium <= 0)
dPriorityMedium = AllowFreeThreshold(); // not enough data, back to hard-coded

if (dPriority / 1000000 > dPriorityMedium) return tr("highest");
else if (dPriority / 100000 > dPriorityMedium) return tr("higher");
else if (dPriority / 10000 > dPriorityMedium) return tr("high");
else if (dPriority / 1000 > dPriorityMedium) return tr("medium-high");
else if (dPriority > dPriorityMedium) return tr("medium");
else if (dPriority * 10 > dPriorityMedium) return tr("low-medium");
else if (dPriority * 100 > dPriorityMedium) return tr("low");
else if (dPriority * 1000 > dPriorityMedium) return tr("lower");
else return tr("lowest");
}

// shows count of locked unspent outputs
Expand Down Expand Up @@ -470,6 +479,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
double dPriorityInputs = 0;
unsigned int nQuantity = 0;
int nQuantityUncompressed = 0;
bool fAllowFree = false;

vector<COutPoint> vCoinControl;
vector<COutput> vOutputs;
Expand Down Expand Up @@ -522,24 +532,22 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here

// Priority
double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget);
dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
sPriorityLabel = CoinControlDialog::getPriorityLabel(mempool, dPriority);
sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority);

// Voluntary Fee
nPayFee = payTxFee.GetFee(max((unsigned int)1000, nBytes));
// Fee
nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);

// Min Fee
if (nPayFee == 0)
{
nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);

double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
if (dPriorityNeeded <= 0 && !AllowFree(dPriority)) // not enough mempool history: never send free
dPriorityNeeded = std::numeric_limits<double>::max();
// Allow free?
double dPriorityNeeded = mempoolEstimatePriority;
if (dPriorityNeeded <= 0)
dPriorityNeeded = AllowFreeThreshold(); // not enough data, back to hard-coded
fAllowFree = (dPriority >= dPriorityNeeded);

if (nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE && dPriority >= dPriorityNeeded)
if (fSendFreeTransactions)
if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
nPayFee = 0;
}

if (nPayAmount > 0)
{
Expand Down Expand Up @@ -595,7 +603,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l6->setText(sPriorityLabel); // Priority
l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
if (nPayFee > 0)
if (nPayFee > 0 && !(payTxFee.GetFeePerK() > 0 && fPayAtLeastCustomFee && nBytes < 1000))
{
l3->setText("~" + l3->text());
l4->setText("~" + l4->text());
Expand All @@ -605,7 +613,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)

// turn labels "red"
l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000
l6->setStyleSheet((dPriority > 0 && !AllowFree(dPriority)) ? "color:red;" : ""); // Priority < "medium"
l6->setStyleSheet((dPriority > 0 && !fAllowFree) ? "color:red;" : ""); // Priority < "medium"
l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes"

// tool tips
Expand All @@ -620,7 +628,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546)));

// how many satoshis the estimated fee can vary per byte we guess wrong
double dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), std::max(payTxFee.GetFeePerK(), mempool.estimateFee(nTxConfirmTarget).GetFeePerK())) / 1000;
double dFeeVary;
if (payTxFee.GetFeePerK() > 0)
dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000;
else
dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), mempool.estimateFee(nTxConfirmTarget).GetFeePerK()) / 1000;
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);

l3->setToolTip(toolTip4);
Expand Down Expand Up @@ -656,6 +668,7 @@ void CoinControlDialog::updateView()
QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;

int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget);

map<QString, vector<COutput> > mapCoins;
model->listCoins(mapCoins);
Expand Down Expand Up @@ -745,7 +758,7 @@ void CoinControlDialog::updateView()

// priority
double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(mempool, dPriority));
itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority));
itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
nInputSum += nInputSize;
Expand Down Expand Up @@ -778,7 +791,7 @@ void CoinControlDialog::updateView()
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(mempool, dPrioritySum));
itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority));
itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/qt/coincontroldialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class CoinControlDialog : public QDialog

// static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*);
static QString getPriorityLabel(const CTxMemPool& pool, double);
static QString getPriorityLabel(double dPriority, double mempoolEstimatePriority);

static QList<CAmount> payAmounts;
static CCoinControl *coinControl;
Expand Down
78 changes: 13 additions & 65 deletions src/qt/forms/optionsdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -137,65 +137,6 @@
<string>W&amp;allet</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Wallet">
<item>
<widget class="QLabel" name="transactionFeeInfoLabel">
<property name="text">
<string>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1_Wallet">
<item>
<widget class="QLabel" name="transactionFeeLabel">
<property name="text">
<string>Pay transaction &amp;fee</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>transactionFee</cstring>
</property>
</widget>
</item>
<item>
<widget class="BitcoinAmountField" name="transactionFee"/>
</item>
<item>
<spacer name="horizontalSpacer_1_Wallet">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_Wallet">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
Expand Down Expand Up @@ -225,6 +166,19 @@
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Wallet">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabNetwork">
Expand Down Expand Up @@ -632,12 +586,6 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
<header>bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
Expand Down
Loading

0 comments on commit b7fe9cd

Please sign in to comment.