Skip to content

Commit

Permalink
Merge pull request #6722
Browse files Browse the repository at this point in the history
58254aa Fix stale comment in CTxMemPool::TrimToSize. (Matt Corallo)
2bc5018 Fix comment formatting tabs (Matt Corallo)
8abe0f5 Undo GetMinFee-requires-extra-call-to-hit-0 (Matt Corallo)
9e93640 Drop minRelayTxFee to 1000 (Matt Corallo)
074cb15 Add reasonable test case for mempool trimming (Matt Corallo)
d355cf4 Only call TrimToSize once per reorg/blocks disconnect (Matt Corallo)
794a8ce Implement on-the-fly mempool size limitation. (Matt Corallo)
e6c7b36 Print mempool size in KB when adding txn (Matt Corallo)
241d607 Add CFeeRate += operator (Matt Corallo)
e8bcdce Track (and define) ::minRelayTxFee in CTxMemPool (Matt Corallo)
9c9b66f Fix calling mempool directly, instead of pool, in ATMP (Matt Corallo)
49b6fd5 Add Mempool Expire function to remove old transactions (Pieter Wuille)
78b82f4 Reverse the sort on the mempool's feerate index (Suhas Daftuar)
  • Loading branch information
laanwj committed Oct 21, 2015
2 parents c6de5cc + 58254aa commit 3b20e23
Show file tree
Hide file tree
Showing 10 changed files with 361 additions and 57 deletions.
1 change: 1 addition & 0 deletions src/amount.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class CFeeRate
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString() const;

ADD_SERIALIZE_METHODS;
Expand Down
8 changes: 8 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef WIN32
Expand Down Expand Up @@ -840,6 +842,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = GetBoolArg("-checkpoints", true);

// -mempoollimit limits
int64_t nMempoolSizeLimit = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nMempoolDescendantSizeLimit = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
if (nMempoolSizeLimit < 0 || nMempoolSizeLimit < nMempoolDescendantSizeLimit * 40)
return InitError(strprintf(_("Error: -maxmempool must be at least %d MB"), GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25));

// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (nScriptCheckThreads <= 0)
Expand Down
58 changes: 38 additions & 20 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;

/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(5000);
CFeeRate minRelayTxFee = CFeeRate(1000);

CTxMemPool mempool(::minRelayTxFee);

Expand Down Expand Up @@ -740,17 +740,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return true;
}

CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned int nBytes, bool fAllowFree)
{
{
LOCK(mempool.cs);
uint256 hash = tx.GetHash();
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (dPriorityDelta > 0 || nFeeDelta > 0)
return 0;
}
uint256 hash = tx.GetHash();
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
pool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (dPriorityDelta > 0 || nFeeDelta > 0)
return 0;

CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);

Expand Down Expand Up @@ -779,7 +776,7 @@ static std::string FormatStateMessage(const CValidationState &state)
}

bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee)
bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
Expand Down Expand Up @@ -879,17 +876,20 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
CAmount nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());

CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx));
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx));
unsigned int nSize = entry.GetTxSize();

// Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
CAmount txMinFee = GetMinRelayFee(tx, pool, nSize, true);
if (fLimitFree && nFees < txMinFee)
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
strprintf("%d < %d", nFees, txMinFee));

// Require that free transactions have sufficient priority to be mined in the next block.
if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
} else if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}

Expand Down Expand Up @@ -954,6 +954,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa

// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());

// trim mempool and check if tx was trimmed
if (!fOverrideMempoolLimit) {
int expired = pool.Expire(GetTime() - GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
if (expired != 0)
LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);

pool.TrimToSize(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
if (!pool.exists(tx.GetHash()))
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full");
}
}

SyncWithWallets(tx, NULL);
Expand Down Expand Up @@ -2020,7 +2031,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
}
}

/** Disconnect chainActive's tip. */
/** Disconnect chainActive's tip. You want to manually re-limit mempool size after this */
bool static DisconnectTip(CValidationState &state) {
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
Expand All @@ -2047,7 +2058,7 @@ bool static DisconnectTip(CValidationState &state) {
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) {
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
mempool.remove(tx, removed, true);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
Expand Down Expand Up @@ -2220,9 +2231,11 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);

// Disconnect active blocks which are no longer in the best chain.
bool fBlocksDisconnected = false;
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
if (!DisconnectTip(state))
return false;
fBlocksDisconnected = true;
}

// Build list of new blocks to connect.
Expand Down Expand Up @@ -2268,6 +2281,9 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
}
}

if (fBlocksDisconnected)
mempool.TrimToSize(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);

// Callbacks/notifications for a new best chain.
if (fInvalidFound)
CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
Expand Down Expand Up @@ -2354,6 +2370,8 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) {
}
}

mempool.TrimToSize(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);

// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add it again.
BlockMap::iterator it = mapBlockIndex.begin();
Expand Down Expand Up @@ -4290,10 +4308,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);

LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u)\n",
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
pfrom->id,
tx.GetHash().ToString(),
mempool.size());
mempool.size(), mempool.DynamicMemoryUsage() / 1000);

// Recursively process any orphan transactions that depended on this one
set<NodeId> setMisbehaving;
Expand Down
6 changes: 5 additions & 1 deletion src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 900;
static const unsigned int DEFAULT_DESCENDANT_LIMIT = 1000;
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 2500;
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
Expand Down Expand Up @@ -225,7 +229,7 @@ void PruneAndFlush();

/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
bool* pfMissingInputs, bool fOverrideMempoolLimit=false, bool fRejectAbsurdFee=false);


struct CNodeStateStats {
Expand Down
2 changes: 1 addition & 1 deletion src/rpcrawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) {
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, !fOverrideFees)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
Expand Down
Loading

0 comments on commit 3b20e23

Please sign in to comment.