From c6cb21d17ab8097b6a425d37e48c955fbb0e9f0c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 10 Apr 2014 14:14:18 -0400 Subject: Type-safe CFeeRate class Use CFeeRate instead of an int64_t for quantities that are fee-per-size. Helps prevent unit-conversion mismatches between the wallet, relaying, and mining code. --- src/qt/coincontroldialog.cpp | 29 +++++++---------------------- src/qt/guiutil.cpp | 2 +- src/qt/optionsdialog.cpp | 4 ++-- src/qt/optionsmodel.cpp | 21 ++++++++++++--------- src/qt/paymentserver.cpp | 2 +- src/qt/walletmodel.cpp | 6 ------ 6 files changed, 23 insertions(+), 41 deletions(-) (limited to 'src/qt') diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index dc9d2afe27..e27f1bff97 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -453,7 +453,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) CTxOut txout(amount, (CScript)vector(24, 0)); txDummy.vout.push_back(txout); - if (txout.IsDust(CTransaction::nMinRelayTxFee)) + if (txout.IsDust(CTransaction::minRelayTxFee)) fDust = true; } } @@ -525,7 +525,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority); // Fee - int64_t nFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); + int64_t nFee = payTxFee.GetFee(nBytes); // Min Fee int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND); @@ -536,26 +536,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { nChange = nAmount - nPayFee - nPayAmount; - // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee - if (nPayFee < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) - { - if (nChange < CTransaction::nMinTxFee) // change < 0.0001 => simply move all change to fees - { - nPayFee += nChange; - nChange = 0; - } - else - { - nChange = nChange + nPayFee - CTransaction::nMinTxFee; - nPayFee = CTransaction::nMinTxFee; - } - } - // Never create dust outputs; if we would, just add the dust to the fee. if (nChange > 0 && nChange < CENT) { CTxOut txout(nChange, (CScript)vector(24, 0)); - if (txout.IsDust(CTransaction::nMinRelayTxFee)) + if (txout.IsDust(CTransaction::minRelayTxFee)) { nPayFee += nChange; nChange = 0; @@ -610,19 +595,19 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // tool tips QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "

"; - toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "

"; + toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())) + "

"; toolTip1 += tr("Can vary +/- 1 byte per input."); QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "

"; toolTip2 += tr("This label turns red, if the priority is smaller than \"medium\".") + "

"; - toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)); + toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())); QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "

"; - toolTip3 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "

"; + toolTip3 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())) + "

"; toolTip3 += tr("Amounts below 0.546 times the minimum relay fee are shown as dust."); QString toolTip4 = tr("This label turns red, if the change is smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "

"; - toolTip4 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)); + toolTip4 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())); l5->setToolTip(toolTip1); l6->setToolTip(toolTip2); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 1922d228c5..4fe98251d9 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -210,7 +210,7 @@ bool isDust(const QString& address, qint64 amount) CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); CScript script; script.SetDestination(dest); CTxOut txOut(amount, script); - return txOut.IsDust(CTransaction::nMinRelayTxFee); + return txOut.IsDust(CTransaction::minRelayTxFee); } QString HtmlEscape(const QString& str, bool fMultiLine) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 96464d2cc0..1cbf5f8810 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -14,7 +14,7 @@ #include "monitoreddatamapper.h" #include "optionsmodel.h" -#include "main.h" // for CTransaction::nMinTxFee and MAX_SCRIPTCHECK_THREADS +#include "main.h" // for CTransaction::minTxFee and MAX_SCRIPTCHECK_THREADS #include "netbase.h" #include "txdb.h" // for -dbcache defaults @@ -101,7 +101,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) : #endif ui->unit->setModel(new BitcoinUnits(this)); - ui->transactionFee->setSingleStep(CTransaction::nMinTxFee); + ui->transactionFee->setSingleStep(CTransaction::minTxFee.GetFeePerK()); /* Widget-to-option mapper */ mapper = new MonitoredDataMapper(this); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 051098315d..f3a5f37bb3 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -94,7 +94,7 @@ void OptionsModel::Init() #ifdef ENABLE_WALLET if (!settings.contains("nTransactionFee")) settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE); - nTransactionFee = settings.value("nTransactionFee").toLongLong(); // if -paytxfee is set, this will be overridden later in init.cpp + payTxFee = CFeeRate(settings.value("nTransactionFee").toLongLong()); // if -paytxfee is set, this will be overridden later in init.cpp if (mapArgs.count("-paytxfee")) addOverriddenOption("-paytxfee"); @@ -187,15 +187,16 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const return settings.value("nSocksVersion", 5); #ifdef ENABLE_WALLET - case Fee: - // Attention: Init() is called before nTransactionFee is set in AppInit2()! + case Fee: { + // Attention: Init() is called before payTxFee is set in AppInit2()! // To ensure we can change the fee on-the-fly update our QSetting when // opening OptionsDialog, which queries Fee via the mapper. - if (nTransactionFee != settings.value("nTransactionFee").toLongLong()) - settings.setValue("nTransactionFee", (qint64)nTransactionFee); - // Todo: Consider to revert back to use just nTransactionFee here, if we don't want + if (!(payTxFee == CFeeRate(settings.value("nTransactionFee").toLongLong(), 1000))) + settings.setValue("nTransactionFee", (qint64)payTxFee.GetFeePerK()); + // Todo: Consider to revert back to use just payTxFee here, if we don't want // -paytxfee to update our QSettings! return settings.value("nTransactionFee"); + } case SpendZeroConfChange: return settings.value("bSpendZeroConfChange"); #endif @@ -284,12 +285,14 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in } break; #ifdef ENABLE_WALLET - case Fee: // core option - can be changed on-the-fly + case Fee: { // core option - can be changed on-the-fly // Todo: Add is valid check and warn via message, if not - nTransactionFee = value.toLongLong(); - settings.setValue("nTransactionFee", (qint64)nTransactionFee); + qint64 nTransactionFee = value.toLongLong(); + payTxFee = CFeeRate(nTransactionFee, 1000); + settings.setValue("nTransactionFee", nTransactionFee); emit transactionFeeChanged(nTransactionFee); break; + } case SpendZeroConfChange: if (settings.value("bSpendZeroConfChange") != value) { settings.setValue("bSpendZeroConfChange", value); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 4c45585685..6165731d22 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -551,7 +551,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins // Extract and check amounts CTxOut txOut(sendingTo.second, sendingTo.first); - if (txOut.IsDust(CTransaction::nMinRelayTxFee)) { + if (txOut.IsDust(CTransaction::minRelayTxFee)) { emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).") .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)), CClientUIInterface::MSG_ERROR); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 37d82ec063..87ff3db584 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -231,12 +231,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return AmountExceedsBalance; } - if((total + nTransactionFee) > nBalance) - { - transaction.setTransactionFee(nTransactionFee); - return SendCoinsReturn(AmountWithFeeExceedsBalance); - } - { LOCK2(cs_main, wallet->cs_wallet); -- cgit v1.2.3