[Qt] Add Smartfee to GUI

This commit is contained in:
Cozz Lovan
2014-11-02 00:14:47 +01:00
parent e7876b2979
commit c1c9d5b415
20 changed files with 903 additions and 166 deletions

View File

@@ -24,6 +24,7 @@
#include <QDialogButtonBox>
#include <QFlags>
#include <QIcon>
#include <QSettings>
#include <QString>
#include <QTreeWidget>
#include <QTreeWidgetItem>
@@ -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;
}
@@ -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
@@ -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
@@ -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"));
double dPriorityMedium = mempoolEstimatePriority;
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");
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
@@ -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;
@@ -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);
// Allow free?
double dPriorityNeeded = mempoolEstimatePriority;
if (dPriorityNeeded <= 0)
dPriorityNeeded = AllowFreeThreshold(); // not enough data, back to hard-coded
fAllowFree = (dPriority >= dPriorityNeeded);
double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
if (dPriorityNeeded <= 0 && !AllowFree(dPriority)) // not enough mempool history: never send free
dPriorityNeeded = std::numeric_limits<double>::max();
if (nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE && dPriority >= dPriorityNeeded)
if (fSendFreeTransactions)
if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
nPayFee = 0;
}
if (nPayAmount > 0)
{
@@ -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());
@@ -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
@@ -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);
@@ -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);
@@ -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;
@@ -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, " "));
}
}