0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-24 12:41:41 -05:00
bitcoin-bitcoin-core/src/test/util/setup_common.cpp

535 lines
28 KiB
C++
Raw Normal View History

// Copyright (c) 2011-2022 The Bitcoin Core developers
2014-12-13 12:09:33 +08:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/util/setup_common.h>
#include <kernel/validation_cache_sizes.h>
#include <addrman.h>
2017-10-05 16:40:43 -04:00
#include <banman.h>
#include <chainparams.h>
#include <common/system.h>
#include <common/url.h>
#include <consensus/consensus.h>
#include <consensus/params.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
2019-06-20 09:34:45 -04:00
#include <init.h>
#include <init/common.h>
#include <interfaces/chain.h>
#include <kernel/mempool_entry.h>
#include <logging.h>
#include <net.h>
#include <net_processing.h>
2021-11-11 14:40:50 -05:00
#include <node/blockstorage.h>
#include <node/chainstate.h>
pool: Add and use MemPoolOptions, ApplyArgsManOptions Reviewers: Note that CTxMemPool now requires a non-defaulted CTxMemPool::Options for its constructor. Meaning that there's no need to worry about a stray CTxMemPool constructor somewhere defaulting to something incorrect. All instances of CTxMemPool construction are addressed here in this commit. We set options for CTxMemPool and construct it in many different ways. A good example can be seen in how we determine CTxMemPool's check_ratio in AppInitMain(...). 1. We first set the default based on chainparams's DefaultConsistencyChecks() 2. Then, we apply the ArgsManager option on top of that default 3. Finally, we clamp the result of that between 0 and 1 Million With this patch, most CTxMemPool construction are along the lines of: MemPoolOptions mempool_opts{...default overrides...}; ApplyArgsManOptions(argsman, mempool_opts); ...hard overrides... CTxMemPool pool{mempool_opts}; This "compositional" style of building options means that we can omit unnecessary/irrelevant steps wherever we want but also maintain full customizability. For example: - For users of libbitcoinkernel, where we eventually want to remove ArgsManager, they simply won't call (or even know about) ApplyArgsManOptions. - See src/init.cpp to see how the check_ratio CTxMemPool option works after this change. A MemPoolOptionsForTest helper was also added and used by tests/fuzz tests where a local CTxMemPool needed to be created. The change in src/test/fuzz/tx_pool.cpp seemingly changes behaviour by applying ArgsManager options on top of the CTxMemPool::Options defaults. However, in future commits where we introduce flags like -maxmempool, the call to ApplyArgsManOptions is actually what preserves the existing behaviour. Previously, although it wasn't obvious, our CTxMemPool would consult gArgs for flags like -maxmempool when it needed it, so it already relied on ArgsManager information. This patchset just laid bare the obfuscatory perils of globals. [META] As this patchset progresses, we will move more and more CTxMemPool-relevant options into MemPoolOptions and add their ArgsMan-related logic to ApplyArgsManOptions.
2022-03-18 13:51:37 -04:00
#include <node/context.h>
#include <node/kernel_notifications.h>
2022-08-02 15:21:47 +02:00
#include <node/mempool_args.h>
#include <node/miner.h>
#include <node/peerman_args.h>
#include <node/validation_cache_args.h>
#include <noui.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
#include <pow.h>
#include <random.h>
#include <rpc/blockchain.h>
#include <rpc/register.h>
#include <rpc/server.h>
#include <scheduler.h>
#include <script/sigcache.h>
#include <streams.h>
#include <test/util/net.h>
#include <test/util/random.h>
#include <test/util/txmempool.h>
#include <txdb.h>
pool: Add and use MemPoolOptions, ApplyArgsManOptions Reviewers: Note that CTxMemPool now requires a non-defaulted CTxMemPool::Options for its constructor. Meaning that there's no need to worry about a stray CTxMemPool constructor somewhere defaulting to something incorrect. All instances of CTxMemPool construction are addressed here in this commit. We set options for CTxMemPool and construct it in many different ways. A good example can be seen in how we determine CTxMemPool's check_ratio in AppInitMain(...). 1. We first set the default based on chainparams's DefaultConsistencyChecks() 2. Then, we apply the ArgsManager option on top of that default 3. Finally, we clamp the result of that between 0 and 1 Million With this patch, most CTxMemPool construction are along the lines of: MemPoolOptions mempool_opts{...default overrides...}; ApplyArgsManOptions(argsman, mempool_opts); ...hard overrides... CTxMemPool pool{mempool_opts}; This "compositional" style of building options means that we can omit unnecessary/irrelevant steps wherever we want but also maintain full customizability. For example: - For users of libbitcoinkernel, where we eventually want to remove ArgsManager, they simply won't call (or even know about) ApplyArgsManOptions. - See src/init.cpp to see how the check_ratio CTxMemPool option works after this change. A MemPoolOptionsForTest helper was also added and used by tests/fuzz tests where a local CTxMemPool needed to be created. The change in src/test/fuzz/tx_pool.cpp seemingly changes behaviour by applying ArgsManager options on top of the CTxMemPool::Options defaults. However, in future commits where we introduce flags like -maxmempool, the call to ApplyArgsManOptions is actually what preserves the existing behaviour. Previously, although it wasn't obvious, our CTxMemPool would consult gArgs for flags like -maxmempool when it needed it, so it already relied on ArgsManager information. This patchset just laid bare the obfuscatory perils of globals. [META] As this patchset progresses, we will move more and more CTxMemPool-relevant options into MemPoolOptions and add their ArgsMan-related logic to ApplyArgsManOptions.
2022-03-18 13:51:37 -04:00
#include <txmempool.h>
#include <util/chaintype.h>
2023-11-28 19:11:52 +00:00
#include <util/check.h>
#include <util/rbf.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/thread.h>
#include <util/threadnames.h>
#include <util/time.h>
#include <util/translation.h>
#include <util/vector.h>
#include <validation.h>
#include <validationinterface.h>
#include <walletinitinterface.h>
#include <algorithm>
#include <functional>
#include <stdexcept>
using kernel::BlockTreeDB;
using kernel::ValidationCacheSizes;
using node::ApplyArgsManOptions;
using node::BlockAssembler;
using node::BlockManager;
using node::CalculateCacheSizes;
using node::KernelNotifications;
using node::LoadChainstate;
using node::RegenerateCommitments;
using node::VerifyLoadedChainstate;
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = nullptr;
/** Random context to get unique temp data dirs. Separate from g_insecure_rand_ctx, which can be seeded from a const env var */
static FastRandomContext g_insecure_rand_ctx_temp_path;
std::ostream& operator<<(std::ostream& os, const uint256& num)
{
os << num.ToString();
return os;
}
2023-11-28 19:11:52 +00:00
struct NetworkSetup
{
NetworkSetup()
{
Assert(SetupNetworking());
}
};
static NetworkSetup g_networksetup_instance;
BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args)
2021-04-18 11:37:06 +02:00
: m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()},
m_args{}
{
m_node.shutdown = &m_interrupt;
m_node.args = &gArgs;
std::vector<const char*> arguments = Cat(
{
"dummy",
"-printtoconsole=0",
"-logsourcelocations",
"-logtimemicros",
"-logthreadnames",
"-loglevel=trace",
"-debug",
"-debugexclude=libevent",
"-debugexclude=leveldb",
},
extra_args);
if (G_TEST_COMMAND_LINE_ARGUMENTS) {
arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS());
}
util::ThreadRename("test");
fs::create_directories(m_path_root);
m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ClearPathCache();
{
SetupServerArgs(*m_node.args);
std::string error;
if (!m_node.args->ParseParameters(arguments.size(), arguments.data(), error)) {
m_node.args->ClearArgs();
throw std::runtime_error{error};
}
}
SelectParams(chainType);
SeedInsecureRand();
if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN);
InitLogging(*m_node.args);
AppInitParameterInteraction(*m_node.args);
2019-06-20 09:34:45 -04:00
LogInstance().StartLogging();
m_node.kernel = std::make_unique<kernel::Context>();
SetupEnvironment();
ValidationCacheSizes validation_cache_sizes{};
ApplyArgsManOptions(*m_node.args, validation_cache_sizes);
Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
m_node.chain = interfaces::MakeChain(m_node);
static bool noui_connected = false;
if (!noui_connected) {
noui_connect();
noui_connected = true;
}
}
BasicTestingSetup::~BasicTestingSetup()
{
m_node.kernel.reset();
SetMockTime(0s); // Reset mocktime for following tests
2019-06-20 09:34:45 -04:00
LogInstance().DisconnectTestLogger();
fs::remove_all(m_path_root);
gArgs.ClearArgs();
}
ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args)
: BasicTestingSetup(chainType, extra_args)
{
const CChainParams& chainparams = Params();
// We have to run a scheduler thread to prevent ActivateBestChain
// from blocking due to queue overrun.
m_node.scheduler = std::make_unique<CScheduler>();
m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); });
GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
pool: Add and use MemPoolOptions, ApplyArgsManOptions Reviewers: Note that CTxMemPool now requires a non-defaulted CTxMemPool::Options for its constructor. Meaning that there's no need to worry about a stray CTxMemPool constructor somewhere defaulting to something incorrect. All instances of CTxMemPool construction are addressed here in this commit. We set options for CTxMemPool and construct it in many different ways. A good example can be seen in how we determine CTxMemPool's check_ratio in AppInitMain(...). 1. We first set the default based on chainparams's DefaultConsistencyChecks() 2. Then, we apply the ArgsManager option on top of that default 3. Finally, we clamp the result of that between 0 and 1 Million With this patch, most CTxMemPool construction are along the lines of: MemPoolOptions mempool_opts{...default overrides...}; ApplyArgsManOptions(argsman, mempool_opts); ...hard overrides... CTxMemPool pool{mempool_opts}; This "compositional" style of building options means that we can omit unnecessary/irrelevant steps wherever we want but also maintain full customizability. For example: - For users of libbitcoinkernel, where we eventually want to remove ArgsManager, they simply won't call (or even know about) ApplyArgsManOptions. - See src/init.cpp to see how the check_ratio CTxMemPool option works after this change. A MemPoolOptionsForTest helper was also added and used by tests/fuzz tests where a local CTxMemPool needed to be created. The change in src/test/fuzz/tx_pool.cpp seemingly changes behaviour by applying ArgsManager options on top of the CTxMemPool::Options defaults. However, in future commits where we introduce flags like -maxmempool, the call to ApplyArgsManOptions is actually what preserves the existing behaviour. Previously, although it wasn't obvious, our CTxMemPool would consult gArgs for flags like -maxmempool when it needed it, so it already relied on ArgsManager information. This patchset just laid bare the obfuscatory perils of globals. [META] As this patchset progresses, we will move more and more CTxMemPool-relevant options into MemPoolOptions and add their ArgsMan-related logic to ApplyArgsManOptions.
2022-03-18 13:51:37 -04:00
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
m_cache_sizes = CalculateCacheSizes(m_args);
m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status);
const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
.datadir = m_args.GetDataDirNet(),
.check_block_index = true,
.notifications = *m_node.notifications,
.signals = &GetMainSignals(),
.worker_threads_num = 2,
};
const BlockManager::Options blockman_opts{
.chainparams = chainman_opts.chainparams,
.blocks_dir = m_args.GetBlocksDirPath(),
.notifications = chainman_opts.notifications,
};
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts);
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{
.path = m_args.GetDataDirNet() / "blocks" / "index",
.cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),
.memory_only = true});
}
test: Add new ChainTestingSetup and use it Previously, the validation_chainstatemanager_tests test suite instantiated its own duplicate ChainstateManager on which tests were performed. This wasn't a problem for the specific actions performed in that suite. However, the existence of this duplicate ChainstateManager and the fact that many of our validation static functions reach for g_chainman, ::Chain(state|)Active means we may end up acting on two different CChainStates should we write more extensive tests in the future. This change adds a new ChainTestingSetup which performs all initialization previously done by TestingSetup except: 1. RPC command registration 2. ChainState initialization 3. Genesis Activation 4. {Ban,Conn,Peer}Man initialization Means that we will no longer need to initialize a duplicate ChainstateManger in order to test the initialization codepaths of CChainState and ChainstateManager. Lastly, this change has the additional benefit of allowing for review-only assertions meant to show correctness to work in future work de-globalizing g_chainman. In the test chainstatemanager_rebalance_caches, an additional LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile], which is out of bounds when LoadGenesisBlock hasn't been called yet. ----- Note for the future: The class con/destructor inheritance structure we have for these TestingSetup classes is probably not the most suitable abstraction. In particular, for both TestingSetup and ChainTestingSetup, we need to stop the scheduler first before anything else. Otherwise classes depending on the scheduler may be referenced by the scheduler after said classes are freed. This means that there's no clear parallel between our teardown code and C++'s destructuring order for class hierarchies. Future work should strive to coalesce (as much as possible) test and non-test init codepaths and perhaps structure it in a more fail-proof way.
2020-10-13 16:55:20 -04:00
ChainTestingSetup::~ChainTestingSetup()
{
if (m_node.scheduler) m_node.scheduler->stop();
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler();
m_node.connman.reset();
m_node.banman.reset();
m_node.addrman.reset();
2021-08-31 18:40:18 +01:00
m_node.netgroupman.reset();
2020-04-08 19:47:56 -04:00
m_node.args = nullptr;
2020-07-19 20:30:46 +02:00
m_node.mempool.reset();
m_node.fee_estimator.reset();
m_node.chainman.reset();
m_node.scheduler.reset();
}
void ChainTestingSetup::LoadVerifyActivateChainstate()
test: Add new ChainTestingSetup and use it Previously, the validation_chainstatemanager_tests test suite instantiated its own duplicate ChainstateManager on which tests were performed. This wasn't a problem for the specific actions performed in that suite. However, the existence of this duplicate ChainstateManager and the fact that many of our validation static functions reach for g_chainman, ::Chain(state|)Active means we may end up acting on two different CChainStates should we write more extensive tests in the future. This change adds a new ChainTestingSetup which performs all initialization previously done by TestingSetup except: 1. RPC command registration 2. ChainState initialization 3. Genesis Activation 4. {Ban,Conn,Peer}Man initialization Means that we will no longer need to initialize a duplicate ChainstateManger in order to test the initialization codepaths of CChainState and ChainstateManager. Lastly, this change has the additional benefit of allowing for review-only assertions meant to show correctness to work in future work de-globalizing g_chainman. In the test chainstatemanager_rebalance_caches, an additional LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile], which is out of bounds when LoadGenesisBlock hasn't been called yet. ----- Note for the future: The class con/destructor inheritance structure we have for these TestingSetup classes is probably not the most suitable abstraction. In particular, for both TestingSetup and ChainTestingSetup, we need to stop the scheduler first before anything else. Otherwise classes depending on the scheduler may be referenced by the scheduler after said classes are freed. This means that there's no clear parallel between our teardown code and C++'s destructuring order for class hierarchies. Future work should strive to coalesce (as much as possible) test and non-test init codepaths and perhaps structure it in a more fail-proof way.
2020-10-13 16:55:20 -04:00
{
2023-01-16 17:23:18 +01:00
auto& chainman{*Assert(m_node.chainman)};
node::ChainstateLoadOptions options;
options.mempool = Assert(m_node.mempool.get());
options.block_tree_db_in_memory = m_block_tree_db_in_memory;
options.coins_db_in_memory = m_coins_db_in_memory;
options.reindex = node::fReindex;
options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false);
2023-01-16 17:23:18 +01:00
options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
options.require_full_verification = m_args.IsArgSet("-checkblocks") || m_args.IsArgSet("-checklevel");
2023-01-16 17:23:18 +01:00
auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options);
assert(status == node::ChainstateLoadStatus::SUCCESS);
2023-01-16 17:23:18 +01:00
std::tie(status, error) = VerifyLoadedChainstate(chainman, options);
assert(status == node::ChainstateLoadStatus::SUCCESS);
test: Add new ChainTestingSetup and use it Previously, the validation_chainstatemanager_tests test suite instantiated its own duplicate ChainstateManager on which tests were performed. This wasn't a problem for the specific actions performed in that suite. However, the existence of this duplicate ChainstateManager and the fact that many of our validation static functions reach for g_chainman, ::Chain(state|)Active means we may end up acting on two different CChainStates should we write more extensive tests in the future. This change adds a new ChainTestingSetup which performs all initialization previously done by TestingSetup except: 1. RPC command registration 2. ChainState initialization 3. Genesis Activation 4. {Ban,Conn,Peer}Man initialization Means that we will no longer need to initialize a duplicate ChainstateManger in order to test the initialization codepaths of CChainState and ChainstateManager. Lastly, this change has the additional benefit of allowing for review-only assertions meant to show correctness to work in future work de-globalizing g_chainman. In the test chainstatemanager_rebalance_caches, an additional LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile], which is out of bounds when LoadGenesisBlock hasn't been called yet. ----- Note for the future: The class con/destructor inheritance structure we have for these TestingSetup classes is probably not the most suitable abstraction. In particular, for both TestingSetup and ChainTestingSetup, we need to stop the scheduler first before anything else. Otherwise classes depending on the scheduler may be referenced by the scheduler after said classes are freed. This means that there's no clear parallel between our teardown code and C++'s destructuring order for class hierarchies. Future work should strive to coalesce (as much as possible) test and non-test init codepaths and perhaps structure it in a more fail-proof way.
2020-10-13 16:55:20 -04:00
BlockValidationState state;
2023-01-16 17:23:18 +01:00
if (!chainman.ActiveChainstate().ActivateBestChain(state)) {
test: Add new ChainTestingSetup and use it Previously, the validation_chainstatemanager_tests test suite instantiated its own duplicate ChainstateManager on which tests were performed. This wasn't a problem for the specific actions performed in that suite. However, the existence of this duplicate ChainstateManager and the fact that many of our validation static functions reach for g_chainman, ::Chain(state|)Active means we may end up acting on two different CChainStates should we write more extensive tests in the future. This change adds a new ChainTestingSetup which performs all initialization previously done by TestingSetup except: 1. RPC command registration 2. ChainState initialization 3. Genesis Activation 4. {Ban,Conn,Peer}Man initialization Means that we will no longer need to initialize a duplicate ChainstateManger in order to test the initialization codepaths of CChainState and ChainstateManager. Lastly, this change has the additional benefit of allowing for review-only assertions meant to show correctness to work in future work de-globalizing g_chainman. In the test chainstatemanager_rebalance_caches, an additional LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile], which is out of bounds when LoadGenesisBlock hasn't been called yet. ----- Note for the future: The class con/destructor inheritance structure we have for these TestingSetup classes is probably not the most suitable abstraction. In particular, for both TestingSetup and ChainTestingSetup, we need to stop the scheduler first before anything else. Otherwise classes depending on the scheduler may be referenced by the scheduler after said classes are freed. This means that there's no clear parallel between our teardown code and C++'s destructuring order for class hierarchies. Future work should strive to coalesce (as much as possible) test and non-test init codepaths and perhaps structure it in a more fail-proof way.
2020-10-13 16:55:20 -04:00
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
}
}
TestingSetup::TestingSetup(
const ChainType chainType,
const std::vector<const char*>& extra_args,
const bool coins_db_in_memory,
const bool block_tree_db_in_memory)
: ChainTestingSetup(chainType, extra_args)
{
m_coins_db_in_memory = coins_db_in_memory;
m_block_tree_db_in_memory = block_tree_db_in_memory;
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC);
LoadVerifyActivateChainstate();
test: Add new ChainTestingSetup and use it Previously, the validation_chainstatemanager_tests test suite instantiated its own duplicate ChainstateManager on which tests were performed. This wasn't a problem for the specific actions performed in that suite. However, the existence of this duplicate ChainstateManager and the fact that many of our validation static functions reach for g_chainman, ::Chain(state|)Active means we may end up acting on two different CChainStates should we write more extensive tests in the future. This change adds a new ChainTestingSetup which performs all initialization previously done by TestingSetup except: 1. RPC command registration 2. ChainState initialization 3. Genesis Activation 4. {Ban,Conn,Peer}Man initialization Means that we will no longer need to initialize a duplicate ChainstateManger in order to test the initialization codepaths of CChainState and ChainstateManager. Lastly, this change has the additional benefit of allowing for review-only assertions meant to show correctness to work in future work de-globalizing g_chainman. In the test chainstatemanager_rebalance_caches, an additional LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile], which is out of bounds when LoadGenesisBlock hasn't been called yet. ----- Note for the future: The class con/destructor inheritance structure we have for these TestingSetup classes is probably not the most suitable abstraction. In particular, for both TestingSetup and ChainTestingSetup, we need to stop the scheduler first before anything else. Otherwise classes depending on the scheduler may be referenced by the scheduler after said classes are freed. This means that there's no clear parallel between our teardown code and C++'s destructuring order for class hierarchies. Future work should strive to coalesce (as much as possible) test and non-test init codepaths and perhaps structure it in a more fail-proof way.
2020-10-13 16:55:20 -04:00
2021-08-31 18:40:18 +01:00
m_node.netgroupman = std::make_unique<NetGroupManager>(/*asmap=*/std::vector<bool>());
m_node.addrman = std::make_unique<AddrMan>(*m_node.netgroupman,
/*deterministic=*/false,
m_node.args->GetIntArg("-checkaddrman", 0));
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); // Deterministic randomness for tests.
PeerManager::Options peerman_opts;
ApplyArgsManOptions(*m_node.args, peerman_opts);
peerman_opts.deterministic_rng = true;
m_node.peerman = PeerManager::make(*m_node.connman, *m_node.addrman,
m_node.banman.get(), *m_node.chainman,
*m_node.mempool, peerman_opts);
test: Add new ChainTestingSetup and use it Previously, the validation_chainstatemanager_tests test suite instantiated its own duplicate ChainstateManager on which tests were performed. This wasn't a problem for the specific actions performed in that suite. However, the existence of this duplicate ChainstateManager and the fact that many of our validation static functions reach for g_chainman, ::Chain(state|)Active means we may end up acting on two different CChainStates should we write more extensive tests in the future. This change adds a new ChainTestingSetup which performs all initialization previously done by TestingSetup except: 1. RPC command registration 2. ChainState initialization 3. Genesis Activation 4. {Ban,Conn,Peer}Man initialization Means that we will no longer need to initialize a duplicate ChainstateManger in order to test the initialization codepaths of CChainState and ChainstateManager. Lastly, this change has the additional benefit of allowing for review-only assertions meant to show correctness to work in future work de-globalizing g_chainman. In the test chainstatemanager_rebalance_caches, an additional LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile], which is out of bounds when LoadGenesisBlock hasn't been called yet. ----- Note for the future: The class con/destructor inheritance structure we have for these TestingSetup classes is probably not the most suitable abstraction. In particular, for both TestingSetup and ChainTestingSetup, we need to stop the scheduler first before anything else. Otherwise classes depending on the scheduler may be referenced by the scheduler after said classes are freed. This means that there's no clear parallel between our teardown code and C++'s destructuring order for class hierarchies. Future work should strive to coalesce (as much as possible) test and non-test init codepaths and perhaps structure it in a more fail-proof way.
2020-10-13 16:55:20 -04:00
{
CConnman::Options options;
options.m_msgproc = m_node.peerman.get();
m_node.connman->Init(options);
}
}
TestChain100Setup::TestChain100Setup(
const ChainType chain_type,
const std::vector<const char*>& extra_args,
const bool coins_db_in_memory,
const bool block_tree_db_in_memory)
: TestingSetup{ChainType::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory}
{
SetMockTime(1598887952);
constexpr std::array<unsigned char, 32> vchKey = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
coinbaseKey.Set(vchKey.begin(), vchKey.end(), true);
// Generate a 100-block chain:
this->mineBlocks(COINBASE_MATURITY);
{
LOCK(::cs_main);
assert(
m_node.chainman->ActiveChain().Tip()->GetBlockHash().ToString() ==
"571d80a9967ae599cec0448b0b0ba1cfb606f584d8069bd7166b86854ba7a191");
}
}
void TestChain100Setup::mineBlocks(int num_blocks)
{
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
for (int i = 0; i < num_blocks; i++) {
std::vector<CMutableTransaction> noTxns;
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
SetMockTime(GetTime() + 1);
2018-04-11 13:51:28 -04:00
m_coinbase_txns.push_back(b.vtx[0]);
}
}
CBlock TestChain100Setup::CreateBlock(
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
Chainstate& chainstate)
{
CBlock block = BlockAssembler{chainstate, nullptr}.CreateNewBlock(scriptPubKey)->block;
Assert(block.vtx.size() == 1);
for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx));
}
RegenerateCommitments(block, *Assert(m_node.chainman));
while (!CheckProofOfWork(block.GetHash(), block.nBits, m_node.chainman->GetConsensus())) ++block.nNonce;
return block;
}
CBlock TestChain100Setup::CreateAndProcessBlock(
const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey,
Chainstate* chainstate)
{
if (!chainstate) {
chainstate = &Assert(m_node.chainman)->ActiveChainstate();
}
CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate);
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, true, nullptr);
return block;
}
std::pair<CMutableTransaction, CAmount> TestChain100Setup::CreateValidTransaction(const std::vector<CTransactionRef>& input_transactions,
const std::vector<COutPoint>& inputs,
int input_height,
const std::vector<CKey>& input_signing_keys,
const std::vector<CTxOut>& outputs,
const std::optional<CFeeRate>& feerate,
const std::optional<uint32_t>& fee_output)
{
CMutableTransaction mempool_txn;
mempool_txn.vin.reserve(inputs.size());
mempool_txn.vout.reserve(outputs.size());
for (const auto& outpoint : inputs) {
mempool_txn.vin.emplace_back(outpoint, CScript(), MAX_BIP125_RBF_SEQUENCE);
}
mempool_txn.vout = outputs;
// - Add the signing key to a keystore
FillableSigningProvider keystore;
for (const auto& input_signing_key : input_signing_keys) {
keystore.AddKey(input_signing_key);
}
// - Populate a CoinsViewCache with the unspent output
CCoinsView coins_view;
CCoinsViewCache coins_cache(&coins_view);
for (const auto& input_transaction : input_transactions) {
AddCoins(coins_cache, *input_transaction.get(), input_height);
}
// Build Outpoint to Coin map for SignTransaction
std::map<COutPoint, Coin> input_coins;
CAmount inputs_amount{0};
for (const auto& outpoint_to_spend : inputs) {
// - Use GetCoin to properly populate utxo_to_spend,
Coin utxo_to_spend;
assert(coins_cache.GetCoin(outpoint_to_spend, utxo_to_spend));
input_coins.insert({outpoint_to_spend, utxo_to_spend});
inputs_amount += utxo_to_spend.out.nValue;
}
// - Default signature hashing type
int nHashType = SIGHASH_ALL;
std::map<int, bilingual_str> input_errors;
assert(SignTransaction(mempool_txn, &keystore, input_coins, nHashType, input_errors));
CAmount current_fee = inputs_amount - std::accumulate(outputs.begin(), outputs.end(), CAmount(0),
[](const CAmount& acc, const CTxOut& out) {
return acc + out.nValue;
});
// Deduct fees from fee_output to meet feerate if set
if (feerate.has_value()) {
assert(fee_output.has_value());
assert(fee_output.value() < mempool_txn.vout.size());
CAmount target_fee = feerate.value().GetFee(GetVirtualTransactionSize(CTransaction{mempool_txn}));
CAmount deduction = target_fee - current_fee;
if (deduction > 0) {
// Only deduct fee if there's anything to deduct. If the caller has put more fees than
// the target feerate, don't change the fee.
mempool_txn.vout[fee_output.value()].nValue -= deduction;
// Re-sign since an output has changed
input_errors.clear();
assert(SignTransaction(mempool_txn, &keystore, input_coins, nHashType, input_errors));
current_fee = target_fee;
}
}
return {mempool_txn, current_fee};
}
CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(const std::vector<CTransactionRef>& input_transactions,
const std::vector<COutPoint>& inputs,
int input_height,
const std::vector<CKey>& input_signing_keys,
const std::vector<CTxOut>& outputs,
bool submit)
{
CMutableTransaction mempool_txn = CreateValidTransaction(input_transactions, inputs, input_height, input_signing_keys, outputs, std::nullopt, std::nullopt).first;
// If submit=true, add transaction to the mempool.
if (submit) {
LOCK(cs_main);
const MempoolAcceptResult result = m_node.chainman->ProcessTransaction(MakeTransactionRef(mempool_txn));
assert(result.m_result_type == MempoolAcceptResult::ResultType::VALID);
}
return mempool_txn;
}
CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(CTransactionRef input_transaction,
uint32_t input_vout,
int input_height,
CKey input_signing_key,
CScript output_destination,
CAmount output_amount,
bool submit)
{
COutPoint input{input_transaction->GetHash(), input_vout};
CTxOut output{output_amount, output_destination};
return CreateValidMempoolTransaction(/*input_transactions=*/{input_transaction},
/*inputs=*/{input},
/*input_height=*/input_height,
/*input_signing_keys=*/{input_signing_key},
/*outputs=*/{output},
/*submit=*/submit);
}
std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit)
{
std::vector<CTransactionRef> mempool_transactions;
std::deque<std::pair<COutPoint, CAmount>> unspent_prevouts;
std::transform(m_coinbase_txns.begin(), m_coinbase_txns.end(), std::back_inserter(unspent_prevouts),
[](const auto& tx){ return std::make_pair(COutPoint(tx->GetHash(), 0), tx->vout[0].nValue); });
while (num_transactions > 0 && !unspent_prevouts.empty()) {
// The number of inputs and outputs are random, between 1 and 24.
CMutableTransaction mtx = CMutableTransaction();
const size_t num_inputs = det_rand.randrange(24) + 1;
CAmount total_in{0};
for (size_t n{0}; n < num_inputs; ++n) {
if (unspent_prevouts.empty()) break;
const auto& [prevout, amount] = unspent_prevouts.front();
2023-10-04 13:53:40 +02:00
mtx.vin.emplace_back(prevout, CScript());
total_in += amount;
unspent_prevouts.pop_front();
}
const size_t num_outputs = det_rand.randrange(24) + 1;
const CAmount fee = 100 * det_rand.randrange(30);
const CAmount amount_per_output = (total_in - fee) / num_outputs;
for (size_t n{0}; n < num_outputs; ++n) {
CScript spk = CScript() << CScriptNum(num_transactions + n);
2023-10-04 13:53:40 +02:00
mtx.vout.emplace_back(amount_per_output, spk);
}
CTransactionRef ptx = MakeTransactionRef(mtx);
mempool_transactions.push_back(ptx);
if (amount_per_output > 3000) {
// If the value is high enough to fund another transaction + fees, keep track of it so
// it can be used to build a more complex transaction graph. Insert randomly into
// unspent_prevouts for extra randomness in the resulting structures.
for (size_t n{0}; n < num_outputs; ++n) {
2023-10-04 13:53:40 +02:00
unspent_prevouts.emplace_back(COutPoint(ptx->GetHash(), n), amount_per_output);
std::swap(unspent_prevouts.back(), unspent_prevouts[det_rand.randrange(unspent_prevouts.size())]);
}
}
if (submit) {
LOCK2(cs_main, m_node.mempool->cs);
LockPoints lp;
m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, /*fee=*/(total_in - num_outputs * amount_per_output),
/*time=*/0, /*entry_height=*/1, /*entry_sequence=*/0,
/*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
}
--num_transactions;
}
return mempool_transactions;
}
void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate)
{
LOCK2(cs_main, m_node.mempool->cs);
// Transactions in the mempool will affect the new minimum feerate.
assert(m_node.mempool->size() == 0);
// The target feerate cannot be too low...
// ...otherwise the transaction's feerate will need to be negative.
assert(target_feerate > m_node.mempool->m_incremental_relay_feerate);
// ...otherwise this is not meaningful. The feerate policy uses the maximum of both feerates.
assert(target_feerate > m_node.mempool->m_min_relay_feerate);
// Manually create an invalid transaction. Manually set the fee in the CTxMemPoolEntry to
// achieve the exact target feerate.
CMutableTransaction mtx = CMutableTransaction();
2023-10-11 14:53:04 +01:00
mtx.vin.emplace_back(COutPoint{Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0});
2023-10-04 13:53:40 +02:00
mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE)));
const auto tx{MakeTransactionRef(mtx)};
LockPoints lp;
// The new mempool min feerate is equal to the removed package's feerate + incremental feerate.
const auto tx_fee = target_feerate.GetFee(GetVirtualTransactionSize(*tx)) -
m_node.mempool->m_incremental_relay_feerate.GetFee(GetVirtualTransactionSize(*tx));
m_node.mempool->addUnchecked(CTxMemPoolEntry(tx, /*fee=*/tx_fee,
/*time=*/0, /*entry_height=*/1, /*entry_sequence=*/0,
/*spends_coinbase=*/true, /*sigops_cost=*/1, lp));
m_node.mempool->TrimToSize(0);
assert(m_node.mempool->GetMinFee() == target_feerate);
}
/**
* @returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
* with 9 txs.
*/
CBlock getBlock13b8a()
{
CBlock block;
2023-09-11 18:06:51 +02:00
DataStream stream{
ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0
};
stream >> TX_WITH_WITNESS(block);
return block;
}