Merge pull request #5485
aa279d6
Enforce minRelayTxFee on wallet created tx and add a maxtxfee option. (Gregory Maxwell)
This commit is contained in:
commit
d01bcc446e
3 changed files with 49 additions and 20 deletions
15
src/init.cpp
15
src/init.cpp
|
@ -287,6 +287,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||||
strUsage += " -sendfreetransactions " + strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0) + "\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 += " -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 += " -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 += " -maxtxfee=<amt> " + strprintf(_("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)"), FormatMoney(maxTxFee)) + "\n";
|
||||||
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
|
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
|
||||||
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat") + "\n";
|
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat") + "\n";
|
||||||
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
|
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
|
||||||
|
@ -696,6 +697,20 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||||
mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
|
mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mapArgs.count("-maxtxfee"))
|
||||||
|
{
|
||||||
|
CAmount nMaxFee = 0;
|
||||||
|
if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
|
||||||
|
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maptxfee"]));
|
||||||
|
if (nMaxFee > nHighTransactionMaxFeeWarning)
|
||||||
|
InitWarning(_("Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction."));
|
||||||
|
maxTxFee = nMaxFee;
|
||||||
|
if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
|
||||||
|
{
|
||||||
|
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
|
||||||
|
mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
|
nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
|
||||||
bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
|
bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
|
||||||
fSendFreeTransactions = GetArg("-sendfreetransactions", false);
|
fSendFreeTransactions = GetArg("-sendfreetransactions", false);
|
||||||
|
|
|
@ -26,6 +26,7 @@ using namespace std;
|
||||||
* Settings
|
* Settings
|
||||||
*/
|
*/
|
||||||
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
|
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
|
||||||
|
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
||||||
unsigned int nTxConfirmTarget = 1;
|
unsigned int nTxConfirmTarget = 1;
|
||||||
bool bSpendZeroConfChange = true;
|
bool bSpendZeroConfChange = true;
|
||||||
bool fSendFreeTransactions = false;
|
bool fSendFreeTransactions = false;
|
||||||
|
@ -1525,28 +1526,33 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
|
||||||
}
|
}
|
||||||
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
|
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
|
||||||
|
|
||||||
|
// Can we complete this as a free transaction?
|
||||||
|
if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
|
||||||
|
{
|
||||||
|
// Not enough fee: enough priority?
|
||||||
|
double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
|
||||||
|
// Not enough mempool history to estimate: use hard-coded AllowFree.
|
||||||
|
if (dPriorityNeeded <= 0 && AllowFree(dPriority))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Small enough, and priority high enough, to send for free
|
||||||
|
if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
|
CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
|
||||||
|
|
||||||
|
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
|
||||||
|
// because we must be at the maximum allowed fee.
|
||||||
|
if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
|
||||||
|
{
|
||||||
|
strFailReason = _("Transaction too large for fee policy");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (nFeeRet >= nFeeNeeded)
|
if (nFeeRet >= nFeeNeeded)
|
||||||
break; // Done, enough fee included.
|
break; // Done, enough fee included.
|
||||||
|
|
||||||
// Too big to send for free? Include more fee and try again:
|
|
||||||
if (!fSendFreeTransactions || nBytes > MAX_FREE_TRANSACTION_CREATE_SIZE)
|
|
||||||
{
|
|
||||||
nFeeRet = nFeeNeeded;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not enough fee: enough priority?
|
|
||||||
double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
|
|
||||||
// Not enough mempool history to estimate: use hard-coded AllowFree.
|
|
||||||
if (dPriorityNeeded <= 0 && AllowFree(dPriority))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Small enough, and priority high enough, to send for free
|
|
||||||
if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Include more fee and try again.
|
// Include more fee and try again.
|
||||||
nFeeRet = nFeeNeeded;
|
nFeeRet = nFeeNeeded;
|
||||||
continue;
|
continue;
|
||||||
|
@ -1617,9 +1623,6 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
|
||||||
{
|
{
|
||||||
// payTxFee is user-set "I want to pay this much"
|
// payTxFee is user-set "I want to pay this much"
|
||||||
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
|
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
|
||||||
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
|
|
||||||
if (nFeeNeeded > 0 && nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
|
|
||||||
nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
|
|
||||||
// user selected total at least (default=true)
|
// user selected total at least (default=true)
|
||||||
if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
|
if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
|
||||||
nFeeNeeded = payTxFee.GetFeePerK();
|
nFeeNeeded = payTxFee.GetFeePerK();
|
||||||
|
@ -1630,6 +1633,12 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
|
||||||
// back to a hard-coded fee
|
// back to a hard-coded fee
|
||||||
if (nFeeNeeded == 0)
|
if (nFeeNeeded == 0)
|
||||||
nFeeNeeded = minTxFee.GetFee(nTxBytes);
|
nFeeNeeded = minTxFee.GetFee(nTxBytes);
|
||||||
|
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
|
||||||
|
if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
|
||||||
|
nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
|
||||||
|
// But always obey the maximum
|
||||||
|
if (nFeeNeeded > maxTxFee)
|
||||||
|
nFeeNeeded = maxTxFee;
|
||||||
return nFeeNeeded;
|
return nFeeNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
* Settings
|
* Settings
|
||||||
*/
|
*/
|
||||||
extern CFeeRate payTxFee;
|
extern CFeeRate payTxFee;
|
||||||
|
extern CAmount maxTxFee;
|
||||||
extern unsigned int nTxConfirmTarget;
|
extern unsigned int nTxConfirmTarget;
|
||||||
extern bool bSpendZeroConfChange;
|
extern bool bSpendZeroConfChange;
|
||||||
extern bool fSendFreeTransactions;
|
extern bool fSendFreeTransactions;
|
||||||
|
@ -39,6 +40,10 @@ extern bool fPayAtLeastCustomFee;
|
||||||
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;
|
||||||
|
//! -maxtxfee default
|
||||||
|
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
|
||||||
|
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
|
||||||
|
static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning;
|
||||||
//! Largest (in bytes) free transaction we're willing to create
|
//! Largest (in bytes) free transaction we're willing to create
|
||||||
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
|
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue