From c6cb21d17ab8097b6a425d37e48c955fbb0e9f0c Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 10 Apr 2014 14:14:18 -0400 Subject: Type-safe CFeeRate class Use CFeeRate instead of an int64_t for quantities that are fee-per-size. Helps prevent unit-conversion mismatches between the wallet, relaying, and mining code. --- src/main.cpp | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 8e63e4213..9d6c01d64 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,9 +50,9 @@ bool fTxIndex = false; unsigned int nCoinCacheSize = 5000; /** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ -int64_t CTransaction::nMinTxFee = 10000; // Override with -mintxfee +CFeeRate CTransaction::minTxFee = CFeeRate(10000); // Override with -mintxfee /** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ -int64_t CTransaction::nMinRelayTxFee = 1000; +CFeeRate CTransaction::minRelayTxFee = CFeeRate(1000); struct COrphanBlock { uint256 hashBlock; @@ -543,7 +543,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) } if (whichType == TX_NULL_DATA) nDataOut++; - else if (txout.IsDust(CTransaction::nMinRelayTxFee)) { + else if (txout.IsDust(CTransaction::minRelayTxFee)) { reason = "dust"; return false; } @@ -783,10 +783,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode) { - // Base fee is either nMinTxFee or nMinRelayTxFee - int64_t nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee; + // Base fee is either minTxFee or minRelayTxFee + CFeeRate baseFeeRate = (mode == GMF_RELAY) ? tx.minRelayTxFee : tx.minTxFee; - int64_t nMinFee = (1 + (int64_t)nBytes / 1000) * nBaseFee; + int64_t nMinFee = baseFeeRate.GetFee(nBytes); if (fAllowFree) { @@ -800,16 +800,6 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, nMinFee = 0; } - // This code can be removed after enough miners have upgraded to version 0.9. - // Until then, be safe when sending and require a fee if any output - // is less than CENT: - if (nMinFee < nBaseFee && mode == GMF_SEND) - { - BOOST_FOREACH(const CTxOut& txout, tx.vout) - if (txout.nValue < CENT) - nMinFee = nBaseFee; - } - if (!MoneyRange(nMinFee)) nMinFee = MAX_MONEY; return nMinFee; @@ -916,10 +906,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); - // Continuously rate-limit free transactions + // Continuously rate-limit free (really, very-low-fee)transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < CTransaction::nMinRelayTxFee) + if (fLimitFree && nFees < CTransaction::minRelayTxFee.GetFee(nSize)) { static CCriticalSection csFreeLimiter; static double dFreeCount; @@ -940,10 +930,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa dFreeCount += nSize; } - if (fRejectInsaneFee && nFees > CTransaction::nMinRelayTxFee * 10000) + if (fRejectInsaneFee && nFees > CTransaction::minRelayTxFee.GetFee(nSize) * 10000) return error("AcceptToMemoryPool: : insane fees %s, %d > %d", hash.ToString(), - nFees, CTransaction::nMinRelayTxFee * 10000); + nFees, CTransaction::minRelayTxFee.GetFee(nSize) * 10000); // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. -- cgit v1.2.3 From 171ca7745e77c9f78f26556457fe64e5b2004a75 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Mon, 17 Mar 2014 08:19:54 -0400 Subject: estimatefee / estimatepriority RPC methods New RPC methods: return an estimate of the fee (or priority) a transaction needs to be likely to confirm in a given number of blocks. Mike Hearn created the first version of this method for estimating fees. It works as follows: For transactions that took 1 to N (I picked N=25) blocks to confirm, keep N buckets with at most 100 entries in each recording the fees-per-kilobyte paid by those transactions. (separate buckets are kept for transactions that confirmed because they are high-priority) The buckets are filled as blocks are found, and are saved/restored in a new fee_estiamtes.dat file in the data directory. A few variations on Mike's initial scheme: To estimate the fee needed for a transaction to confirm in X buckets, all of the samples in all of the buckets are used and a median of all of the data is used to make the estimate. For example, imagine 25 buckets each containing the full 100 entries. Those 2,500 samples are sorted, and the estimate of the fee needed to confirm in the very next block is the 50'th-highest-fee-entry in that sorted list; the estimate of the fee needed to confirm in the next two blocks is the 150'th-highest-fee-entry, etc. That algorithm has the nice property that estimates of how much fee you need to pay to get confirmed in block N will always be greater than or equal to the estimate for block N+1. It would clearly be wrong to say "pay 11 uBTC and you'll get confirmed in 3 blocks, but pay 12 uBTC and it will take LONGER". A single block will not contribute more than 10 entries to any one bucket, so a single miner and a large block cannot overwhelm the estimates. --- src/main.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 9d6c01d64..429473d8f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -851,6 +851,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CCoinsView dummy; CCoinsViewCache view(dummy); + int64_t nValueIn = 0; { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(*pcoinsTip, pool); @@ -879,6 +880,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Bring the best block into scope view.GetBestBlock(); + nValueIn = view.GetValueIn(tx); + // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool view.SetBackend(dummy); } @@ -891,7 +894,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // you should add code here to check that the transaction does a // reasonable number of ECDSA signature verifications. - int64_t nValueIn = view.GetValueIn(tx); int64_t nValueOut = tx.GetValueOut(); int64_t nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); @@ -2017,11 +2019,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { return false; // Remove conflicting transactions from the mempool. list txConflicted; - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - list unused; - mempool.remove(tx, unused); - mempool.removeConflicts(tx, txConflicted); - } + mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted); mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); -- cgit v1.2.3