Skip to content

Commit 2118750

Browse files
committed
[test util] to populate mempool with random transactions/packages
1 parent 5374dfc commit 2118750

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

src/test/util/setup_common.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <validationinterface.h>
4444
#include <walletinitinterface.h>
4545

46+
#include <algorithm>
4647
#include <functional>
4748
#include <stdexcept>
4849

@@ -357,6 +358,52 @@ CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(CTransactio
357358
return mempool_txn;
358359
}
359360

361+
std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit)
362+
{
363+
std::vector<CTransactionRef> mempool_transactions;
364+
std::deque<std::pair<COutPoint, CAmount>> unspent_prevouts;
365+
std::transform(m_coinbase_txns.begin(), m_coinbase_txns.end(), std::back_inserter(unspent_prevouts),
366+
[](const auto& tx){ return std::make_pair(COutPoint(tx->GetHash(), 0), tx->vout[0].nValue); });
367+
while (num_transactions > 0 && !unspent_prevouts.empty()) {
368+
// The number of inputs and outputs are random, between 1 and 24.
369+
CMutableTransaction mtx = CMutableTransaction();
370+
const size_t num_inputs = det_rand.randrange(24) + 1;
371+
CAmount total_in{0};
372+
for (size_t n{0}; n < num_inputs; ++n) {
373+
if (unspent_prevouts.empty()) break;
374+
const auto& [prevout, amount] = unspent_prevouts.front();
375+
mtx.vin.push_back(CTxIn(prevout, CScript()));
376+
total_in += amount;
377+
unspent_prevouts.pop_front();
378+
}
379+
const size_t num_outputs = det_rand.randrange(24) + 1;
380+
// Approximately 1000sat "fee," equal output amounts.
381+
const CAmount amount_per_output = (total_in - 1000) / num_outputs;
382+
for (size_t n{0}; n < num_outputs; ++n) {
383+
CScript spk = CScript() << CScriptNum(num_transactions + n);
384+
mtx.vout.push_back(CTxOut(amount_per_output, spk));
385+
}
386+
CTransactionRef ptx = MakeTransactionRef(mtx);
387+
mempool_transactions.push_back(ptx);
388+
if (amount_per_output > 2000) {
389+
// If the value is high enough to fund another transaction + fees, keep track of it so
390+
// it can be used to build a more complex transaction graph. Insert randomly into
391+
// unspent_prevouts for extra randomness in the resulting structures.
392+
for (size_t n{0}; n < num_outputs; ++n) {
393+
unspent_prevouts.push_back(std::make_pair(COutPoint(ptx->GetHash(), n), amount_per_output));
394+
std::swap(unspent_prevouts.back(), unspent_prevouts[det_rand.randrange(unspent_prevouts.size())]);
395+
}
396+
}
397+
if (submit) {
398+
LOCK2(m_node.mempool->cs, cs_main);
399+
LockPoints lp;
400+
m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, 1000, 0, 1, false, 4, lp));
401+
}
402+
--num_transactions;
403+
}
404+
return mempool_transactions;
405+
}
406+
360407
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const
361408
{
362409
return FromTx(MakeTransactionRef(tx));

src/test/util/setup_common.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ struct TestChain100Setup : public TestingSetup {
165165
CAmount output_amount = CAmount(1 * COIN),
166166
bool submit = true);
167167

168+
/** Create transactions spending from m_coinbase_txns. These transactions will only spend coins
169+
* that exist in the current chain, but may be premature coinbase spends, have missing
170+
* signatures, or violate some other consensus rules. They should only be used for testing
171+
* mempool consistency. All transactions will have some random number of inputs and outputs
172+
* (between 1 and 24). Transactions may or may not be dependent upon each other; if dependencies
173+
* exit, every parent will always be somewhere in the list before the child so each transaction
174+
* can be submitted in the same order they appear in the list.
175+
* @param[in] submit When true, submit transactions to the mempool.
176+
* When false, return them but don't submit them.
177+
* @returns A vector of transactions that can be submitted to the mempool.
178+
*/
179+
std::vector<CTransactionRef> PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit);
180+
168181
std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions
169182
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
170183
};

0 commit comments

Comments
 (0)