Skip to content

Commit ae69436

Browse files
author
MarcoFalke
committed
Merge #17407: node: Add reference to mempool in NodeContext
fa53881 scripted-diff: Replace ::mempool with m_node.mempool in tests (MarcoFalke) 8888ad0 test: Replace recursive lock with locking annotations (MarcoFalke) fac07f2 node: Add reference to mempool in NodeContext (MarcoFalke) Pull request description: This is the first step toward making the mempool a global that is not initialized before main. #### Motivation Currently the mempool is a global that is initialized before the `main` function. This is confusing and easy to get wrong. E.g. the mempool constructor queries state that has not been initialized, like randomness (fixed), or command line arguments (not an issue last time I checked). Also without having the chainstate (chain tip) initialized first, it doesn't make conceptually sense to have a mempool, since the mempool builds txs on top of the utxo set (chain tip). Finally, in the future someone might want to run a consensus-only full node (`-nowallet -noblockfilter -no... -nomempool` command line options) that only verifies blocks and updates the utxo set. This is conceptually the same change that has already been done for the connection manager `CConnman`. ACKs for top commit: jnewbery: utACK fa53881 ariard: Tested ACK fa53881. Tree-SHA512: 2c446a8a51476354aad7126c2b833500d36b24490caa94f847b2bdc622054de0dae28980f23e3d91b1b492dc32931656d98dbd019af9e4e58f2f8c5375aac694
2 parents 5ff798c + fa53881 commit ae69436

File tree

11 files changed

+100
-75
lines changed

11 files changed

+100
-75
lines changed

src/init.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ void Shutdown(NodeContext& node)
284284
GetMainSignals().UnregisterWithMempoolSignals(mempool);
285285
globalVerifyHandle.reset();
286286
ECC_Stop();
287+
if (node.mempool) node.mempool = nullptr;
287288
LogPrintf("%s: done\n", __func__);
288289
}
289290

@@ -1635,6 +1636,11 @@ bool AppInitMain(NodeContext& node)
16351636
return false;
16361637
}
16371638

1639+
// Now that the chain state is loaded, make mempool generally available in the node context. For example the
1640+
// connection manager, wallet, or RPC threads, which are all started after this, may use it from the node context.
1641+
assert(!node.mempool);
1642+
node.mempool = &::mempool;
1643+
16381644
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
16391645
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
16401646
// Allowed to fail as this file IS missing on first startup.

src/node/context.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
class BanMan;
1212
class CConnman;
13+
class CTxMemPool;
1314
class PeerLogicValidation;
1415
namespace interfaces {
1516
class Chain;
@@ -22,13 +23,13 @@ class ChainClient;
2223
//! This is used by init, rpc, and test code to pass object references around
2324
//! without needing to declare the same variables and parameters repeatedly, or
2425
//! to use globals. More variables could be added to this struct (particularly
25-
//! references to validation and mempool objects) to eliminate use of globals
26+
//! references to validation objects) to eliminate use of globals
2627
//! and make code more modular and testable. The struct isn't intended to have
2728
//! any member functions. It should just be a collection of references that can
2829
//! be used without pulling in unwanted dependencies or functionality.
29-
struct NodeContext
30-
{
30+
struct NodeContext {
3131
std::unique_ptr<CConnman> connman;
32+
CTxMemPool* mempool{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
3233
std::unique_ptr<PeerLogicValidation> peer_logic;
3334
std::unique_ptr<BanMan> banman;
3435
std::unique_ptr<interfaces::Chain> chain;

src/qt/test/rpcnestedtests.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ void RPCNestedTests::rpcNestedTests()
3232
// do some test setup
3333
// could be moved to a more generic place when we add more tests on QT level
3434
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
35-
//mempool.setSanityCheck(1.0);
3635

3736
TestingSetup test;
3837

src/rpc/blockchain.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <hash.h>
1616
#include <index/blockfilterindex.h>
1717
#include <node/coinstats.h>
18+
#include <node/context.h>
1819
#include <node/utxo_snapshot.h>
1920
#include <policy/feerate.h>
2021
#include <policy/policy.h>
@@ -53,6 +54,15 @@ static Mutex cs_blockchange;
5354
static std::condition_variable cond_blockchange;
5455
static CUpdatedBlock latestblock;
5556

57+
CTxMemPool& EnsureMemPool()
58+
{
59+
CHECK_NONFATAL(g_rpc_node);
60+
if (!g_rpc_node->mempool) {
61+
throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found");
62+
}
63+
return *g_rpc_node->mempool;
64+
}
65+
5666
/* Calculate the difficulty for a given block index.
5767
*/
5868
double GetDifficulty(const CBlockIndex* blockindex)

src/rpc/blockchain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,6 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
5252
//! direct way to pass in state to RPC methods without globals.
5353
extern NodeContext* g_rpc_node;
5454

55+
CTxMemPool& EnsureMemPool();
56+
5557
#endif

src/rpc/protocol.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ enum RPCErrorCode
6363
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
6464
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
6565

66+
//! Chain errors
67+
RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found
68+
6669
//! Wallet errors
6770
RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
6871
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account

src/test/miner_tests.cpp

Lines changed: 51 additions & 47 deletions
Large diffs are not rendered by default.

src/test/txvalidation_tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
3434

3535
LOCK(cs_main);
3636

37-
unsigned int initialPoolSize = mempool.size();
37+
unsigned int initialPoolSize = m_node.mempool->size();
3838

3939
BOOST_CHECK_EQUAL(
4040
false,
41-
AcceptToMemoryPool(mempool, state, MakeTransactionRef(coinbaseTx),
41+
AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx),
4242
nullptr /* plTxnReplaced */,
4343
true /* bypass_limits */,
4444
0 /* nAbsurdFee */));
4545

4646
// Check that the transaction hasn't been added to mempool.
47-
BOOST_CHECK_EQUAL(mempool.size(), initialPoolSize);
47+
BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
4848

4949
// Check that the validation state reflects the unsuccessful attempt.
5050
BOOST_CHECK(state.IsInvalid());

src/test/txvalidationcache_tests.cpp

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,6 @@ bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsV
1717

1818
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
1919

20-
static bool
21-
ToMemPool(const CMutableTransaction& tx)
22-
{
23-
LOCK(cs_main);
24-
25-
TxValidationState state;
26-
return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx),
27-
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
28-
}
29-
3020
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
3121
{
3222
// Make sure skipping validation of transactions that were
@@ -35,6 +25,14 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
3525

3626
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
3727

28+
const auto ToMemPool = [this](const CMutableTransaction& tx) {
29+
LOCK(cs_main);
30+
31+
TxValidationState state;
32+
return AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(tx),
33+
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
34+
};
35+
3836
// Create a double-spend of mature coinbase txn:
3937
std::vector<CMutableTransaction> spends;
4038
spends.resize(2);
@@ -72,7 +70,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
7270
LOCK(cs_main);
7371
BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
7472
}
75-
mempool.clear();
73+
m_node.mempool->clear();
7674

7775
// Test 3: ... and should be rejected if spend2 is in the memory pool
7876
BOOST_CHECK(ToMemPool(spends[1]));
@@ -81,9 +79,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
8179
LOCK(cs_main);
8280
BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
8381
}
84-
mempool.clear();
82+
m_node.mempool->clear();
8583

86-
// Final sanity test: first spend in mempool, second in block, that's OK:
84+
// Final sanity test: first spend in *m_node.mempool, second in block, that's OK:
8785
std::vector<CMutableTransaction> oneSpend;
8886
oneSpend.push_back(spends[0]);
8987
BOOST_CHECK(ToMemPool(spends[1]));
@@ -94,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
9492
}
9593
// spends[1] should have been removed from the mempool when the
9694
// block with spends[0] is accepted:
97-
BOOST_CHECK_EQUAL(mempool.size(), 0U);
95+
BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
9896
}
9997

10098
// Run CheckInputs (using CoinsTip()) on the given transaction, for all script

src/test/util/setup_common.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
107107
threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
108108
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
109109

110-
mempool.setSanityCheck(1.0);
111110
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
112111
g_chainstate = MakeUnique<CChainState>();
113112
::ChainstateActive().InitCoinsDB(
@@ -131,6 +130,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
131130
}
132131
g_parallel_script_checks = true;
133132

133+
m_node.mempool = &::mempool;
134+
m_node.mempool->setSanityCheck(1.0);
134135
m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
135136
m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
136137
}
@@ -144,6 +145,7 @@ TestingSetup::~TestingSetup()
144145
g_rpc_node = nullptr;
145146
m_node.connman.reset();
146147
m_node.banman.reset();
148+
m_node.mempool = nullptr;
147149
UnloadBlockIndex();
148150
g_chainstate.reset();
149151
pblocktree.reset();

0 commit comments

Comments
 (0)