From 6f2c26a457d279138d23d0f321edf55cd6b1f72f Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 6 Aug 2014 23:58:19 -0400 Subject: [PATCH] Closely track mempool byte total. Add "getmempoolinfo" RPC. Goal: Gain live insight into the mempool. Groundwork for future work that caps mempool size. --- src/rpcblockchain.cpp | 24 ++++++++++++++++++++++++ src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + src/txmempool.cpp | 9 +++++++++ src/txmempool.h | 6 ++++++ 5 files changed, 41 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 1e5198b85..e511fe422 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -531,3 +531,27 @@ Value getchaintips(const Array& params, bool fHelp) return res; } + +Value getmempoolinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getmempoolinfo\n" + "\nReturns details on the active state of the TX memory pool.\n" + "\nResult:\n" + "{\n" + " \"size\": xxxxx (numeric) Current tx count\n" + " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getmempoolinfo", "") + + HelpExampleRpc("getmempoolinfo", "") + ); + + Object ret; + ret.push_back(Pair("size", (int64_t) mempool.size())); + ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); + + return ret; +} + diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 56064941f..3b51c91e7 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -256,6 +256,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockhash", &getblockhash, true, false, false }, { "blockchain", "getchaintips", &getchaintips, true, false, false }, { "blockchain", "getdifficulty", &getdifficulty, true, false, false }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false }, { "blockchain", "getrawmempool", &getrawmempool, true, false, false }, { "blockchain", "gettxout", &gettxout, true, false, false }, { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 2248e8aeb..b850d15d4 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -200,6 +200,7 @@ extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool f extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getmempoolinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 29924fff0..80cae6824 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -402,6 +402,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry) for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); nTransactionsUpdated++; + totalTxSize += entry.GetTxSize(); } return true; } @@ -426,6 +427,8 @@ void CTxMemPool::remove(const CTransaction &tx, std::list& removed removed.push_front(tx); BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); + + totalTxSize -= mapTx[hash].GetTxSize(); mapTx.erase(hash); nTransactionsUpdated++; } @@ -477,6 +480,7 @@ void CTxMemPool::clear() LOCK(cs); mapTx.clear(); mapNextTx.clear(); + totalTxSize = 0; ++nTransactionsUpdated; } @@ -487,9 +491,12 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); + uint64_t checkTotal = 0; + LOCK(cs); for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; + checkTotal += it->second.GetTxSize(); const CTransaction& tx = it->second.GetTx(); BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. @@ -518,6 +525,8 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const assert(tx.vin.size() > it->second.n); assert(it->first == it->second.ptx->vin[it->second.n].prevout); } + + assert(totalTxSize == checkTotal); } void CTxMemPool::queryHashes(vector& vtxid) diff --git a/src/txmempool.h b/src/txmempool.h index 41b2c52f3..2577397bc 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -68,6 +68,7 @@ private: CMinerPolicyEstimator* minerPolicyEstimator; CFeeRate minRelayFee; // Passed to constructor to avoid dependency on main + uint64_t totalTxSize; // sum of all mempool tx' byte sizes public: mutable CCriticalSection cs; @@ -108,6 +109,11 @@ public: LOCK(cs); return mapTx.size(); } + uint64_t GetTotalTxSize() + { + LOCK(cs); + return totalTxSize; + } bool exists(uint256 hash) {