mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-24 12:41:41 -05:00

-BEGIN VERIFY SCRIPT- regex_string='^(?!//).*(AC_APPLE_UNIVERSAL_BUILD|BOOST_PROCESS_USE_STD_FS|CHAR_EQUALS_INT8|CLIENT_VERSION_BUILD|CLIENT_VERSION_IS_RELEASE|CLIENT_VERSION_MAJOR|CLIENT_VERSION_MINOR|COPYRIGHT_HOLDERS|COPYRIGHT_HOLDERS_FINAL|COPYRIGHT_HOLDERS_SUBSTITUTION|COPYRIGHT_YEAR|ENABLE_ARM_SHANI|ENABLE_AVX2|ENABLE_EXTERNAL_SIGNER|ENABLE_SSE41|ENABLE_TRACING|ENABLE_WALLET|ENABLE_X86_SHANI|ENABLE_ZMQ|HAVE_BOOST|HAVE_BUILTIN_CLZL|HAVE_BUILTIN_CLZLL|HAVE_BYTESWAP_H|HAVE_CLMUL|HAVE_CONSENSUS_LIB|HAVE_CXX20|HAVE_DECL_BE16TOH|HAVE_DECL_BE32TOH|HAVE_DECL_BE64TOH|HAVE_DECL_BSWAP_16|HAVE_DECL_BSWAP_32|HAVE_DECL_BSWAP_64|HAVE_DECL_FORK|HAVE_DECL_FREEIFADDRS|HAVE_DECL_GETIFADDRS|HAVE_DECL_HTOBE16|HAVE_DECL_HTOBE32|HAVE_DECL_HTOBE64|HAVE_DECL_HTOLE16|HAVE_DECL_HTOLE32|HAVE_DECL_HTOLE64|HAVE_DECL_LE16TOH|HAVE_DECL_LE32TOH|HAVE_DECL_LE64TOH|HAVE_DECL_PIPE2|HAVE_DECL_SETSID|HAVE_DECL_STRERROR_R|HAVE_DEFAULT_VISIBILITY_ATTRIBUTE|HAVE_DLFCN_H|HAVE_DLLEXPORT_ATTRIBUTE|HAVE_ENDIAN_H|HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR|HAVE_FDATASYNC|HAVE_GETENTROPY_RAND|HAVE_GETRANDOM|HAVE_GMTIME_R|HAVE_INTTYPES_H|HAVE_LIBADVAPI32|HAVE_LIBCOMCTL32|HAVE_LIBCOMDLG32|HAVE_LIBGDI32|HAVE_LIBIPHLPAPI|HAVE_LIBKERNEL32|HAVE_LIBOLE32|HAVE_LIBOLEAUT32|HAVE_LIBSHELL32|HAVE_LIBSHLWAPI|HAVE_LIBUSER32|HAVE_LIBUUID|HAVE_LIBWINMM|HAVE_LIBWS2_32|HAVE_MALLOC_INFO|HAVE_MALLOPT_ARENA_MAX|HAVE_MINIUPNPC_MINIUPNPC_H|HAVE_MINIUPNPC_UPNPCOMMANDS_H|HAVE_MINIUPNPC_UPNPERRORS_H|HAVE_NATPMP_H|HAVE_O_CLOEXEC|HAVE_POSIX_FALLOCATE|HAVE_PTHREAD|HAVE_PTHREAD_PRIO_INHERIT|HAVE_STDINT_H|HAVE_STDIO_H|HAVE_STDLIB_H|HAVE_STRERROR_R|HAVE_STRINGS_H|HAVE_STRING_H|HAVE_STRONG_GETAUXVAL|HAVE_SYSCTL|HAVE_SYSCTL_ARND|HAVE_SYSTEM|HAVE_SYS_ENDIAN_H|HAVE_SYS_PRCTL_H|HAVE_SYS_RESOURCES_H|HAVE_SYS_SELECT_H|HAVE_SYS_STAT_H|HAVE_SYS_SYSCTL_H|HAVE_SYS_TYPES_H|HAVE_SYS_VMMETER_H|HAVE_THREAD_LOCAL|HAVE_TIMINGSAFE_BCMP|HAVE_UNISTD_H|HAVE_VM_VM_PARAM_H|LT_OBJDIR|PACKAGE_BUGREPORT|PACKAGE_NAME|PACKAGE_STRING|PACKAGE_TARNAME|PACKAGE_URL|PACKAGE_VERSION|PTHREAD_CREATE_JOINABLE|QT_QPA_PLATFORM_ANDROID|QT_QPA_PLATFORM_COCOA|QT_QPA_PLATFORM_MINIMAL|QT_QPA_PLATFORM_WINDOWS|QT_QPA_PLATFORM_XCB|QT_STATICPLUGIN|STDC_HEADERS|STRERROR_R_CHAR_P|USE_ASM|USE_BDB|USE_DBUS|USE_NATPMP|USE_QRCODE|USE_SQLITE|USE_UPNP|_FILE_OFFSET_BITS|_LARGE_FILES)' exclusion_files=":(exclude)src/minisketch :(exclude)src/crc32c :(exclude)src/secp256k1 :(exclude)src/crypto/sha256_arm_shani.cpp :(exclude)src/crypto/sha256_avx2.cpp :(exclude)src/crypto/sha256_sse41.cpp :(exclude)src/crypto/sha256_x86_shani.cpp" git grep --perl-regexp --files-with-matches "$regex_string" -- '*.cpp' $exclusion_files | xargs git grep -L "bitcoin-config.h" | while read -r file; do line_number=$(awk -v my_file="$file" '/\/\/ file COPYING or https?:\/\/www.opensource.org\/licenses\/mit-license.php\./ {line = NR} /^\/\// && NR == line + 1 {while(getline && /^\/\//) line = NR} END {print line+1}' "$file"); sed -i "${line_number}i\\\\n\#if defined(HAVE_CONFIG_H)\\n#include <config/bitcoin-config.h>\\n\#endif" "$file"; done; git grep --perl-regexp --files-with-matches "$regex_string" -- '*.h' $exclusion_files | xargs git grep -L "bitcoin-config.h" | while read -r file; do sed -i "/#define.*_H/a \\\\n\#if defined(HAVE_CONFIG_H)\\n#include <config/bitcoin-config.h>\\n\#endif" "$file"; done; for file in $(git grep --files-with-matches 'bitcoin-config.h' -- '*.cpp' '*.h' $exclusion_files); do if ! grep -q --perl-regexp "$regex_string" $file; then sed -i '/HAVE_CONFIG_H/{N;N;N;d;}' $file; fi; done; -END VERIFY SCRIPT- The first command creates a regular expression for matching all bitcoin-config.h symbols in the following form: ^(?!//).*(AC_APPLE_UNIVERSAL_BUILD|BOOST_PROCESS_USE_STD_FS|...|_LARGE_FILES). It was generated with: ./autogen.sh && printf '^(?!//).*(%s)' $(awk '/^#undef/ {print $2}' src/config/bitcoin-config.h.in | paste -sd "|" -) The second command holds a list of files and directories that should not be processed. These include subtree directories as well as some crypto files that already get their symbols through the makefile. The third command checks for missing bitcoin-config headers in .cpp files and adds the header if it is missing. The fourth command checks for missing bitcoin-config headers in .h files and adds the header if it is missing. The fifth command checks for unneeded bitcoin-config headers in sources files and removes the header if it is unneeded.
537 lines
28 KiB
C++
537 lines
28 KiB
C++
// Copyright (c) 2011-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include <config/bitcoin-config.h>
|
|
#endif
|
|
|
|
#include <test/util/setup_common.h>
|
|
|
|
#include <kernel/validation_cache_sizes.h>
|
|
|
|
#include <addrman.h>
|
|
#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>
|
|
#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>
|
|
#include <node/blockstorage.h>
|
|
#include <node/chainstate.h>
|
|
#include <node/context.h>
|
|
#include <node/kernel_notifications.h>
|
|
#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>
|
|
#include <txmempool.h>
|
|
#include <util/chaintype.h>
|
|
#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;
|
|
}
|
|
|
|
struct NetworkSetup
|
|
{
|
|
NetworkSetup()
|
|
{
|
|
Assert(SetupNetworking());
|
|
}
|
|
};
|
|
static NetworkSetup g_networksetup_instance;
|
|
|
|
BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args)
|
|
: 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);
|
|
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
|
|
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);
|
|
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,
|
|
.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});
|
|
}
|
|
|
|
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();
|
|
m_node.netgroupman.reset();
|
|
m_node.args = nullptr;
|
|
m_node.mempool.reset();
|
|
m_node.fee_estimator.reset();
|
|
m_node.chainman.reset();
|
|
m_node.scheduler.reset();
|
|
}
|
|
|
|
void ChainTestingSetup::LoadVerifyActivateChainstate()
|
|
{
|
|
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);
|
|
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");
|
|
auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options);
|
|
assert(status == node::ChainstateLoadStatus::SUCCESS);
|
|
|
|
std::tie(status, error) = VerifyLoadedChainstate(chainman, options);
|
|
assert(status == node::ChainstateLoadStatus::SUCCESS);
|
|
|
|
BlockValidationState state;
|
|
if (!chainman.ActiveChainstate().ActivateBestChain(state)) {
|
|
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();
|
|
|
|
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);
|
|
|
|
{
|
|
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);
|
|
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();
|
|
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);
|
|
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) {
|
|
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();
|
|
mtx.vin.emplace_back(COutPoint{Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0});
|
|
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;
|
|
DataStream stream{
|
|
ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"),
|
|
};
|
|
stream >> TX_WITH_WITNESS(block);
|
|
return block;
|
|
}
|