diff options
author | MarcoFalke <falke.marco@gmail.com> | 2019-12-16 16:02:53 -0500 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2019-12-16 16:05:06 -0500 |
commit | 48d64d73c06f4d5db3ad35bed87388ff0795d511 (patch) | |
tree | a38549f55e4108b7a95cf0d64f1283296c99ee5e | |
parent | 988eaf2fcb71284c5fc57c7ef755bdafa4b929a0 (diff) | |
parent | fa8e650b525e9493bdfa393c0c3e34cb22c78c08 (diff) | |
download | bitcoin-48d64d73c06f4d5db3ad35bed87388ff0795d511.tar.xz |
Merge #17564: rpc: Use mempool from node context instead of global
fa8e650b525e9493bdfa393c0c3e34cb22c78c08 rest: Use mempool from node context instead of global (MarcoFalke)
fa660d65d7cc401ad5bbfdc076a074de19a79329 node: Use mempool from node context instead of global (MarcoFalke)
facbaf092f1ab298943206603cff6e6e3d30d452 rpc: Use mempool from node context instead of global (MarcoFalke)
Pull request description:
Currently they are identical, but in the future we might want to turn
the mempool into a unique_ptr. Replacing the global with the mempool
pointer from the node context simplifies this step.
ACKs for top commit:
jnewbery:
Code review ACK fa8e650b5
ryanofsky:
Code review ACK fa8e650b525e9493bdfa393c0c3e34cb22c78c08, Only the discussed REST server changes since the last review.
Tree-SHA512: 0836f3f39cf90306455962918446e5f8612e88c32072b92afc30929aea1f17430bbda0e2b3668d36c9d6b97d63a93cf4903185194571108642b7bf5a39b89125
-rw-r--r-- | src/interfaces/chain.cpp | 2 | ||||
-rw-r--r-- | src/interfaces/node.cpp | 4 | ||||
-rw-r--r-- | src/node/coin.cpp | 8 | ||||
-rw-r--r-- | src/node/coin.h | 4 | ||||
-rw-r--r-- | src/node/transaction.cpp | 5 | ||||
-rw-r--r-- | src/qt/test/wallettests.cpp | 1 | ||||
-rw-r--r-- | src/rest.cpp | 39 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 20 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 6 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 5 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 4 |
11 files changed, 68 insertions, 30 deletions
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 26856a00d3..ac640aa35a 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -263,7 +263,7 @@ public: } return true; } - void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); } + void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); } double guessVerificationProgress(const uint256& block_hash) override { LOCK(cs_main); diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 1877c92178..24695c1afc 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -167,8 +167,8 @@ public: } int64_t getTotalBytesRecv() override { return m_context.connman ? m_context.connman->GetTotalBytesRecv() : 0; } int64_t getTotalBytesSent() override { return m_context.connman ? m_context.connman->GetTotalBytesSent() : 0; } - size_t getMempoolSize() override { return ::mempool.size(); } - size_t getMempoolDynamicUsage() override { return ::mempool.DynamicMemoryUsage(); } + size_t getMempoolSize() override { return m_context.mempool ? m_context.mempool->size() : 0; } + size_t getMempoolDynamicUsage() override { return m_context.mempool ? m_context.mempool->DynamicMemoryUsage() : 0; } bool getHeaderTip(int& height, int64_t& block_time) override { LOCK(::cs_main); diff --git a/src/node/coin.cpp b/src/node/coin.cpp index ad8d1d3af4..f4f86cdbe9 100644 --- a/src/node/coin.cpp +++ b/src/node/coin.cpp @@ -4,14 +4,16 @@ #include <node/coin.h> +#include <node/context.h> #include <txmempool.h> #include <validation.h> -void FindCoins(std::map<COutPoint, Coin>& coins) +void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins) { - LOCK2(cs_main, ::mempool.cs); + assert(node.mempool); + LOCK2(cs_main, node.mempool->cs); CCoinsViewCache& chain_view = ::ChainstateActive().CoinsTip(); - CCoinsViewMemPool mempool_view(&chain_view, ::mempool); + CCoinsViewMemPool mempool_view(&chain_view, *node.mempool); for (auto& coin : coins) { if (!mempool_view.GetCoin(coin.first, coin.second)) { // Either the coin is not in the CCoinsViewCache or is spent. Clear it. diff --git a/src/node/coin.h b/src/node/coin.h index eb95b75cfb..908850e2a5 100644 --- a/src/node/coin.h +++ b/src/node/coin.h @@ -9,14 +9,16 @@ class COutPoint; class Coin; +struct NodeContext; /** * Look up unspent output information. Returns coins in the mempool and in the * current chain UTXO set. Iterates through all the keys in the map and * populates the values. * + * @param[in] node The node context to use for lookup * @param[in,out] coins map to fill */ -void FindCoins(std::map<COutPoint, Coin>& coins); +void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins); #endif // BITCOIN_NODE_COIN_H diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 3c0df2b26e..5e2e502015 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -20,6 +20,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t // node.connman is assigned both before chain clients and before RPC server is accepting calls, // and reset after chain clients and RPC sever are stopped. node.connman should never be null here. assert(node.connman); + assert(node.mempool); std::promise<void> promise; uint256 hashTx = tx->GetHash(); bool callback_set = false; @@ -35,10 +36,10 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t // So if the output does exist, then this transaction exists in the chain. if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN; } - if (!mempool.exists(hashTx)) { + if (!node.mempool->exists(hashTx)) { // Transaction is not already in the mempool. Submit it. TxValidationState state; - if (!AcceptToMemoryPool(mempool, state, std::move(tx), + if (!AcceptToMemoryPool(*node.mempool, state, std::move(tx), nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) { err_string = FormatStateMessage(state); if (state.IsInvalid()) { diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index dfd56511ea..f6d2816ff8 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -134,6 +134,7 @@ void TestGUI(interfaces::Node& node) test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } node.context()->connman = std::move(test.m_node.connman); + node.context()->mempool = std::move(test.m_node.mempool); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), WalletDatabase::CreateMock()); bool firstRun; wallet->LoadWallet(firstRun); diff --git a/src/rest.cpp b/src/rest.cpp index 228c122de3..55756ecfdf 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -8,6 +8,7 @@ #include <core_io.h> #include <httpserver.h> #include <index/txindex.h> +#include <node/context.h> #include <primitives/block.h> #include <primitives/transaction.h> #include <rpc/blockchain.h> @@ -16,6 +17,7 @@ #include <streams.h> #include <sync.h> #include <txmempool.h> +#include <util/check.h> #include <util/strencodings.h> #include <validation.h> #include <version.h> @@ -69,6 +71,24 @@ static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string me return false; } +/** + * Get the node context mempool. + * + * Set the HTTP error and return nullptr if node context + * mempool is not found. + * + * @param[in] req the HTTP request + * return pointer to the mempool or nullptr if no mempool found + */ +static CTxMemPool* GetMemPool(HTTPRequest* req) +{ + if (!g_rpc_node || !g_rpc_node->mempool) { + RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found"); + return nullptr; + } + return g_rpc_node->mempool; +} + static RetFormat ParseDataFormat(std::string& param, const std::string& strReq) { const std::string::size_type pos = strReq.rfind('.'); @@ -295,12 +315,14 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; + const CTxMemPool* mempool = GetMemPool(req); + if (!mempool) return false; std::string param; const RetFormat rf = ParseDataFormat(param, strURIPart); switch (rf) { case RetFormat::JSON: { - UniValue mempoolInfoObject = MempoolInfoToJSON(::mempool); + UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool); std::string strJSON = mempoolInfoObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -315,14 +337,15 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart) { - if (!CheckWarmup(req)) - return false; + if (!CheckWarmup(req)) return false; + const CTxMemPool* mempool = GetMemPool(req); + if (!mempool) return false; std::string param; const RetFormat rf = ParseDataFormat(param, strURIPart); switch (rf) { case RetFormat::JSON: { - UniValue mempoolObject = MempoolToJSON(::mempool, true); + UniValue mempoolObject = MempoolToJSON(*mempool, true); std::string strJSON = mempoolObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -500,11 +523,13 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) }; if (fCheckMemPool) { + const CTxMemPool* mempool = GetMemPool(req); + if (!mempool) return false; // use db+mempool as cache backend in case user likes to query mempool - LOCK2(cs_main, mempool.cs); + LOCK2(cs_main, mempool->cs); CCoinsViewCache& viewChain = ::ChainstateActive().CoinsTip(); - CCoinsViewMemPool viewMempool(&viewChain, mempool); - process_utxos(viewMempool, mempool); + CCoinsViewMemPool viewMempool(&viewChain, *mempool); + process_utxos(viewMempool, *mempool); } else { LOCK(cs_main); // no need to lock mempool! process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool()); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 44f5326b3c..02f610d841 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -528,7 +528,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request) if (!request.params[0].isNull()) fVerbose = request.params[0].get_bool(); - return MempoolToJSON(::mempool, fVerbose); + return MempoolToJSON(EnsureMemPool(), fVerbose); } static UniValue getmempoolancestors(const JSONRPCRequest& request) @@ -566,6 +566,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) uint256 hash = ParseHashV(request.params[0], "parameter 1"); + const CTxMemPool& mempool = EnsureMemPool(); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(hash); @@ -591,7 +592,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) const CTxMemPoolEntry &e = *ancestorIt; const uint256& _hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); - entryToJSON(::mempool, info, e); + entryToJSON(mempool, info, e); o.pushKV(_hash.ToString(), info); } return o; @@ -633,6 +634,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) uint256 hash = ParseHashV(request.params[0], "parameter 1"); + const CTxMemPool& mempool = EnsureMemPool(); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(hash); @@ -658,7 +660,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) const CTxMemPoolEntry &e = *descendantIt; const uint256& _hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); - entryToJSON(::mempool, info, e); + entryToJSON(mempool, info, e); o.pushKV(_hash.ToString(), info); } return o; @@ -685,6 +687,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) uint256 hash = ParseHashV(request.params[0], "parameter 1"); + const CTxMemPool& mempool = EnsureMemPool(); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(hash); @@ -694,7 +697,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) const CTxMemPoolEntry &e = *it; UniValue info(UniValue::VOBJ); - entryToJSON(::mempool, info, e); + entryToJSON(mempool, info, e); return info; } @@ -1070,6 +1073,7 @@ UniValue gettxout(const JSONRPCRequest& request) CCoinsViewCache* coins_view = &::ChainstateActive().CoinsTip(); if (fMempool) { + const CTxMemPool& mempool = EnsureMemPool(); LOCK(mempool.cs); CCoinsViewMemPool view(coins_view, mempool); if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { @@ -1448,7 +1452,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) }, }.Check(request); - return MempoolInfoToJSON(::mempool); + return MempoolInfoToJSON(EnsureMemPool()); } static UniValue preciousblock(const JSONRPCRequest& request) @@ -1964,11 +1968,13 @@ static UniValue savemempool(const JSONRPCRequest& request) }, }.Check(request); - if (!::mempool.IsLoaded()) { + const CTxMemPool& mempool = EnsureMemPool(); + + if (!mempool.IsLoaded()) { throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet"); } - if (!DumpMempool(::mempool)) { + if (!DumpMempool(mempool)) { throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk"); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index fc16a31423..5017e5b9d9 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -244,6 +244,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request) }.Check(request); LOCK(cs_main); + const CTxMemPool& mempool = EnsureMemPool(); UniValue obj(UniValue::VOBJ); obj.pushKV("blocks", (int)::ChainActive().Height()); @@ -290,7 +291,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0."); } - mempool.PrioritiseTransaction(hash, nAmount); + EnsureMemPool().PrioritiseTransaction(hash, nAmount); return true; } @@ -476,6 +477,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); static unsigned int nTransactionsUpdatedLast; + const CTxMemPool& mempool = EnsureMemPool(); if (!lpval.isNull()) { @@ -510,7 +512,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) { // Timeout: Check transactions for update - // without holding ::mempool.cs to avoid deadlocks + // without holding the mempool lock to avoid deadlocks if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; checktxtime += std::chrono::seconds(10); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index b816a54d2f..5be7acce1c 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -636,6 +636,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { + const CTxMemPool& mempool = EnsureMemPool(); LOCK(cs_main); LOCK(mempool.cs); CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); @@ -758,7 +759,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) for (const CTxIn& txin : mtx.vin) { coins[txin.prevout]; // Create empty map entry keyed by prevout. } - FindCoins(coins); + FindCoins(*g_rpc_node, coins); // Parse the prevtxs array ParsePrevouts(request.params[2], &keystore, coins); @@ -890,6 +891,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) max_raw_tx_fee_rate = CFeeRate(AmountFromValue(request.params[1])); } + CTxMemPool& mempool = EnsureMemPool(); int64_t virtual_size = GetVirtualTransactionSize(*tx); CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); @@ -1508,6 +1510,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { + const CTxMemPool& mempool = EnsureMemPool(); LOCK2(cs_main, mempool.cs); CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, mempool); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 52dd22de7e..84a3980b19 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -112,14 +112,10 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) std::string notsigned = r.get_str(); std::string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\""; std::string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\""; - NodeContext node; - node.chain = interfaces::MakeChain(node); - g_rpc_node = &node; r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" [] "+prevout); BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" ["+privkey1+","+privkey2+"] "+prevout); BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); - g_rpc_node = nullptr; } BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) |