| 574 | } |
| 575 | |
| 576 | std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit) |
| 577 | { |
| 578 | std::vector<CTransactionRef> mempool_transactions; |
| 579 | std::deque<std::pair<COutPoint, CAmount>> unspent_prevouts, undo_info; |
| 580 | std::transform(m_coinbase_txns.begin(), m_coinbase_txns.end(), std::back_inserter(unspent_prevouts), |
| 581 | [](const auto& tx){ return std::make_pair(COutPoint(tx->GetHash(), 0), tx->vout[0].nValue); }); |
| 582 | while (num_transactions > 0 && !unspent_prevouts.empty()) { |
| 583 | // The number of inputs and outputs are randomly chosen, between 1-5 |
| 584 | // and 1-25 respectively. |
| 585 | CMutableTransaction mtx = CMutableTransaction(); |
| 586 | const size_t num_inputs = det_rand.randrange(5) + 1; |
| 587 | CAmount total_in{0}; |
| 588 | for (size_t n{0}; n < num_inputs; ++n) { |
| 589 | if (unspent_prevouts.empty()) break; |
| 590 | const auto& [prevout, amount] = unspent_prevouts.front(); |
| 591 | undo_info.emplace_back(prevout, amount); |
| 592 | mtx.vin.emplace_back(prevout, CScript()); |
| 593 | total_in += amount; |
| 594 | unspent_prevouts.pop_front(); |
| 595 | } |
| 596 | const size_t num_outputs = det_rand.randrange(25) + 1; |
| 597 | const CAmount fee = 100 * det_rand.randrange(30); |
| 598 | const CAmount amount_per_output = (total_in - fee) / num_outputs; |
| 599 | for (size_t n{0}; n < num_outputs; ++n) { |
| 600 | CScript spk = CScript() << CScriptNum(num_transactions + n); |
| 601 | mtx.vout.emplace_back(amount_per_output, spk); |
| 602 | } |
| 603 | CTransactionRef ptx = MakeTransactionRef(mtx); |
| 604 | bool success{true}; |
| 605 | if (submit) { |
| 606 | LOCK2(cs_main, m_node.mempool->cs); |
| 607 | LockPoints lp; |
| 608 | auto changeset = m_node.mempool->GetChangeSet(); |
| 609 | changeset->StageAddition(ptx, /*fee=*/(total_in - num_outputs * amount_per_output), |
| 610 | /*time=*/0, /*entry_height=*/1, /*entry_sequence=*/0, |
| 611 | /*spends_coinbase=*/false, /*sigops_cost=*/4, lp); |
| 612 | if (changeset->CheckMemPoolPolicyLimits()) { |
| 613 | changeset->Apply(); |
| 614 | --num_transactions; |
| 615 | } else { |
| 616 | success = false; |
| 617 | // Add the inputs back to unspent prevouts |
| 618 | for (const auto& [prevout, amount] : undo_info) { |
| 619 | unspent_prevouts.emplace_back(prevout, amount); |
| 620 | std::swap(unspent_prevouts.back(), unspent_prevouts[det_rand.randrange(unspent_prevouts.size())]); |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | if (success) { |
| 625 | mempool_transactions.push_back(ptx); |
| 626 | if (amount_per_output > 3000) { |
| 627 | // If the value is high enough to fund another transaction + fees, keep track of it so |
| 628 | // it can be used to build a more complex transaction graph. Insert randomly into |
| 629 | // unspent_prevouts for extra randomness in the resulting structures. |
| 630 | for (size_t n{0}; n < num_outputs; ++n) { |
| 631 | unspent_prevouts.emplace_back(COutPoint(ptx->GetHash(), n), amount_per_output); |
| 632 | std::swap(unspent_prevouts.back(), unspent_prevouts[det_rand.randrange(unspent_prevouts.size())]); |
| 633 | } |
no test coverage detected