Merge #17407: node: Add reference to mempool in NodeContext
fa538813b1
scripted-diff: Replace ::mempool with m_node.mempool in tests (MarcoFalke)8888ad02e2
test: Replace recursive lock with locking annotations (MarcoFalke)fac07f2038
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: utACKfa538813b1
ariard: Tested ACKfa53881
. Tree-SHA512: 2c446a8a51476354aad7126c2b833500d36b24490caa94f847b2bdc622054de0dae28980f23e3d91b1b492dc32931656d98dbd019af9e4e58f2f8c5375aac694
This commit is contained in:
commit
ae6943620a
|
@ -284,6 +284,7 @@ void Shutdown(NodeContext& node)
|
||||||
GetMainSignals().UnregisterWithMempoolSignals(mempool);
|
GetMainSignals().UnregisterWithMempoolSignals(mempool);
|
||||||
globalVerifyHandle.reset();
|
globalVerifyHandle.reset();
|
||||||
ECC_Stop();
|
ECC_Stop();
|
||||||
|
if (node.mempool) node.mempool = nullptr;
|
||||||
LogPrintf("%s: done\n", __func__);
|
LogPrintf("%s: done\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1635,6 +1636,11 @@ bool AppInitMain(NodeContext& node)
|
||||||
return false;
|
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;
|
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
|
||||||
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
|
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
|
||||||
// Allowed to fail as this file IS missing on first startup.
|
// Allowed to fail as this file IS missing on first startup.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
class BanMan;
|
class BanMan;
|
||||||
class CConnman;
|
class CConnman;
|
||||||
|
class CTxMemPool;
|
||||||
class PeerLogicValidation;
|
class PeerLogicValidation;
|
||||||
namespace interfaces {
|
namespace interfaces {
|
||||||
class Chain;
|
class Chain;
|
||||||
|
@ -22,13 +23,13 @@ class ChainClient;
|
||||||
//! This is used by init, rpc, and test code to pass object references around
|
//! 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
|
//! without needing to declare the same variables and parameters repeatedly, or
|
||||||
//! to use globals. More variables could be added to this struct (particularly
|
//! 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
|
//! 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
|
//! any member functions. It should just be a collection of references that can
|
||||||
//! be used without pulling in unwanted dependencies or functionality.
|
//! be used without pulling in unwanted dependencies or functionality.
|
||||||
struct NodeContext
|
struct NodeContext {
|
||||||
{
|
|
||||||
std::unique_ptr<CConnman> connman;
|
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<PeerLogicValidation> peer_logic;
|
||||||
std::unique_ptr<BanMan> banman;
|
std::unique_ptr<BanMan> banman;
|
||||||
std::unique_ptr<interfaces::Chain> chain;
|
std::unique_ptr<interfaces::Chain> chain;
|
||||||
|
|
|
@ -32,7 +32,6 @@ void RPCNestedTests::rpcNestedTests()
|
||||||
// do some test setup
|
// do some test setup
|
||||||
// could be moved to a more generic place when we add more tests on QT level
|
// could be moved to a more generic place when we add more tests on QT level
|
||||||
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
|
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
|
||||||
//mempool.setSanityCheck(1.0);
|
|
||||||
|
|
||||||
TestingSetup test;
|
TestingSetup test;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
#include <index/blockfilterindex.h>
|
#include <index/blockfilterindex.h>
|
||||||
#include <node/coinstats.h>
|
#include <node/coinstats.h>
|
||||||
|
#include <node/context.h>
|
||||||
#include <node/utxo_snapshot.h>
|
#include <node/utxo_snapshot.h>
|
||||||
#include <policy/feerate.h>
|
#include <policy/feerate.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
|
@ -53,6 +54,15 @@ static Mutex cs_blockchange;
|
||||||
static std::condition_variable cond_blockchange;
|
static std::condition_variable cond_blockchange;
|
||||||
static CUpdatedBlock latestblock;
|
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.
|
/* Calculate the difficulty for a given block index.
|
||||||
*/
|
*/
|
||||||
double GetDifficulty(const CBlockIndex* blockindex)
|
double GetDifficulty(const CBlockIndex* blockindex)
|
||||||
|
|
|
@ -52,4 +52,6 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
|
||||||
//! direct way to pass in state to RPC methods without globals.
|
//! direct way to pass in state to RPC methods without globals.
|
||||||
extern NodeContext* g_rpc_node;
|
extern NodeContext* g_rpc_node;
|
||||||
|
|
||||||
|
CTxMemPool& EnsureMemPool();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -63,6 +63,9 @@ enum RPCErrorCode
|
||||||
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
|
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
|
||||||
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
|
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
|
||||||
|
|
||||||
|
//! Chain errors
|
||||||
|
RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found
|
||||||
|
|
||||||
//! Wallet errors
|
//! Wallet errors
|
||||||
RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
|
RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
|
||||||
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account
|
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account
|
||||||
|
|
|
@ -23,7 +23,17 @@
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#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
|
// BOOST_CHECK_EXCEPTION predicates to check the specific validation error
|
||||||
class HasReason {
|
class HasReason {
|
||||||
|
@ -89,16 +99,10 @@ static CBlockIndex CreateBlockIndex(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_mai
|
||||||
return index;
|
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.
|
// Test suite for ancestor feerate transaction selection.
|
||||||
// Implemented as an additional function, rather than a separate test case,
|
// Implemented as an additional function, rather than a separate test case,
|
||||||
// to allow reusing the blockchain created in CreateNewBlock_validity.
|
// 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.
|
// Test the ancestor feerate transaction selection.
|
||||||
TestMemPoolEntryHelper entry;
|
TestMemPoolEntryHelper entry;
|
||||||
|
@ -114,19 +118,19 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript&
|
||||||
tx.vout[0].nValue = 5000000000LL - 1000;
|
tx.vout[0].nValue = 5000000000LL - 1000;
|
||||||
// This tx has a low fee: 1000 satoshis
|
// This tx has a low fee: 1000 satoshis
|
||||||
uint256 hashParentTx = tx.GetHash(); // save this txid for later use
|
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
|
// This tx has a medium fee: 10000 satoshis
|
||||||
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
||||||
tx.vout[0].nValue = 5000000000LL - 10000;
|
tx.vout[0].nValue = 5000000000LL - 10000;
|
||||||
uint256 hashMediumFeeTx = tx.GetHash();
|
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
|
// This tx has a high fee, but depends on the first transaction
|
||||||
tx.vin[0].prevout.hash = hashParentTx;
|
tx.vin[0].prevout.hash = hashParentTx;
|
||||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
|
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
|
||||||
uint256 hashHighFeeTx = tx.GetHash();
|
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);
|
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
|
||||||
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
|
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.vin[0].prevout.hash = hashHighFeeTx;
|
||||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
|
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
|
||||||
uint256 hashFreeTx = tx.GetHash();
|
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);
|
size_t freeTxSize = ::GetSerializeSize(tx, PROTOCOL_VERSION);
|
||||||
|
|
||||||
// Calculate a fee on child transaction that will put the package just
|
// 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.vin[0].prevout.hash = hashFreeTx;
|
||||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
|
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
|
||||||
uint256 hashLowFeeTx = tx.GetHash();
|
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);
|
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
|
||||||
// Verify that the free tx and the low fee tx didn't get selected
|
// 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) {
|
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
|
// Test that packages above the min relay fee do get included, even if one
|
||||||
// of the transactions is below the min relay fee
|
// of the transactions is below the min relay fee
|
||||||
// Remove the low fee transaction and replace with a higher fee transaction
|
// 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
|
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
|
||||||
hashLowFeeTx = tx.GetHash();
|
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);
|
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
|
||||||
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
|
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
|
||||||
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
|
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[0].nValue = 5000000000LL - 100000000;
|
||||||
tx.vout[1].nValue = 100000000; // 1BTC output
|
tx.vout[1].nValue = 100000000; // 1BTC output
|
||||||
uint256 hashFreeTx2 = tx.GetHash();
|
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
|
// This tx can't be mined by itself
|
||||||
tx.vin[0].prevout.hash = hashFreeTx2;
|
tx.vin[0].prevout.hash = hashFreeTx2;
|
||||||
|
@ -182,7 +186,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript&
|
||||||
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
|
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
|
||||||
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
|
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
|
||||||
uint256 hashLowFeeTx2 = tx.GetHash();
|
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);
|
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
|
||||||
|
|
||||||
// Verify that this tx isn't selected.
|
// Verify that this tx isn't selected.
|
||||||
|
@ -195,7 +199,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript&
|
||||||
// as well.
|
// as well.
|
||||||
tx.vin[0].prevout.n = 1;
|
tx.vin[0].prevout.n = 1;
|
||||||
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
|
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);
|
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
|
||||||
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
|
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
|
||||||
}
|
}
|
||||||
|
@ -252,7 +256,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
LOCK(::mempool.cs);
|
LOCK(m_node.mempool->cs);
|
||||||
|
|
||||||
// Just to make sure we can still make simple blocks
|
// Just to make sure we can still make simple blocks
|
||||||
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
|
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
|
||||||
|
@ -276,12 +280,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
hash = tx.GetHash();
|
hash = tx.GetHash();
|
||||||
bool spendsCoinbase = i == 0; // only first tx spends coinbase
|
bool spendsCoinbase = i == 0; // only first tx spends coinbase
|
||||||
// If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
|
// 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;
|
tx.vin[0].prevout.hash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
|
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.vin[0].prevout.hash = txFirst[0]->GetHash();
|
||||||
tx.vout[0].nValue = BLOCKSUBSIDY;
|
tx.vout[0].nValue = BLOCKSUBSIDY;
|
||||||
|
@ -291,11 +295,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
hash = tx.GetHash();
|
hash = tx.GetHash();
|
||||||
bool spendsCoinbase = i == 0; // only first tx spends coinbase
|
bool spendsCoinbase = i == 0; // only first tx spends coinbase
|
||||||
// If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
|
// 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;
|
tx.vin[0].prevout.hash = hash;
|
||||||
}
|
}
|
||||||
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
|
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
|
||||||
mempool.clear();
|
m_node.mempool->clear();
|
||||||
|
|
||||||
// block size > limit
|
// block size > limit
|
||||||
tx.vin[0].scriptSig = CScript();
|
tx.vin[0].scriptSig = CScript();
|
||||||
|
@ -311,24 +315,24 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
tx.vout[0].nValue -= LOWFEE;
|
tx.vout[0].nValue -= LOWFEE;
|
||||||
hash = tx.GetHash();
|
hash = tx.GetHash();
|
||||||
bool spendsCoinbase = i == 0; // only first tx spends coinbase
|
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;
|
tx.vin[0].prevout.hash = hash;
|
||||||
}
|
}
|
||||||
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
|
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();
|
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"));
|
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
|
// child with higher feerate than parent
|
||||||
tx.vin[0].scriptSig = CScript() << OP_1;
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
||||||
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
||||||
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
|
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
|
||||||
hash = tx.GetHash();
|
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[0].prevout.hash = hash;
|
||||||
tx.vin.resize(2);
|
tx.vin.resize(2);
|
||||||
tx.vin[1].scriptSig = CScript() << OP_1;
|
tx.vin[1].scriptSig = CScript() << OP_1;
|
||||||
|
@ -336,34 +340,34 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
tx.vin[1].prevout.n = 0;
|
tx.vin[1].prevout.n = 0;
|
||||||
tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
|
tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
|
||||||
hash = tx.GetHash();
|
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));
|
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.resize(1);
|
||||||
tx.vin[0].prevout.SetNull();
|
tx.vin[0].prevout.SetNull();
|
||||||
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
|
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
|
||||||
tx.vout[0].nValue = 0;
|
tx.vout[0].nValue = 0;
|
||||||
hash = tx.GetHash();
|
hash = tx.GetHash();
|
||||||
// give it a fee so it'll get mined
|
// 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
|
// Should throw bad-cb-multiple
|
||||||
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("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].prevout.hash = txFirst[0]->GetHash();
|
||||||
tx.vin[0].scriptSig = CScript() << OP_1;
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
||||||
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
|
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
|
||||||
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
hash = tx.GetHash();
|
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;
|
tx.vout[0].scriptPubKey = CScript() << OP_2;
|
||||||
hash = tx.GetHash();
|
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"));
|
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
|
||||||
mempool.clear();
|
m_node.mempool->clear();
|
||||||
|
|
||||||
// subsidy changing
|
// subsidy changing
|
||||||
int nHeight = ::ChainActive().Height();
|
int nHeight = ::ChainActive().Height();
|
||||||
|
@ -392,7 +396,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
}
|
}
|
||||||
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
|
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.hash = txFirst[0]->GetHash();
|
||||||
tx.vin[0].prevout.n = 0;
|
tx.vin[0].prevout.n = 0;
|
||||||
tx.vin[0].scriptSig = CScript() << OP_1;
|
tx.vin[0].scriptSig = CScript() << OP_1;
|
||||||
|
@ -400,15 +404,15 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
script = CScript() << OP_0;
|
script = CScript() << OP_0;
|
||||||
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
|
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
|
||||||
hash = tx.GetHash();
|
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].prevout.hash = hash;
|
||||||
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
|
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
|
||||||
tx.vout[0].nValue -= LOWFEE;
|
tx.vout[0].nValue -= LOWFEE;
|
||||||
hash = tx.GetHash();
|
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
|
// Should throw block-validation-failed
|
||||||
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("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.
|
// Delete the dummy blocks again.
|
||||||
while (::ChainActive().Tip()->nHeight > nHeight) {
|
while (::ChainActive().Tip()->nHeight > nHeight) {
|
||||||
|
@ -439,7 +443,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
tx.nLockTime = 0;
|
tx.nLockTime = 0;
|
||||||
hash = tx.GetHash();
|
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(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes
|
||||||
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
|
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
|
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
|
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;
|
prevheights[0] = baseheight + 2;
|
||||||
hash = tx.GetHash();
|
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(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes
|
||||||
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
|
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
|
||||||
|
|
||||||
|
@ -465,7 +469,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
prevheights[0] = baseheight + 3;
|
prevheights[0] = baseheight + 3;
|
||||||
tx.nLockTime = ::ChainActive().Tip()->nHeight + 1;
|
tx.nLockTime = ::ChainActive().Tip()->nHeight + 1;
|
||||||
hash = tx.GetHash();
|
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(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails
|
||||||
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass
|
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
|
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.resize(1);
|
||||||
prevheights[0] = baseheight + 4;
|
prevheights[0] = baseheight + 4;
|
||||||
hash = tx.GetHash();
|
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(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails
|
||||||
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass
|
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
|
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--;
|
::ChainActive().Tip()->nHeight--;
|
||||||
SetMockTime(0);
|
SetMockTime(0);
|
||||||
mempool.clear();
|
m_node.mempool->clear();
|
||||||
|
|
||||||
TestPackageSelection(chainparams, scriptPubKey, txFirst);
|
TestPackageSelection(chainparams, scriptPubKey, txFirst);
|
||||||
|
|
||||||
|
|
|
@ -34,17 +34,17 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
unsigned int initialPoolSize = mempool.size();
|
unsigned int initialPoolSize = m_node.mempool->size();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
false,
|
false,
|
||||||
AcceptToMemoryPool(mempool, state, MakeTransactionRef(coinbaseTx),
|
AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx),
|
||||||
nullptr /* plTxnReplaced */,
|
nullptr /* plTxnReplaced */,
|
||||||
true /* bypass_limits */,
|
true /* bypass_limits */,
|
||||||
0 /* nAbsurdFee */));
|
0 /* nAbsurdFee */));
|
||||||
|
|
||||||
// Check that the transaction hasn't been added to mempool.
|
// 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.
|
// Check that the validation state reflects the unsuccessful attempt.
|
||||||
BOOST_CHECK(state.IsInvalid());
|
BOOST_CHECK(state.IsInvalid());
|
||||||
|
|
|
@ -17,16 +17,6 @@ bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsV
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
|
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)
|
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
||||||
{
|
{
|
||||||
// Make sure skipping validation of transactions that were
|
// 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;
|
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:
|
// Create a double-spend of mature coinbase txn:
|
||||||
std::vector<CMutableTransaction> spends;
|
std::vector<CMutableTransaction> spends;
|
||||||
spends.resize(2);
|
spends.resize(2);
|
||||||
|
@ -72,7 +70,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
|
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
|
// Test 3: ... and should be rejected if spend2 is in the memory pool
|
||||||
BOOST_CHECK(ToMemPool(spends[1]));
|
BOOST_CHECK(ToMemPool(spends[1]));
|
||||||
|
@ -81,9 +79,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
|
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;
|
std::vector<CMutableTransaction> oneSpend;
|
||||||
oneSpend.push_back(spends[0]);
|
oneSpend.push_back(spends[0]);
|
||||||
BOOST_CHECK(ToMemPool(spends[1]));
|
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
|
// spends[1] should have been removed from the mempool when the
|
||||||
// block with spends[0] is accepted:
|
// 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
|
// Run CheckInputs (using CoinsTip()) on the given transaction, for all script
|
||||||
|
|
|
@ -107,7 +107,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
||||||
threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
|
threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
|
||||||
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
|
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
|
||||||
|
|
||||||
mempool.setSanityCheck(1.0);
|
|
||||||
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
|
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
|
||||||
g_chainstate = MakeUnique<CChainState>();
|
g_chainstate = MakeUnique<CChainState>();
|
||||||
::ChainstateActive().InitCoinsDB(
|
::ChainstateActive().InitCoinsDB(
|
||||||
|
@ -131,6 +130,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
||||||
}
|
}
|
||||||
g_parallel_script_checks = true;
|
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.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
|
||||||
m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
|
m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
|
||||||
}
|
}
|
||||||
|
@ -144,6 +145,7 @@ TestingSetup::~TestingSetup()
|
||||||
g_rpc_node = nullptr;
|
g_rpc_node = nullptr;
|
||||||
m_node.connman.reset();
|
m_node.connman.reset();
|
||||||
m_node.banman.reset();
|
m_node.banman.reset();
|
||||||
|
m_node.mempool = nullptr;
|
||||||
UnloadBlockIndex();
|
UnloadBlockIndex();
|
||||||
g_chainstate.reset();
|
g_chainstate.reset();
|
||||||
pblocktree.reset();
|
pblocktree.reset();
|
||||||
|
|
|
@ -279,7 +279,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
|
||||||
std::list<CTransactionRef> plTxnReplaced;
|
std::list<CTransactionRef> plTxnReplaced;
|
||||||
for (const auto& tx : txs) {
|
for (const auto& tx : txs) {
|
||||||
BOOST_REQUIRE(AcceptToMemoryPool(
|
BOOST_REQUIRE(AcceptToMemoryPool(
|
||||||
::mempool,
|
*m_node.mempool,
|
||||||
state,
|
state,
|
||||||
tx,
|
tx,
|
||||||
&plTxnReplaced,
|
&plTxnReplaced,
|
||||||
|
@ -290,8 +290,8 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
|
||||||
|
|
||||||
// Check that all txs are in the pool
|
// Check that all txs are in the pool
|
||||||
{
|
{
|
||||||
LOCK(::mempool.cs);
|
LOCK(m_node.mempool->cs);
|
||||||
BOOST_CHECK_EQUAL(::mempool.mapTx.size(), txs.size());
|
BOOST_CHECK_EQUAL(m_node.mempool->mapTx.size(), txs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a thread that simulates an RPC caller that is polling while
|
// 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
|
// the transactions invalidated by the reorg, or none of them, and
|
||||||
// not some intermediate amount.
|
// not some intermediate amount.
|
||||||
while (true) {
|
while (true) {
|
||||||
LOCK(::mempool.cs);
|
LOCK(m_node.mempool->cs);
|
||||||
if (::mempool.mapTx.size() == 0) {
|
if (m_node.mempool->mapTx.size() == 0) {
|
||||||
// We are done with the reorg
|
// We are done with the reorg
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
|
||||||
// be atomic. So the caller assumes that the returned mempool
|
// be atomic. So the caller assumes that the returned mempool
|
||||||
// is consistent. That is, it has all txs that were there
|
// is consistent. That is, it has all txs that were there
|
||||||
// before the reorg.
|
// before the reorg.
|
||||||
assert(::mempool.mapTx.size() == txs.size());
|
assert(m_node.mempool->mapTx.size() == txs.size());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
Loading…
Reference in a new issue