diff options
-rw-r--r-- | src/init.cpp | 6 | ||||
-rw-r--r-- | src/node/context.h | 7 | ||||
-rw-r--r-- | src/qt/test/rpcnestedtests.cpp | 1 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 10 | ||||
-rw-r--r-- | src/rpc/blockchain.h | 2 | ||||
-rw-r--r-- | src/rpc/protocol.h | 3 | ||||
-rw-r--r-- | src/test/miner_tests.cpp | 98 | ||||
-rw-r--r-- | src/test/txvalidation_tests.cpp | 6 | ||||
-rw-r--r-- | src/test/txvalidationcache_tests.cpp | 26 | ||||
-rw-r--r-- | src/test/util/setup_common.cpp | 4 | ||||
-rw-r--r-- | src/test/validation_block_tests.cpp | 12 |
11 files changed, 100 insertions, 75 deletions
diff --git a/src/init.cpp b/src/init.cpp index 421768441e..60209eb60a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -284,6 +284,7 @@ void Shutdown(NodeContext& node) GetMainSignals().UnregisterWithMempoolSignals(mempool); globalVerifyHandle.reset(); ECC_Stop(); + if (node.mempool) node.mempool = nullptr; LogPrintf("%s: done\n", __func__); } @@ -1635,6 +1636,11 @@ bool AppInitMain(NodeContext& node) return false; } + // Now that the chain state is loaded, make mempool generally available in the node context. For example the + // connection manager, wallet, or RPC threads, which are all started after this, may use it from the node context. + assert(!node.mempool); + node.mempool = &::mempool; + fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION); // Allowed to fail as this file IS missing on first startup. diff --git a/src/node/context.h b/src/node/context.h index 2b124af4db..dab5b5d048 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -10,6 +10,7 @@ class BanMan; class CConnman; +class CTxMemPool; class PeerLogicValidation; namespace interfaces { class Chain; @@ -22,13 +23,13 @@ class ChainClient; //! This is used by init, rpc, and test code to pass object references around //! without needing to declare the same variables and parameters repeatedly, or //! to use globals. More variables could be added to this struct (particularly -//! references to validation and mempool objects) to eliminate use of globals +//! references to validation objects) to eliminate use of globals //! and make code more modular and testable. The struct isn't intended to have //! any member functions. It should just be a collection of references that can //! be used without pulling in unwanted dependencies or functionality. -struct NodeContext -{ +struct NodeContext { std::unique_ptr<CConnman> connman; + CTxMemPool* mempool{nullptr}; // Currently a raw pointer because the memory is not managed by this struct std::unique_ptr<PeerLogicValidation> peer_logic; std::unique_ptr<BanMan> banman; std::unique_ptr<interfaces::Chain> chain; diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index 971d9f4a7c..374fc9b59b 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -32,7 +32,6 @@ void RPCNestedTests::rpcNestedTests() // do some test setup // could be moved to a more generic place when we add more tests on QT level tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); - //mempool.setSanityCheck(1.0); TestingSetup test; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 2f4b4412f5..946152d9aa 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -15,6 +15,7 @@ #include <hash.h> #include <index/blockfilterindex.h> #include <node/coinstats.h> +#include <node/context.h> #include <node/utxo_snapshot.h> #include <policy/feerate.h> #include <policy/policy.h> @@ -53,6 +54,15 @@ static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; +CTxMemPool& EnsureMemPool() +{ + CHECK_NONFATAL(g_rpc_node); + if (!g_rpc_node->mempool) { + throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found"); + } + return *g_rpc_node->mempool; +} + /* Calculate the difficulty for a given block index. */ double GetDifficulty(const CBlockIndex* blockindex) diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 8a1264f824..ccb3e39722 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -52,4 +52,6 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], //! direct way to pass in state to RPC methods without globals. extern NodeContext* g_rpc_node; +CTxMemPool& EnsureMemPool(); + #endif diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index ef6537e4ec..ca779497b9 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -63,6 +63,9 @@ enum RPCErrorCode RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found + //! Chain errors + RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found + //! Wallet errors RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.) RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 6ed7350ea2..d79a598bf1 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -23,7 +23,17 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) +namespace miner_tests { +struct MinerTestingSetup : public TestingSetup { + void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); + bool TestSequenceLocks(const CTransaction& tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) + { + return CheckSequenceLocks(*m_node.mempool, tx, flags); + } +}; +} // namespace miner_tests + +BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup) // BOOST_CHECK_EXCEPTION predicates to check the specific validation error class HasReason { @@ -89,16 +99,10 @@ static CBlockIndex CreateBlockIndex(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_mai return index; } -static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - LOCK(::mempool.cs); - return CheckSequenceLocks(::mempool, tx, flags); -} - // Test suite for ancestor feerate transaction selection. // Implemented as an additional function, rather than a separate test case, // to allow reusing the blockchain created in CreateNewBlock_validity. -static void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs) +void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) { // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; @@ -114,19 +118,19 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee uint256 hashHighFeeTx = tx.GetHash(); - mempool.addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); @@ -137,7 +141,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vin[0].prevout.hash = hashHighFeeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee uint256 hashFreeTx = tx.GetHash(); - mempool.addUnchecked(entry.Fee(0).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(0).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just @@ -147,7 +151,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vin[0].prevout.hash = hashFreeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; uint256 hashLowFeeTx = tx.GetHash(); - mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { @@ -158,10 +162,10 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& // Test that packages above the min relay fee do get included, even if one // of the transactions is below the min relay fee // Remove the low fee transaction and replace with a higher fee transaction - mempool.removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED); + m_node.mempool->removeRecursive(CTransaction(tx), MemPoolRemovalReason::REPLACED); tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); - mempool.addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -174,7 +178,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 100000000; tx.vout[1].nValue = 100000000; // 1BTC output uint256 hashFreeTx2 = tx.GetHash(); - mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself tx.vin[0].prevout.hash = hashFreeTx2; @@ -182,7 +186,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& feeToUse = blockMinFeeRate.GetFee(freeTxSize); tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; uint256 hashLowFeeTx2 = tx.GetHash(); - mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. @@ -195,7 +199,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& // as well. tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee - mempool.addUnchecked(entry.Fee(10000).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } @@ -252,7 +256,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) } LOCK(cs_main); - LOCK(::mempool.cs); + LOCK(m_node.mempool->cs); // Just to make sure we can still make simple blocks BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); @@ -276,12 +280,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); - mempool.clear(); + m_node.mempool->clear(); tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vout[0].nValue = BLOCKSUBSIDY; @@ -291,11 +295,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - mempool.clear(); + m_node.mempool->clear(); // block size > limit tx.vin[0].scriptSig = CScript(); @@ -311,24 +315,24 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - mempool.clear(); + m_node.mempool->clear(); - // orphan in mempool, template creation fails + // orphan in *m_node.mempool, template creation fails hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); - mempool.clear(); + m_node.mempool->clear(); // child with higher feerate than parent tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -336,34 +340,34 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[1].prevout.n = 0; tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - mempool.clear(); + m_node.mempool->clear(); - // coinbase in mempool, template creation fails + // coinbase in *m_node.mempool, template creation fails tx.vin.resize(1); tx.vin[0].prevout.SetNull(); tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; tx.vout[0].nValue = 0; hash = tx.GetHash(); // give it a fee so it'll get mined - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw bad-cb-multiple BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); - mempool.clear(); + m_node.mempool->clear(); - // double spend txn pair in mempool, template creation fails + // double spend txn pair in *m_node.mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); - mempool.clear(); + m_node.mempool->clear(); // subsidy changing int nHeight = ::ChainActive().Height(); @@ -392,7 +396,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); - // invalid p2sh txn in mempool, template creation fails + // invalid p2sh txn in *m_node.mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; @@ -400,15 +404,15 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end()); tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw block-validation-failed BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); - mempool.clear(); + m_node.mempool->clear(); // Delete the dummy blocks again. while (::ChainActive().Tip()->nHeight > nHeight) { @@ -439,7 +443,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; hash = tx.GetHash(); - mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 2))); // Sequence locks pass on 2nd block @@ -449,7 +453,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((::ChainActive().Tip()->GetMedianTimePast()+1-::ChainActive()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block prevheights[0] = baseheight + 2; hash = tx.GetHash(); - mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail @@ -465,7 +469,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 3; tx.nLockTime = ::ChainActive().Tip()->nHeight + 1; hash = tx.GetHash(); - mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block @@ -476,7 +480,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetHash(); - mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); + m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later @@ -513,7 +517,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) ::ChainActive().Tip()->nHeight--; SetMockTime(0); - mempool.clear(); + m_node.mempool->clear(); TestPackageSelection(chainparams, scriptPubKey, txFirst); diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp index 245c03d774..cace75f093 100644 --- a/src/test/txvalidation_tests.cpp +++ b/src/test/txvalidation_tests.cpp @@ -34,17 +34,17 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) LOCK(cs_main); - unsigned int initialPoolSize = mempool.size(); + unsigned int initialPoolSize = m_node.mempool->size(); BOOST_CHECK_EQUAL( false, - AcceptToMemoryPool(mempool, state, MakeTransactionRef(coinbaseTx), + AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx), nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)); // Check that the transaction hasn't been added to mempool. - BOOST_CHECK_EQUAL(mempool.size(), initialPoolSize); + BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize); // Check that the validation state reflects the unsuccessful attempt. BOOST_CHECK(state.IsInvalid()); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index a5bc15bb9f..67f45c4ed4 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -17,16 +17,6 @@ bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsV BOOST_AUTO_TEST_SUITE(tx_validationcache_tests) -static bool -ToMemPool(const CMutableTransaction& tx) -{ - LOCK(cs_main); - - TxValidationState state; - return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), - nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */); -} - BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) { // Make sure skipping validation of transactions that were @@ -35,6 +25,14 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + const auto ToMemPool = [this](const CMutableTransaction& tx) { + LOCK(cs_main); + + TxValidationState state; + return AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(tx), + nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */); + }; + // Create a double-spend of mature coinbase txn: std::vector<CMutableTransaction> spends; spends.resize(2); @@ -72,7 +70,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); } - mempool.clear(); + m_node.mempool->clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); @@ -81,9 +79,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) LOCK(cs_main); BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); } - mempool.clear(); + m_node.mempool->clear(); - // Final sanity test: first spend in mempool, second in block, that's OK: + // Final sanity test: first spend in *m_node.mempool, second in block, that's OK: std::vector<CMutableTransaction> oneSpend; oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); @@ -94,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) } // spends[1] should have been removed from the mempool when the // block with spends[0] is accepted: - BOOST_CHECK_EQUAL(mempool.size(), 0U); + BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U); } // Run CheckInputs (using CoinsTip()) on the given transaction, for all script diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 0c6ecdf69d..86c355fdcd 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -107,7 +107,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler)); GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); - mempool.setSanityCheck(1.0); pblocktree.reset(new CBlockTreeDB(1 << 20, true)); g_chainstate = MakeUnique<CChainState>(); ::ChainstateActive().InitCoinsDB( @@ -131,6 +130,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha } g_parallel_script_checks = true; + m_node.mempool = &::mempool; + m_node.mempool->setSanityCheck(1.0); m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests. } @@ -144,6 +145,7 @@ TestingSetup::~TestingSetup() g_rpc_node = nullptr; m_node.connman.reset(); m_node.banman.reset(); + m_node.mempool = nullptr; UnloadBlockIndex(); g_chainstate.reset(); pblocktree.reset(); diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index b7cf82906a..1fa48b325c 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -279,7 +279,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) std::list<CTransactionRef> plTxnReplaced; for (const auto& tx : txs) { BOOST_REQUIRE(AcceptToMemoryPool( - ::mempool, + *m_node.mempool, state, tx, &plTxnReplaced, @@ -290,8 +290,8 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) // Check that all txs are in the pool { - LOCK(::mempool.cs); - BOOST_CHECK_EQUAL(::mempool.mapTx.size(), txs.size()); + LOCK(m_node.mempool->cs); + BOOST_CHECK_EQUAL(m_node.mempool->mapTx.size(), txs.size()); } // Run a thread that simulates an RPC caller that is polling while @@ -301,8 +301,8 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) // the transactions invalidated by the reorg, or none of them, and // not some intermediate amount. while (true) { - LOCK(::mempool.cs); - if (::mempool.mapTx.size() == 0) { + LOCK(m_node.mempool->cs); + if (m_node.mempool->mapTx.size() == 0) { // We are done with the reorg break; } @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) // be atomic. So the caller assumes that the returned mempool // is consistent. That is, it has all txs that were there // before the reorg. - assert(::mempool.mapTx.size() == txs.size()); + assert(m_node.mempool->mapTx.size() == txs.size()); continue; } LOCK(cs_main); |