Use fee/priority estimates in wallet CreateTransaction

The wallet now uses the mempool fee estimator with a new
command-line option: -txconfirmtarget (default: 1) instead
of using hard-coded fees or priorities.

A new bitcoind that hasn't seen enough transactions to estimate
will fall back to the old hard-coded minimum priority or
transaction fee.

-paytxfee option overrides -txconfirmtarget.

Relaying and mining code isn't changed.

For Qt, the coin control dialog now uses priority estimates to
label transaction priority (instead of hard-coded constants);
unspent outputs were consistently labeled with a much higher
priority than is justified by the free transactions actually
being accepted into blocks.

I did not implement any GUI for setting -txconfirmtarget; I would
suggest getting rid of the "Pay transaction fee" GUI and replace
it with either "target number of confirmations" or maybe
a "faster confirmation <--> lower fee" slider or select box.
This commit is contained in:
Gavin Andresen
2014-05-27 15:44:57 -04:00
parent 29264a0a60
commit b33d1f5ee5
9 changed files with 105 additions and 47 deletions

View File

@@ -18,6 +18,7 @@ using namespace std;
// Settings
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = 1;
bool bSpendZeroConfChange = true;
//////////////////////////////////////////////////////////////////////////////
@@ -1273,6 +1274,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
return false;
}
wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.BindWallet(this);
CMutableTransaction txNew;
@@ -1393,19 +1395,31 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
// Check that enough fee is included
int64_t nPayFee = payTxFee.GetFee(nBytes);
bool fAllowFree = AllowFree(dPriority);
int64_t nMinFee = GetMinFee(wtxNew, nBytes, fAllowFree, GMF_SEND);
if (nFeeRet < max(nPayFee, nMinFee))
int64_t nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
if (nFeeRet >= nFeeNeeded)
break; // Done, enough fee included.
// Too big to send for free? Include more fee and try again:
if (nBytes > MAX_FREE_TRANSACTION_CREATE_SIZE)
{
nFeeRet = max(nPayFee, nMinFee);
nFeeRet = nFeeNeeded;
continue;
}
wtxNew.fTimeReceivedIsTxTime = true;
// 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;
break;
// Small enough, and priority high enough, to send for free
if (dPriority >= dPriorityNeeded)
break;
// Include more fee and try again.
nFeeRet = nFeeNeeded;
continue;
}
}
}
@@ -1513,6 +1527,20 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nV
return SendMoney(scriptPubKey, nValue, wtxNew);
}
int64_t CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
{
// payTxFee is user-set "I want to pay this much"
int64_t nFeeNeeded = payTxFee.GetFee(nTxBytes);
// User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0)
nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
// ... unless we don't have enough mempool data, in which case fall
// back to a hard-coded fee
if (nFeeNeeded == 0)
nFeeNeeded = CTransaction::minTxFee.GetFee(nTxBytes);
return nFeeNeeded;
}