aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorglozow <gloriajzhao@gmail.com>2022-04-20 14:04:11 -0700
committerglozow <gloriajzhao@gmail.com>2022-05-30 16:00:41 -0700
commit21187506311d1703d2bca21ccc17c3a921454b70 (patch)
treef3d589b7bbb7a77f8d8d666f0d967fb8bc8ab661 /src/test
parent5374dfc4e3da0e6a76f33b42966b4acf446233dc (diff)
[test util] to populate mempool with random transactions/packages
Diffstat (limited to 'src/test')
-rw-r--r--src/test/util/setup_common.cpp47
-rw-r--r--src/test/util/setup_common.h13
2 files changed, 60 insertions, 0 deletions
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 76bdf37cd7..01f41ccf82 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -43,6 +43,7 @@
#include <validationinterface.h>
#include <walletinitinterface.h>
+#include <algorithm>
#include <functional>
#include <stdexcept>
@@ -357,6 +358,52 @@ CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(CTransactio
return mempool_txn;
}
+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.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 dd01afe087..4270eb18c6 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<CTransactionRef> PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit);
+
std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
};