diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -26,6 +26,7 @@ bench/gcs_filter.cpp \ bench/merkle_root.cpp \ bench/mempool_eviction.cpp \ + bench/rpc_mempool.cpp \ bench/base58.cpp \ bench/lockedpool.cpp \ bench/prevector.cpp @@ -45,7 +46,9 @@ $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ $(LIBSECP256K1) \ - $(LIBUNIVALUE) + $(LIBUNIVALUE) \ + $(EVENT_PTHREADS_LIBS) \ + $(EVENT_LIBS) if ENABLE_ZMQ bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt --- a/src/bench/CMakeLists.txt +++ b/src/bench/CMakeLists.txt @@ -51,6 +51,7 @@ merkle_root.cpp prevector.cpp rollingbloom.cpp + rpc_mempool.cpp # Add the generated headers to trigger the conversion command ${BENCH_DATA_GENERATED_HEADERS} diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp new file mode 100644 --- /dev/null +++ b/src/bench/rpc_mempool.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2011-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include + +#include +#include + +static void AddTx(const CTransactionRef &tx, const Amount &fee, + CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) { + LockPoints lp; + pool.addUnchecked(tx->GetId(), + CTxMemPoolEntry(tx, fee, /* time */ 0, /*priority*/ 10.0, + /* height */ 1, tx->GetValueOut(), + /* spendsCoinbase */ false, + /* sigOpCost */ 4, lp)); +} + +static void RpcMempool(benchmark::State &state) { + CTxMemPool pool; + LOCK2(cs_main, pool.cs); + + for (int i = 0; i < 1000; ++i) { + CMutableTransaction tx = CMutableTransaction(); + tx.vin.resize(1); + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout.resize(1); + tx.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; + tx.vout[0].nValue = i * CENT; + const CTransactionRef tx_r{MakeTransactionRef(tx)}; + AddTx(tx_r, /* fee */ i * CENT, pool); + } + + while (state.KeepRunning()) { + (void)MempoolToJSON(pool, /*verbose*/ true); + } +} + +BENCHMARK(RpcMempool, 40); diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -330,7 +330,7 @@ switch (rf) { case RetFormat::JSON: { - UniValue mempoolInfoObject = mempoolInfoToJSON(); + UniValue mempoolInfoObject = MempoolInfoToJSON(::g_mempool); std::string strJSON = mempoolInfoObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -355,7 +355,7 @@ switch (rf) { case RetFormat::JSON: { - UniValue mempoolObject = mempoolToJSON(true); + UniValue mempoolObject = MempoolToJSON(::g_mempool, true); std::string strJSON = mempoolObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -10,6 +10,7 @@ class CBlock; class CBlockIndex; class Config; +class CTxMemPool; class JSONRPCRequest; UniValue getblockchaininfo(const Config &config, const JSONRPCRequest &request); @@ -30,10 +31,10 @@ const CBlockIndex *blockindex, bool txDetails = false); /** Mempool information to JSON */ -UniValue mempoolInfoToJSON(); +UniValue MempoolInfoToJSON(const CTxMemPool &pool); /** Mempool to JSON */ -UniValue mempoolToJSON(bool fVerbose = false); +UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose = false); /** Block header to JSON */ UniValue blockheaderToJSON(const CBlockIndex *tip, diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -457,9 +457,10 @@ " ... ]\n"; } -static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) - EXCLUSIVE_LOCKS_REQUIRED(g_mempool.cs) { - AssertLockHeld(g_mempool.cs); +static void entryToJSON(const CTxMemPool &pool, UniValue &info, + const CTxMemPoolEntry &e) + EXCLUSIVE_LOCKS_REQUIRED(pool.cs) { + AssertLockHeld(pool.cs); UniValue fees(UniValue::VOBJ); fees.pushKV("base", ValueFromAmount(e.GetFee())); @@ -484,7 +485,7 @@ const CTransaction &tx = e.GetTx(); std::set setDepends; for (const CTxIn &txin : tx.vin) { - if (g_mempool.exists(txin.prevout.GetTxId())) { + if (pool.exists(txin.prevout.GetTxId())) { setDepends.insert(txin.prevout.GetTxId().ToString()); } } @@ -497,9 +498,8 @@ info.pushKV("depends", depends); UniValue spent(UniValue::VARR); - const CTxMemPool::txiter &it = g_mempool.mapTx.find(tx.GetId()); - const CTxMemPool::setEntries &setChildren = - g_mempool.GetMemPoolChildren(it); + const CTxMemPool::txiter &it = pool.mapTx.find(tx.GetId()); + const CTxMemPool::setEntries &setChildren = pool.GetMemPoolChildren(it); for (CTxMemPool::txiter childiter : setChildren) { spent.push_back(childiter->GetTx().GetId().ToString()); } @@ -507,20 +507,20 @@ info.pushKV("spentby", spent); } -UniValue mempoolToJSON(bool fVerbose) { - if (fVerbose) { - LOCK(g_mempool.cs); +UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose) { + if (verbose) { + LOCK(pool.cs); UniValue o(UniValue::VOBJ); - for (const CTxMemPoolEntry &e : g_mempool.mapTx) { + for (const CTxMemPoolEntry &e : pool.mapTx) { const uint256 &txid = e.GetTx().GetId(); UniValue info(UniValue::VOBJ); - entryToJSON(info, e); + entryToJSON(pool, info, e); o.pushKV(txid.ToString(), info); } return o; } else { std::vector vtxids; - g_mempool.queryHashes(vtxids); + pool.queryHashes(vtxids); UniValue a(UniValue::VARR); for (const uint256 &txid : vtxids) { @@ -564,7 +564,7 @@ fVerbose = request.params[0].get_bool(); } - return mempoolToJSON(fVerbose); + return MempoolToJSON(::g_mempool, fVerbose); } static UniValue getmempoolancestors(const Config &config, @@ -630,7 +630,7 @@ const CTxMemPoolEntry &e = *ancestorIt; const uint256 &_hash = e.GetTx().GetId(); UniValue info(UniValue::VOBJ); - entryToJSON(info, e); + entryToJSON(::g_mempool, info, e); o.pushKV(_hash.ToString(), info); } return o; @@ -699,7 +699,7 @@ const CTxMemPoolEntry &e = *descendantIt; const uint256 &_hash = e.GetTx().GetId(); UniValue info(UniValue::VOBJ); - entryToJSON(info, e); + entryToJSON(::g_mempool, info, e); o.pushKV(_hash.ToString(), info); } return o; @@ -736,7 +736,7 @@ const CTxMemPoolEntry &e = *it; UniValue info(UniValue::VOBJ); - entryToJSON(info, e); + entryToJSON(::g_mempool, info, e); return info; } @@ -1485,18 +1485,18 @@ return res; } -UniValue mempoolInfoToJSON() { +UniValue MempoolInfoToJSON(const CTxMemPool &pool) { UniValue ret(UniValue::VOBJ); - ret.pushKV("size", (int64_t)g_mempool.size()); - ret.pushKV("bytes", (int64_t)g_mempool.GetTotalTxSize()); - ret.pushKV("usage", (int64_t)g_mempool.DynamicMemoryUsage()); + ret.pushKV("size", (int64_t)pool.size()); + ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize()); + ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage()); size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; ret.pushKV("maxmempool", (int64_t)maxmempool); - ret.pushKV("mempoolminfee", - ValueFromAmount( - std::max(g_mempool.GetMinFee(maxmempool), ::minRelayTxFee) - .GetFeePerK())); + ret.pushKV( + "mempoolminfee", + ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee) + .GetFeePerK())); ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); return ret; @@ -1528,7 +1528,7 @@ HelpExampleRpc("getmempoolinfo", "")); } - return mempoolInfoToJSON(); + return MempoolInfoToJSON(::g_mempool); } static UniValue preciousblock(const Config &config, diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -225,7 +225,7 @@ const LockPoints &lp; }; -// extracts a transaction hash from CTxMempoolEntry or CTransactionRef +// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef struct mempoolentry_txid { typedef uint256 result_type; result_type operator()(const CTxMemPoolEntry &entry) const { @@ -645,7 +645,7 @@ // lock free void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); bool CompareDepthAndScore(const uint256 &hasha, const uint256 &hashb); - void queryHashes(std::vector &vtxid); + void queryHashes(std::vector &vtxid) const; bool isSpent(const COutPoint &outpoint) const; unsigned int GetTransactionsUpdated() const; void AddTransactionsUpdated(unsigned int n); diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -871,7 +871,7 @@ return iters; } -void CTxMemPool::queryHashes(std::vector &vtxid) { +void CTxMemPool::queryHashes(std::vector &vtxid) const { LOCK(cs); auto iters = GetSortedDepthAndScore();