Use CoinControl to pass custom fee setting from QT.

This fixes buggy behavior where we were temporarily setting and unsetting the
global payTxFee when trying to send a transaction with a custom fee from the
GUI. The previous behavior was inconsistent depending on the order of using the
RPC call settxfee and clicking various radio buttons in the sendcoinsdialog.
The new behavior is that transactions sent with the GUI will always use either
the smartfee slider value or the custom fee set on the GUI and they will not
affect the global defaults which are only for RPC and initial GUI values.
This commit is contained in:
Alex Morcos 2017-06-28 19:24:28 -04:00
parent 03ee701161
commit 1983ca6cb3
2 changed files with 25 additions and 37 deletions

View file

@ -175,18 +175,13 @@ void SendCoinsDialog::setModel(WalletModel *_model)
ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n)); ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
} }
connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel())); connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel()));
connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls())); connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(updateGlobalFeeVariables()));
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels())); connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel())); connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
@ -194,7 +189,6 @@ void SendCoinsDialog::setModel(WalletModel *_model)
updateFeeSectionControls(); updateFeeSectionControls();
updateMinFeeLabel(); updateMinFeeLabel();
updateSmartFeeLabel(); updateSmartFeeLabel();
updateGlobalFeeVariables();
// set default rbf checkbox state // set default rbf checkbox state
ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked); ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
@ -274,12 +268,8 @@ void SendCoinsDialog::on_sendButton_clicked()
CCoinControl ctrl; CCoinControl ctrl;
if (model->getOptionsModel()->getCoinControlFeatures()) if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl; ctrl = *CoinControlDialog::coinControl;
if (ui->radioSmartFee->isChecked()) {
ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex()); updateCoinControlState(ctrl);
} else {
ctrl.m_confirm_target = boost::none;
}
ctrl.signalRbf = ui->optInRBF->isChecked();
prepareStatus = model->prepareTransaction(currentTransaction, ctrl); prepareStatus = model->prepareTransaction(currentTransaction, ctrl);
@ -636,18 +626,6 @@ void SendCoinsDialog::updateFeeSectionControls()
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
} }
void SendCoinsDialog::updateGlobalFeeVariables()
{
if (ui->radioSmartFee->isChecked())
{
payTxFee = CFeeRate(0);
}
else
{
payTxFee = CFeeRate(ui->customFee->value());
}
}
void SendCoinsDialog::updateFeeMinimizedLabel() void SendCoinsDialog::updateFeeMinimizedLabel()
{ {
if(!model || !model->getOptionsModel()) if(!model || !model->getOptionsModel())
@ -669,15 +647,30 @@ void SendCoinsDialog::updateMinFeeLabel()
); );
} }
void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
{
if (ui->radioCustomFee->isChecked()) {
ctrl.m_feerate = CFeeRate(ui->customFee->value());
} else {
ctrl.m_feerate = boost::none;
}
// Avoid using global defaults when sending money from the GUI
// Either custom fee will be used or if not selected, the confirmation target from dropdown box
ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
ctrl.signalRbf = ui->optInRBF->isChecked();
}
void SendCoinsDialog::updateSmartFeeLabel() void SendCoinsDialog::updateSmartFeeLabel()
{ {
if(!model || !model->getOptionsModel()) if(!model || !model->getOptionsModel())
return; return;
CCoinControl coin_control;
int nBlocksToConfirm = getConfTargetForIndex(ui->confTargetSelector->currentIndex()); updateCoinControlState(coin_control);
coin_control.m_feerate = boost::none; // Explicitly use only fee estimation rate for smart fee labels
FeeCalculation feeCalc; FeeCalculation feeCalc;
bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, ui->optInRBF->isChecked()); bool conservative_estimate = CalculateEstimateType(FeeEstimateMode::UNSET, coin_control.signalRbf);
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool, conservative_estimate); CFeeRate feeRate = ::feeEstimator.estimateSmartFee(*coin_control.m_confirm_target, &feeCalc, ::mempool, conservative_estimate);
if (feeRate <= CFeeRate(0)) // not enough data => minfee if (feeRate <= CFeeRate(0)) // not enough data => minfee
{ {
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
@ -752,8 +745,6 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
if (!checked && model) // coin control features disabled if (!checked && model) // coin control features disabled
CoinControlDialog::coinControl->SetNull(); CoinControlDialog::coinControl->SetNull();
// make sure we set back the confirmation target
updateGlobalFeeVariables();
coinControlUpdateLabels(); coinControlUpdateLabels();
} }
@ -844,15 +835,11 @@ void SendCoinsDialog::coinControlUpdateLabels()
if (!model || !model->getOptionsModel()) if (!model || !model->getOptionsModel())
return; return;
updateCoinControlState(*CoinControlDialog::coinControl);
// set pay amounts // set pay amounts
CoinControlDialog::payAmounts.clear(); CoinControlDialog::payAmounts.clear();
CoinControlDialog::fSubtractFeeFromAmount = false; CoinControlDialog::fSubtractFeeFromAmount = false;
if (ui->radioSmartFee->isChecked()) {
CoinControlDialog::coinControl->m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
} else {
CoinControlDialog::coinControl->m_confirm_target = boost::none;
}
CoinControlDialog::coinControl->signalRbf = ui->optInRBF->isChecked();
for(int i = 0; i < ui->entries->count(); ++i) for(int i = 0; i < ui->entries->count(); ++i)
{ {

View file

@ -68,6 +68,8 @@ private:
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString()); void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString());
void minimizeFeeSection(bool fMinimize); void minimizeFeeSection(bool fMinimize);
void updateFeeMinimizedLabel(); void updateFeeMinimizedLabel();
// Update the passed in CCoinControl with state from the GUI
void updateCoinControlState(CCoinControl& ctrl);
private Q_SLOTS: private Q_SLOTS:
void on_sendButton_clicked(); void on_sendButton_clicked();
@ -91,7 +93,6 @@ private Q_SLOTS:
void updateFeeSectionControls(); void updateFeeSectionControls();
void updateMinFeeLabel(); void updateMinFeeLabel();
void updateSmartFeeLabel(); void updateSmartFeeLabel();
void updateGlobalFeeVariables();
Q_SIGNALS: Q_SIGNALS:
// Fired when a message should be reported to the user // Fired when a message should be reported to the user