Skip to content

Commit 3515612

Browse files
author
MarcoFalke
committed
Merge #15473: bench: Benchmark MempoolToJSON
fa38535 bench: Benchmark MempoolToJSON (MarcoFalke) fa5dc35 rpc: Pass mempool into MempoolToJSON (MarcoFalke) Pull request description: This is used in production (e.g. https://jochen-hoenicke.de/queue/#0,24h), so add a benchmark to avoid making it even slower. Related: * "getrawmempool true RPC call is O(n^2)" #14765 Tree-SHA512: da09d2e54ee261af8671152f97f863cf1acd7a6adc6578e94046b1ec9e647a670c67499760ef765254f65522dfdf773c3c8729006fa2d63ccb6d53166bafc425
2 parents df36ddf + fa38535 commit 3515612

File tree

10 files changed

+83
-38
lines changed

10 files changed

+83
-38
lines changed

build_msvc/bench_bitcoin/bench_bitcoin.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<ClCompile Include="..\..\src\bench\examples.cpp" />
3333
<ClCompile Include="..\..\src\bench\lockedpool.cpp" />
3434
<ClCompile Include="..\..\src\bench\mempool_eviction.cpp" />
35+
<ClCompile Include="..\..\src\bench\rpc_mempool.cpp" />
3536
<ClCompile Include="..\..\src\bench\merkle_root.cpp" />
3637
<ClCompile Include="..\..\src\bench\rollingbloom.cpp" />
3738
<ClCompile Include="..\..\src\bench\verify_script.cpp" />

src/Makefile.bench.include

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ bench_bench_bitcoin_SOURCES = \
2626
bench/gcs_filter.cpp \
2727
bench/merkle_root.cpp \
2828
bench/mempool_eviction.cpp \
29+
bench/rpc_mempool.cpp \
2930
bench/verify_script.cpp \
3031
bench/base58.cpp \
3132
bench/bech32.cpp \
@@ -37,6 +38,7 @@ nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
3738
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
3839
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
3940
bench_bench_bitcoin_LDADD = \
41+
$(LIBBITCOIN_SERVER) \
4042
$(LIBBITCOIN_WALLET) \
4143
$(LIBBITCOIN_SERVER) \
4244
$(LIBBITCOIN_COMMON) \
@@ -47,7 +49,9 @@ bench_bench_bitcoin_LDADD = \
4749
$(LIBLEVELDB_SSE42) \
4850
$(LIBMEMENV) \
4951
$(LIBSECP256K1) \
50-
$(LIBUNIVALUE)
52+
$(LIBUNIVALUE) \
53+
$(EVENT_PTHREADS_LIBS) \
54+
$(EVENT_LIBS)
5155

5256
if ENABLE_ZMQ
5357
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)

src/bench/rpc_mempool.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2011-2019 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <bench/bench.h>
6+
#include <policy/policy.h>
7+
#include <rpc/blockchain.h>
8+
#include <txmempool.h>
9+
10+
#include <univalue.h>
11+
12+
#include <list>
13+
#include <vector>
14+
15+
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
16+
{
17+
LockPoints lp;
18+
pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
19+
}
20+
21+
static void RpcMempool(benchmark::State& state)
22+
{
23+
CTxMemPool pool;
24+
LOCK2(cs_main, pool.cs);
25+
26+
for (int i = 0; i < 1000; ++i) {
27+
CMutableTransaction tx = CMutableTransaction();
28+
tx.vin.resize(1);
29+
tx.vin[0].scriptSig = CScript() << OP_1;
30+
tx.vin[0].scriptWitness.stack.push_back({1});
31+
tx.vout.resize(1);
32+
tx.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
33+
tx.vout[0].nValue = i;
34+
const CTransactionRef tx_r{MakeTransactionRef(tx)};
35+
AddTx(tx_r, /* fee */ i, pool);
36+
}
37+
38+
while (state.KeepRunning()) {
39+
(void)MempoolToJSON(pool, /*verbose*/ true);
40+
}
41+
}
42+
43+
BENCHMARK(RpcMempool, 40);

src/policy/rbf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bool SignalsOptInRBF(const CTransaction &tx)
1414
return false;
1515
}
1616

17-
RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool)
17+
RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
1818
{
1919
AssertLockHeld(pool.cs);
2020

src/policy/rbf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ bool SignalsOptInRBF(const CTransaction &tx);
2323
// according to BIP 125
2424
// This involves checking sequence numbers of the transaction, as well
2525
// as the sequence numbers of all in-mempool ancestors.
26-
RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
26+
RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
2727

2828
#endif // BITCOIN_POLICY_RBF_H

src/rest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
300300

301301
switch (rf) {
302302
case RetFormat::JSON: {
303-
UniValue mempoolInfoObject = mempoolInfoToJSON();
303+
UniValue mempoolInfoObject = MempoolInfoToJSON(::mempool);
304304

305305
std::string strJSON = mempoolInfoObject.write() + "\n";
306306
req->WriteHeader("Content-Type", "application/json");
@@ -322,7 +322,7 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar
322322

323323
switch (rf) {
324324
case RetFormat::JSON: {
325-
UniValue mempoolObject = mempoolToJSON(true);
325+
UniValue mempoolObject = MempoolToJSON(::mempool, true);
326326

327327
std::string strJSON = mempoolObject.write() + "\n";
328328
req->WriteHeader("Content-Type", "application/json");

src/rpc/blockchain.cpp

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,9 @@ static std::string EntryDescriptionString()
405405
" \"bip125-replaceable\" : true|false, (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee)\n";
406406
}
407407

408-
static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs)
408+
static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
409409
{
410-
AssertLockHeld(mempool.cs);
410+
AssertLockHeld(pool.cs);
411411

412412
UniValue fees(UniValue::VOBJ);
413413
fees.pushKV("base", ValueFromAmount(e.GetFee()));
@@ -427,12 +427,12 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
427427
info.pushKV("ancestorcount", e.GetCountWithAncestors());
428428
info.pushKV("ancestorsize", e.GetSizeWithAncestors());
429429
info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
430-
info.pushKV("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString());
430+
info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
431431
const CTransaction& tx = e.GetTx();
432432
std::set<std::string> setDepends;
433433
for (const CTxIn& txin : tx.vin)
434434
{
435-
if (mempool.exists(txin.prevout.hash))
435+
if (pool.exists(txin.prevout.hash))
436436
setDepends.insert(txin.prevout.hash.ToString());
437437
}
438438

@@ -445,8 +445,8 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
445445
info.pushKV("depends", depends);
446446

447447
UniValue spent(UniValue::VARR);
448-
const CTxMemPool::txiter &it = mempool.mapTx.find(tx.GetHash());
449-
const CTxMemPool::setEntries &setChildren = mempool.GetMemPoolChildren(it);
448+
const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
449+
const CTxMemPool::setEntries& setChildren = pool.GetMemPoolChildren(it);
450450
for (CTxMemPool::txiter childiter : setChildren) {
451451
spent.push_back(childiter->GetTx().GetHash().ToString());
452452
}
@@ -455,7 +455,7 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
455455

456456
// Add opt-in RBF status
457457
bool rbfStatus = false;
458-
RBFTransactionState rbfState = IsRBFOptIn(tx, mempool);
458+
RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
459459
if (rbfState == RBFTransactionState::UNKNOWN) {
460460
throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
461461
} else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
@@ -465,25 +465,21 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
465465
info.pushKV("bip125-replaceable", rbfStatus);
466466
}
467467

468-
UniValue mempoolToJSON(bool fVerbose)
468+
UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose)
469469
{
470-
if (fVerbose)
471-
{
472-
LOCK(mempool.cs);
470+
if (verbose) {
471+
LOCK(pool.cs);
473472
UniValue o(UniValue::VOBJ);
474-
for (const CTxMemPoolEntry& e : mempool.mapTx)
475-
{
473+
for (const CTxMemPoolEntry& e : pool.mapTx) {
476474
const uint256& hash = e.GetTx().GetHash();
477475
UniValue info(UniValue::VOBJ);
478-
entryToJSON(info, e);
476+
entryToJSON(pool, info, e);
479477
o.pushKV(hash.ToString(), info);
480478
}
481479
return o;
482-
}
483-
else
484-
{
480+
} else {
485481
std::vector<uint256> vtxid;
486-
mempool.queryHashes(vtxid);
482+
pool.queryHashes(vtxid);
487483

488484
UniValue a(UniValue::VARR);
489485
for (const uint256& hash : vtxid)
@@ -525,7 +521,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
525521
if (!request.params[0].isNull())
526522
fVerbose = request.params[0].get_bool();
527523

528-
return mempoolToJSON(fVerbose);
524+
return MempoolToJSON(::mempool, fVerbose);
529525
}
530526

531527
static UniValue getmempoolancestors(const JSONRPCRequest& request)
@@ -591,7 +587,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
591587
const CTxMemPoolEntry &e = *ancestorIt;
592588
const uint256& _hash = e.GetTx().GetHash();
593589
UniValue info(UniValue::VOBJ);
594-
entryToJSON(info, e);
590+
entryToJSON(::mempool, info, e);
595591
o.pushKV(_hash.ToString(), info);
596592
}
597593
return o;
@@ -661,7 +657,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
661657
const CTxMemPoolEntry &e = *descendantIt;
662658
const uint256& _hash = e.GetTx().GetHash();
663659
UniValue info(UniValue::VOBJ);
664-
entryToJSON(info, e);
660+
entryToJSON(::mempool, info, e);
665661
o.pushKV(_hash.ToString(), info);
666662
}
667663
return o;
@@ -700,7 +696,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
700696

701697
const CTxMemPoolEntry &e = *it;
702698
UniValue info(UniValue::VOBJ);
703-
entryToJSON(info, e);
699+
entryToJSON(::mempool, info, e);
704700
return info;
705701
}
706702

@@ -1485,15 +1481,15 @@ static UniValue getchaintips(const JSONRPCRequest& request)
14851481
return res;
14861482
}
14871483

1488-
UniValue mempoolInfoToJSON()
1484+
UniValue MempoolInfoToJSON(const CTxMemPool& pool)
14891485
{
14901486
UniValue ret(UniValue::VOBJ);
1491-
ret.pushKV("size", (int64_t) mempool.size());
1492-
ret.pushKV("bytes", (int64_t) mempool.GetTotalTxSize());
1493-
ret.pushKV("usage", (int64_t) mempool.DynamicMemoryUsage());
1487+
ret.pushKV("size", (int64_t)pool.size());
1488+
ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
1489+
ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
14941490
size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
14951491
ret.pushKV("maxmempool", (int64_t) maxmempool);
1496-
ret.pushKV("mempoolminfee", ValueFromAmount(std::max(mempool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
1492+
ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
14971493
ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
14981494

14991495
return ret;
@@ -1522,7 +1518,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
15221518
},
15231519
}.ToString());
15241520

1525-
return mempoolInfoToJSON();
1521+
return MempoolInfoToJSON(::mempool);
15261522
}
15271523

15281524
static UniValue preciousblock(const JSONRPCRequest& request)

src/rpc/blockchain.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
class CBlock;
1313
class CBlockIndex;
14+
class CTxMemPool;
1415
class UniValue;
1516

1617
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
@@ -30,10 +31,10 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
3031
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false);
3132

3233
/** Mempool information to JSON */
33-
UniValue mempoolInfoToJSON();
34+
UniValue MempoolInfoToJSON(const CTxMemPool& pool);
3435

3536
/** Mempool to JSON */
36-
UniValue mempoolToJSON(bool fVerbose = false);
37+
UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false);
3738

3839
/** Block header to JSON */
3940
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex);

src/txmempool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::Get
764764
return iters;
765765
}
766766

767-
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
767+
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
768768
{
769769
LOCK(cs);
770770
auto iters = GetSortedDepthAndScore();

src/txmempool.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ struct update_lock_points
184184
const LockPoints& lp;
185185
};
186186

187-
// extracts a transaction hash from CTxMempoolEntry or CTransactionRef
187+
// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef
188188
struct mempoolentry_txid
189189
{
190190
typedef uint256 result_type;
@@ -588,7 +588,7 @@ class CTxMemPool
588588
void clear();
589589
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
590590
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
591-
void queryHashes(std::vector<uint256>& vtxid);
591+
void queryHashes(std::vector<uint256>& vtxid) const;
592592
bool isSpent(const COutPoint& outpoint) const;
593593
unsigned int GetTransactionsUpdated() const;
594594
void AddTransactionsUpdated(unsigned int n);

0 commit comments

Comments
 (0)