diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -156,6 +156,22 @@ //! Mine a series of new blocks on the active chain. void mineBlocks(int num_blocks); + /** + * Create a transaction and submit to the mempool. + * + * @param input_transaction The transaction to spend + * @param input_vout The vout to spend from the input_transaction + * @param input_height The height of the block that included the + * input_transaction + * @param input_signing_key The key to spend the input_transaction + * @param output_destination Where to send the output + * @param output_amount How much to send + */ + CMutableTransaction CreateValidMempoolTransaction( + CTransactionRef input_transaction, int input_vout, int input_height, + CKey input_signing_key, CScript output_destination, + Amount output_amount = COIN); + ~TestChain100Setup(); bool m_deterministic; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -325,6 +325,54 @@ return block; } +CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction( + CTransactionRef input_transaction, int input_vout, int input_height, + CKey input_signing_key, CScript output_destination, Amount output_amount) { + // Transaction we will submit to the mempool + CMutableTransaction mempool_txn; + + // Create an input + COutPoint outpoint_to_spend(input_transaction->GetId(), input_vout); + CTxIn input(outpoint_to_spend); + mempool_txn.vin.push_back(input); + + // Create an output + CTxOut output(output_amount, output_destination); + mempool_txn.vout.push_back(output); + + // Sign the transaction + // - Add the signing key to a keystore + FillableSigningProvider keystore; + keystore.AddKey(input_signing_key); + // - Populate a CoinsViewCache with the unspent output + CCoinsView coins_view; + CCoinsViewCache coins_cache(&coins_view); + AddCoins(coins_cache, *input_transaction.get(), input_height); + // - Use GetCoin to properly populate utxo_to_spend, + Coin utxo_to_spend; + assert(coins_cache.GetCoin(outpoint_to_spend, utxo_to_spend)); + // - Then add it to a map to pass in to SignTransaction + std::map input_coins; + input_coins.insert({outpoint_to_spend, utxo_to_spend}); + // - Default signature hashing type + SigHashType nHashType{SIGHASH_ALL}; + std::map input_errors; + assert(SignTransaction(mempool_txn, &keystore, input_coins, nHashType, + input_errors)); + + // Add transaction to the mempool + { + LOCK(cs_main); + const MempoolAcceptResult result = AcceptToMemoryPool( + m_node.chainman->ActiveChainstate(), GetConfig(), + *m_node.mempool.get(), MakeTransactionRef(mempool_txn), + /* bypass_limits */ false); + assert(result.m_result_type == MempoolAcceptResult::ResultType::VALID); + } + + return mempool_txn; +} + TestChain100Setup::~TestChain100Setup() { if (m_deterministic) { SetMockTime(0);