Skip to content

Commit d01bcc4

Browse files
committed
Merge pull request #5485
aa279d6 Enforce minRelayTxFee on wallet created tx and add a maxtxfee option. (Gregory Maxwell)
2 parents 4406c3e + aa279d6 commit d01bcc4

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

src/init.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ std::string HelpMessage(HelpMessageMode mode)
287287
strUsage += " -sendfreetransactions " + strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0) + "\n";
288288
strUsage += " -spendzeroconfchange " + strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1) + "\n";
289289
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";
290+
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";
290291
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
291292
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat") + "\n";
292293
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)
696697
mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
697698
}
698699
}
700+
if (mapArgs.count("-maxtxfee"))
701+
{
702+
CAmount nMaxFee = 0;
703+
if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
704+
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maptxfee"]));
705+
if (nMaxFee > nHighTransactionMaxFeeWarning)
706+
InitWarning(_("Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction."));
707+
maxTxFee = nMaxFee;
708+
if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
709+
{
710+
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
711+
mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
712+
}
713+
}
699714
nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
700715
bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
701716
fSendFreeTransactions = GetArg("-sendfreetransactions", false);

src/wallet.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ using namespace std;
2626
* Settings
2727
*/
2828
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
29+
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
2930
unsigned int nTxConfirmTarget = 1;
3031
bool bSpendZeroConfChange = true;
3132
bool fSendFreeTransactions = false;
@@ -1525,27 +1526,32 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
15251526
}
15261527
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
15271528

1528-
CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
1529+
// Can we complete this as a free transaction?
1530+
if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
1531+
{
1532+
// Not enough fee: enough priority?
1533+
double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
1534+
// Not enough mempool history to estimate: use hard-coded AllowFree.
1535+
if (dPriorityNeeded <= 0 && AllowFree(dPriority))
1536+
break;
1537+
1538+
// Small enough, and priority high enough, to send for free
1539+
if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
1540+
break;
1541+
}
15291542

1530-
if (nFeeRet >= nFeeNeeded)
1531-
break; // Done, enough fee included.
1543+
CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
15321544

1533-
// Too big to send for free? Include more fee and try again:
1534-
if (!fSendFreeTransactions || nBytes > MAX_FREE_TRANSACTION_CREATE_SIZE)
1545+
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
1546+
// because we must be at the maximum allowed fee.
1547+
if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
15351548
{
1536-
nFeeRet = nFeeNeeded;
1537-
continue;
1549+
strFailReason = _("Transaction too large for fee policy");
1550+
return false;
15381551
}
15391552

1540-
// Not enough fee: enough priority?
1541-
double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
1542-
// Not enough mempool history to estimate: use hard-coded AllowFree.
1543-
if (dPriorityNeeded <= 0 && AllowFree(dPriority))
1544-
break;
1545-
1546-
// Small enough, and priority high enough, to send for free
1547-
if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
1548-
break;
1553+
if (nFeeRet >= nFeeNeeded)
1554+
break; // Done, enough fee included.
15491555

15501556
// Include more fee and try again.
15511557
nFeeRet = nFeeNeeded;
@@ -1617,9 +1623,6 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
16171623
{
16181624
// payTxFee is user-set "I want to pay this much"
16191625
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
1620-
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
1621-
if (nFeeNeeded > 0 && nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
1622-
nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
16231626
// user selected total at least (default=true)
16241627
if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
16251628
nFeeNeeded = payTxFee.GetFeePerK();
@@ -1630,6 +1633,12 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
16301633
// back to a hard-coded fee
16311634
if (nFeeNeeded == 0)
16321635
nFeeNeeded = minTxFee.GetFee(nTxBytes);
1636+
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
1637+
if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
1638+
nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
1639+
// But always obey the maximum
1640+
if (nFeeNeeded > maxTxFee)
1641+
nFeeNeeded = maxTxFee;
16331642
return nFeeNeeded;
16341643
}
16351644

src/wallet.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* Settings
3131
*/
3232
extern CFeeRate payTxFee;
33+
extern CAmount maxTxFee;
3334
extern unsigned int nTxConfirmTarget;
3435
extern bool bSpendZeroConfChange;
3536
extern bool fSendFreeTransactions;
@@ -39,6 +40,10 @@ extern bool fPayAtLeastCustomFee;
3940
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
4041
//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
4142
static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
43+
//! -maxtxfee default
44+
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
45+
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
46+
static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning;
4247
//! Largest (in bytes) free transaction we're willing to create
4348
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
4449

0 commit comments

Comments
 (0)