Merge pull request #7296

bebe58b SQUASHME: Fix rpc tests that assumed fallback to minRelayTxFee (Alex Morcos)
e420a1b Add sane fallback for fee estimation (Alex Morcos)
995b9f3 Always respect GetRequiredFee for wallet txs (Alex Morcos)
pull/262/head
Wladimir J. van der Laan 9 years ago
commit c49551886a
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6

@ -30,6 +30,11 @@ class RawTransactionsTest(BitcoinTestFramework):
print "Mining blocks..." print "Mining blocks..."
min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee'] min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
node.settxfee(min_relay_tx_fee)
# if the fee's positive delta is higher than this value tests will fail, # if the fee's positive delta is higher than this value tests will fail,
# neg. delta always fail the tests. # neg. delta always fail the tests.
# The size of the signature of every input may be at most 2 bytes larger # The size of the signature of every input may be at most 2 bytes larger
@ -447,6 +452,10 @@ class RawTransactionsTest(BitcoinTestFramework):
wait_bitcoinds() wait_bitcoinds()
self.nodes = start_nodes(4, self.options.tmpdir) self.nodes = start_nodes(4, self.options.tmpdir)
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
node.settxfee(min_relay_tx_fee)
connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,1,2)

@ -33,7 +33,9 @@ class MempoolLimitTest(BitcoinTestFramework):
inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}] inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
outputs = {self.nodes[0].getnewaddress() : 0.0001} outputs = {self.nodes[0].getnewaddress() : 0.0001}
tx = self.nodes[0].createrawtransaction(inputs, outputs) tx = self.nodes[0].createrawtransaction(inputs, outputs)
self.nodes[0].settxfee(self.relayfee) # specifically fund this tx with low fee
txF = self.nodes[0].fundrawtransaction(tx) txF = self.nodes[0].fundrawtransaction(tx)
self.nodes[0].settxfee(0) # return to automatic fee selection
txFS = self.nodes[0].signrawtransaction(txF['hex']) txFS = self.nodes[0].signrawtransaction(txF['hex'])
txid = self.nodes[0].sendrawtransaction(txFS['hex']) txid = self.nodes[0].sendrawtransaction(txFS['hex'])
self.nodes[0].lockunspent(True, [us0]) self.nodes[0].lockunspent(True, [us0])

@ -393,6 +393,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE)); strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
@ -959,6 +961,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
else else
return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"]));
} }
if (mapArgs.count("-fallbackfee"))
{
CAmount nFeePerK = 0;
if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK))
return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"]));
if (nFeePerK > nHighTransactionFeeWarning)
InitWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available."));
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
if (mapArgs.count("-paytxfee")) if (mapArgs.count("-paytxfee"))
{ {
CAmount nFeePerK = 0; CAmount nFeePerK = 0;

@ -640,13 +640,15 @@ void SendCoinsDialog::updateSmartFeeLabel()
CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks); CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
if (feeRate <= CFeeRate(0)) // not enough data => minfee if (feeRate <= CFeeRate(0)) // not enough data => minfee
{ {
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB"); ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
ui->labelFeeEstimation->setText(""); ui->labelFeeEstimation->setText("");
} }
else else
{ {
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->hide(); ui->labelSmartFee2->hide();
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks));
} }

@ -47,6 +47,12 @@ bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
* Override with -mintxfee * Override with -mintxfee
*/ */
CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE); CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
/**
* If fee estimation does not have enough data to provide estimates, use this fee instead.
* Has no effect if not using fee estimation
* Override with -fallbackfee
*/
CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
/** @defgroup mapWallet /** @defgroup mapWallet
* *
@ -2230,14 +2236,12 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
if (nFeeNeeded == 0) { if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget; int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes); nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for our desired target // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
// so we make sure we're paying at least minTxFee if (nFeeNeeded == 0)
if (nFeeNeeded == 0 || (unsigned int)estimateFoundTarget > nConfirmTarget) nFeeNeeded = fallbackFee.GetFee(nTxBytes);
nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); }
} // prevent user from paying a fee below minRelayTxFee or minTxFee
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
// But always obey the maximum // But always obey the maximum
if (nFeeNeeded > maxTxFee) if (nFeeNeeded > maxTxFee)
nFeeNeeded = maxTxFee; nFeeNeeded = maxTxFee;

@ -41,6 +41,8 @@ static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
static const CAmount DEFAULT_TRANSACTION_FEE = 0; static const CAmount DEFAULT_TRANSACTION_FEE = 0;
//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB //! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
static const CAmount nHighTransactionFeeWarning = 0.01 * COIN; static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
//! -fallbackfee default
static const CAmount DEFAULT_FALLBACK_FEE = 20000;
//! -mintxfee default //! -mintxfee default
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000; static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
//! -maxtxfee default //! -maxtxfee default
@ -745,6 +747,7 @@ public:
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
static CFeeRate minTxFee; static CFeeRate minTxFee;
static CFeeRate fallbackFee;
/** /**
* Estimate the minimum fee considering user set parameters * Estimate the minimum fee considering user set parameters
* and the required fee * and the required fee

Loading…
Cancel
Save