From 21187506311d1703d2bca21ccc17c3a921454b70 Mon Sep 17 00:00:00 2001 From: glozow Date: Wed, 20 Apr 2022 14:04:11 -0700 Subject: [PATCH] [test util] to populate mempool with random transactions/packages --- src/test/util/setup_common.cpp | 47 ++++++++++++++++++++++++++++++++++ src/test/util/setup_common.h | 13 ++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 76bdf37cd7d..01f41ccf820 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -357,6 +358,52 @@ CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(CTransactio return mempool_txn; } +std::vector TestChain100Setup::PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit) +{ + std::vector mempool_transactions; + std::deque> 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.push_back(CTxIn(prevout, CScript())); + total_in += amount; + unspent_prevouts.pop_front(); + } + const size_t num_outputs = det_rand.randrange(24) + 1; + // Approximately 1000sat "fee," equal output amounts. + const CAmount amount_per_output = (total_in - 1000) / num_outputs; + for (size_t n{0}; n < num_outputs; ++n) { + CScript spk = CScript() << CScriptNum(num_transactions + n); + mtx.vout.push_back(CTxOut(amount_per_output, spk)); + } + CTransactionRef ptx = MakeTransactionRef(mtx); + mempool_transactions.push_back(ptx); + if (amount_per_output > 2000) { + // 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.push_back(std::make_pair(COutPoint(ptx->GetHash(), n), amount_per_output)); + std::swap(unspent_prevouts.back(), unspent_prevouts[det_rand.randrange(unspent_prevouts.size())]); + } + } + if (submit) { + LOCK2(m_node.mempool->cs, cs_main); + LockPoints lp; + m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, 1000, 0, 1, false, 4, lp)); + } + --num_transactions; + } + return mempool_transactions; +} + CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const { return FromTx(MakeTransactionRef(tx)); diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index dd01afe0870..4270eb18c61 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -165,6 +165,19 @@ struct TestChain100Setup : public TestingSetup { CAmount output_amount = CAmount(1 * COIN), bool submit = true); + /** Create transactions spending from m_coinbase_txns. These transactions will only spend coins + * that exist in the current chain, but may be premature coinbase spends, have missing + * signatures, or violate some other consensus rules. They should only be used for testing + * mempool consistency. All transactions will have some random number of inputs and outputs + * (between 1 and 24). Transactions may or may not be dependent upon each other; if dependencies + * exit, every parent will always be somewhere in the list before the child so each transaction + * can be submitted in the same order they appear in the list. + * @param[in] submit When true, submit transactions to the mempool. + * When false, return them but don't submit them. + * @returns A vector of transactions that can be submitted to the mempool. + */ + std::vector PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit); + std::vector m_coinbase_txns; // For convenience, coinbase transactions CKey coinbaseKey; // private/public key needed to spend coinbase transactions };