/ src / test / txpackage_tests.cpp
txpackage_tests.cpp
  1  // Copyright (c) 2021-2022 The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #include <consensus/validation.h>
  6  #include <key_io.h>
  7  #include <policy/packages.h>
  8  #include <policy/policy.h>
  9  #include <primitives/transaction.h>
 10  #include <script/script.h>
 11  #include <test/util/random.h>
 12  #include <test/util/script.h>
 13  #include <test/util/setup_common.h>
 14  #include <test/util/txmempool.h>
 15  #include <validation.h>
 16  
 17  #include <boost/test/unit_test.hpp>
 18  
 19  BOOST_AUTO_TEST_SUITE(txpackage_tests)
 20  // A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these
 21  // unit tests.
 22  static const CAmount low_fee_amt{200};
 23  
 24  // Create placeholder transactions that have no meaning.
 25  inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
 26  {
 27      CMutableTransaction mtx = CMutableTransaction();
 28      mtx.vin.resize(num_inputs);
 29      mtx.vout.resize(num_outputs);
 30      auto random_script = CScript() << ToByteVector(InsecureRand256()) << ToByteVector(InsecureRand256());
 31      for (size_t i{0}; i < num_inputs; ++i) {
 32          mtx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256());
 33          mtx.vin[i].prevout.n = 0;
 34          mtx.vin[i].scriptSig = random_script;
 35      }
 36      for (size_t o{0}; o < num_outputs; ++o) {
 37          mtx.vout[o].nValue = 1 * CENT;
 38          mtx.vout[o].scriptPubKey = random_script;
 39      }
 40      return MakeTransactionRef(mtx);
 41  }
 42  
 43  BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
 44  {
 45      // Packages can't have more than 25 transactions.
 46      Package package_too_many;
 47      package_too_many.reserve(MAX_PACKAGE_COUNT + 1);
 48      for (size_t i{0}; i < MAX_PACKAGE_COUNT + 1; ++i) {
 49          package_too_many.emplace_back(create_placeholder_tx(1, 1));
 50      }
 51      PackageValidationState state_too_many;
 52      BOOST_CHECK(!IsWellFormedPackage(package_too_many, state_too_many, /*require_sorted=*/true));
 53      BOOST_CHECK_EQUAL(state_too_many.GetResult(), PackageValidationResult::PCKG_POLICY);
 54      BOOST_CHECK_EQUAL(state_too_many.GetRejectReason(), "package-too-many-transactions");
 55  
 56      // Packages can't have a total weight of more than 404'000WU.
 57      CTransactionRef large_ptx = create_placeholder_tx(150, 150);
 58      Package package_too_large;
 59      auto size_large = GetTransactionWeight(*large_ptx);
 60      size_t total_weight{0};
 61      while (total_weight <= MAX_PACKAGE_WEIGHT) {
 62          package_too_large.push_back(large_ptx);
 63          total_weight += size_large;
 64      }
 65      BOOST_CHECK(package_too_large.size() <= MAX_PACKAGE_COUNT);
 66      PackageValidationState state_too_large;
 67      BOOST_CHECK(!IsWellFormedPackage(package_too_large, state_too_large, /*require_sorted=*/true));
 68      BOOST_CHECK_EQUAL(state_too_large.GetResult(), PackageValidationResult::PCKG_POLICY);
 69      BOOST_CHECK_EQUAL(state_too_large.GetRejectReason(), "package-too-large");
 70  
 71      // Packages can't contain transactions with the same txid.
 72      Package package_duplicate_txids_empty;
 73      for (auto i{0}; i < 3; ++i) {
 74          CMutableTransaction empty_tx;
 75          package_duplicate_txids_empty.emplace_back(MakeTransactionRef(empty_tx));
 76      }
 77      PackageValidationState state_duplicates;
 78      BOOST_CHECK(!IsWellFormedPackage(package_duplicate_txids_empty, state_duplicates, /*require_sorted=*/true));
 79      BOOST_CHECK_EQUAL(state_duplicates.GetResult(), PackageValidationResult::PCKG_POLICY);
 80      BOOST_CHECK_EQUAL(state_duplicates.GetRejectReason(), "package-contains-duplicates");
 81      BOOST_CHECK(!IsConsistentPackage(package_duplicate_txids_empty));
 82  
 83      // Packages can't have transactions spending the same prevout
 84      CMutableTransaction tx_zero_1;
 85      CMutableTransaction tx_zero_2;
 86      COutPoint same_prevout{Txid::FromUint256(InsecureRand256()), 0};
 87      tx_zero_1.vin.emplace_back(same_prevout);
 88      tx_zero_2.vin.emplace_back(same_prevout);
 89      // Different vouts (not the same tx)
 90      tx_zero_1.vout.emplace_back(CENT, P2WSH_OP_TRUE);
 91      tx_zero_2.vout.emplace_back(2 * CENT, P2WSH_OP_TRUE);
 92      Package package_conflicts{MakeTransactionRef(tx_zero_1), MakeTransactionRef(tx_zero_2)};
 93      BOOST_CHECK(!IsConsistentPackage(package_conflicts));
 94      // Transactions are considered sorted when they have no dependencies.
 95      BOOST_CHECK(IsTopoSortedPackage(package_conflicts));
 96      PackageValidationState state_conflicts;
 97      BOOST_CHECK(!IsWellFormedPackage(package_conflicts, state_conflicts, /*require_sorted=*/true));
 98      BOOST_CHECK_EQUAL(state_conflicts.GetResult(), PackageValidationResult::PCKG_POLICY);
 99      BOOST_CHECK_EQUAL(state_conflicts.GetRejectReason(), "conflict-in-package");
100  
101      // IsConsistentPackage only cares about conflicts between transactions, not about a transaction
102      // conflicting with itself (i.e. duplicate prevouts in vin).
103      CMutableTransaction dup_tx;
104      const COutPoint rand_prevout{Txid::FromUint256(InsecureRand256()), 0};
105      dup_tx.vin.emplace_back(rand_prevout);
106      dup_tx.vin.emplace_back(rand_prevout);
107      Package package_with_dup_tx{MakeTransactionRef(dup_tx)};
108      BOOST_CHECK(IsConsistentPackage(package_with_dup_tx));
109      package_with_dup_tx.emplace_back(create_placeholder_tx(1, 1));
110      BOOST_CHECK(IsConsistentPackage(package_with_dup_tx));
111  }
112  
113  BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
114  {
115      LOCK(cs_main);
116      unsigned int initialPoolSize = m_node.mempool->size();
117  
118      // Parent and Child Package
119      CKey parent_key = GenerateRandomKey();
120      CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
121      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
122                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
123                                                      /*output_destination=*/parent_locking_script,
124                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
125      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
126  
127      CKey child_key = GenerateRandomKey();
128      CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
129      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
130                                                     /*input_height=*/101, /*input_signing_key=*/parent_key,
131                                                     /*output_destination=*/child_locking_script,
132                                                     /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
133      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
134      Package package_parent_child{tx_parent, tx_child};
135      const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_parent_child, /*test_accept=*/true, /*client_maxfeerate=*/{});
136      if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_parent_child, result_parent_child, /*expect_valid=*/true, nullptr)}) {
137          BOOST_ERROR(err_parent_child.value());
138      } else {
139          auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
140          auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
141  
142          BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == COIN);
143          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
144          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
145  
146          BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == COIN);
147          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
148          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
149      }
150      // A single, giant transaction submitted through ProcessNewPackage fails on single tx policy.
151      CTransactionRef giant_ptx = create_placeholder_tx(999, 999);
152      BOOST_CHECK(GetVirtualTransactionSize(*giant_ptx) > DEFAULT_ANCESTOR_SIZE_LIMIT_KVB * 1000);
153      Package package_single_giant{giant_ptx};
154      auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_single_giant, /*test_accept=*/true, /*client_maxfeerate=*/{});
155      if (auto err_single_large{CheckPackageMempoolAcceptResult(package_single_giant, result_single_large, /*expect_valid=*/false, nullptr)}) {
156          BOOST_ERROR(err_single_large.value());
157      } else {
158          BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX);
159          BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed");
160          auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
161          BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size");
162      }
163  
164      // Check that mempool size hasn't changed.
165      BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
166  }
167  
168  BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
169  {
170      // The signatures won't be verified so we can just use a placeholder
171      CKey placeholder_key = GenerateRandomKey();
172      CScript spk = GetScriptForDestination(PKHash(placeholder_key.GetPubKey()));
173      CKey placeholder_key_2 = GenerateRandomKey();
174      CScript spk2 = GetScriptForDestination(PKHash(placeholder_key_2.GetPubKey()));
175  
176      // Parent and Child Package
177      {
178          auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
179                                                          CAmount(49 * COIN), /*submit=*/false);
180          CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
181  
182          auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
183                                                         CAmount(48 * COIN), /*submit=*/false);
184          CTransactionRef tx_child = MakeTransactionRef(mtx_child);
185  
186          PackageValidationState state;
187          BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_child}, state, /*require_sorted=*/true));
188          BOOST_CHECK(!IsWellFormedPackage({tx_child, tx_parent}, state, /*require_sorted=*/true));
189          BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);
190          BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
191          BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
192          BOOST_CHECK(IsChildWithParentsTree({tx_parent, tx_child}));
193      }
194  
195      // 24 Parents and 1 Child
196      {
197          Package package;
198          CMutableTransaction child;
199          for (int i{0}; i < 24; ++i) {
200              auto parent = MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
201                                               0, 0, coinbaseKey, spk, CAmount(48 * COIN), false));
202              package.emplace_back(parent);
203              child.vin.emplace_back(COutPoint(parent->GetHash(), 0));
204          }
205          child.vout.emplace_back(47 * COIN, spk2);
206  
207          // The child must be in the package.
208          BOOST_CHECK(!IsChildWithParents(package));
209  
210          // The parents can be in any order.
211          FastRandomContext rng;
212          Shuffle(package.begin(), package.end(), rng);
213          package.push_back(MakeTransactionRef(child));
214  
215          PackageValidationState state;
216          BOOST_CHECK(IsWellFormedPackage(package, state, /*require_sorted=*/true));
217          BOOST_CHECK(IsChildWithParents(package));
218          BOOST_CHECK(IsChildWithParentsTree(package));
219  
220          package.erase(package.begin());
221          BOOST_CHECK(IsChildWithParents(package));
222  
223          // The package cannot have unrelated transactions.
224          package.insert(package.begin(), m_coinbase_txns[0]);
225          BOOST_CHECK(!IsChildWithParents(package));
226      }
227  
228      // 2 Parents and 1 Child where one parent depends on the other.
229      {
230          CMutableTransaction mtx_parent;
231          mtx_parent.vin.emplace_back(COutPoint(m_coinbase_txns[0]->GetHash(), 0));
232          mtx_parent.vout.emplace_back(20 * COIN, spk);
233          mtx_parent.vout.emplace_back(20 * COIN, spk2);
234          CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
235  
236          CMutableTransaction mtx_parent_also_child;
237          mtx_parent_also_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 0));
238          mtx_parent_also_child.vout.emplace_back(20 * COIN, spk);
239          CTransactionRef tx_parent_also_child = MakeTransactionRef(mtx_parent_also_child);
240  
241          CMutableTransaction mtx_child;
242          mtx_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 1));
243          mtx_child.vin.emplace_back(COutPoint(tx_parent_also_child->GetHash(), 0));
244          mtx_child.vout.emplace_back(39 * COIN, spk);
245          CTransactionRef tx_child = MakeTransactionRef(mtx_child);
246  
247          PackageValidationState state;
248          BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child}));
249          BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
250          BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child, tx_child}));
251          BOOST_CHECK(!IsChildWithParentsTree({tx_parent, tx_parent_also_child, tx_child}));
252          // IsChildWithParents does not detect unsorted parents.
253          BOOST_CHECK(IsChildWithParents({tx_parent_also_child, tx_parent, tx_child}));
254          BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_parent_also_child, tx_child}, state, /*require_sorted=*/true));
255          BOOST_CHECK(!IsWellFormedPackage({tx_parent_also_child, tx_parent, tx_child}, state, /*require_sorted=*/true));
256          BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);
257          BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
258      }
259  }
260  
261  BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup)
262  {
263      LOCK(cs_main);
264      unsigned int expected_pool_size = m_node.mempool->size();
265      CKey parent_key = GenerateRandomKey();
266      CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
267  
268      // Unrelated transactions are not allowed in package submission.
269      Package package_unrelated;
270      for (size_t i{0}; i < 10; ++i) {
271          auto mtx = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[i + 25], /*input_vout=*/0,
272                                                   /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
273                                                   /*output_destination=*/parent_locking_script,
274                                                   /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
275          package_unrelated.emplace_back(MakeTransactionRef(mtx));
276      }
277      auto result_unrelated_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
278                                                       package_unrelated, /*test_accept=*/false, /*client_maxfeerate=*/{});
279      // We don't expect m_tx_results for each transaction when basic sanity checks haven't passed.
280      BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
281      BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
282      BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
283      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
284  
285      // Parent and Child (and Grandchild) Package
286      Package package_parent_child;
287      Package package_3gen;
288      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
289                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
290                                                      /*output_destination=*/parent_locking_script,
291                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
292      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
293      package_parent_child.push_back(tx_parent);
294      package_3gen.push_back(tx_parent);
295  
296      CKey child_key = GenerateRandomKey();
297      CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
298      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
299                                                     /*input_height=*/101, /*input_signing_key=*/parent_key,
300                                                     /*output_destination=*/child_locking_script,
301                                                     /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
302      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
303      package_parent_child.push_back(tx_child);
304      package_3gen.push_back(tx_child);
305  
306      CKey grandchild_key = GenerateRandomKey();
307      CScript grandchild_locking_script = GetScriptForDestination(PKHash(grandchild_key.GetPubKey()));
308      auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/tx_child, /*input_vout=*/0,
309                                                         /*input_height=*/101, /*input_signing_key=*/child_key,
310                                                         /*output_destination=*/grandchild_locking_script,
311                                                         /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
312      CTransactionRef tx_grandchild = MakeTransactionRef(mtx_grandchild);
313      package_3gen.push_back(tx_grandchild);
314  
315      // 3 Generations is not allowed.
316      {
317          auto result_3gen_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
318                                                      package_3gen, /*test_accept=*/false, /*client_maxfeerate=*/{});
319          BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
320          BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
321          BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
322          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
323      }
324  
325      // Parent and child package where transactions are invalid for reasons other than fee and
326      // missing inputs, so the package validation isn't expected to happen.
327      {
328          CScriptWitness bad_witness;
329          bad_witness.stack.emplace_back(1);
330          CMutableTransaction mtx_parent_invalid{mtx_parent};
331          mtx_parent_invalid.vin[0].scriptWitness = bad_witness;
332          CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid);
333          Package package_invalid_parent{tx_parent_invalid, tx_child};
334          auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
335                                                     package_invalid_parent, /*test_accept=*/ false, /*client_maxfeerate=*/{});
336          if (auto err_parent_invalid{CheckPackageMempoolAcceptResult(package_invalid_parent, result_quit_early, /*expect_valid=*/false, m_node.mempool.get())}) {
337              BOOST_ERROR(err_parent_invalid.value());
338          } else {
339              auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
340              auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
341              BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED);
342              BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard");
343              BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);
344              BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");
345          }
346          BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX);
347      }
348  
349      // Child with missing parent.
350      mtx_child.vin.emplace_back(COutPoint(package_unrelated[0]->GetHash(), 0));
351      Package package_missing_parent;
352      package_missing_parent.push_back(tx_parent);
353      package_missing_parent.push_back(MakeTransactionRef(mtx_child));
354      {
355          const auto result_missing_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
356                                                               package_missing_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
357          BOOST_CHECK(result_missing_parent.m_state.IsInvalid());
358          BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
359          BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(), "package-not-child-with-unconfirmed-parents");
360          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
361      }
362  
363      // Submit package with parent + child.
364      {
365          const auto submit_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
366                                                             package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
367          expected_pool_size += 2;
368          BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
369                              "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
370          BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
371          auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
372          auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
373          BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
374          BOOST_CHECK(it_parent->second.m_state.IsValid());
375          BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent)));
376          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
377          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
378          BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child)));
379          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
380          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
381  
382          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
383      }
384  
385      // Already-in-mempool transactions should be detected and de-duplicated.
386      {
387          const auto submit_deduped = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
388                                                        package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
389          if (auto err_deduped{CheckPackageMempoolAcceptResult(package_parent_child, submit_deduped, /*expect_valid=*/true, m_node.mempool.get())}) {
390              BOOST_ERROR(err_deduped.value());
391          } else {
392              auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
393              auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
394              BOOST_CHECK(it_parent_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
395              BOOST_CHECK(it_child_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
396          }
397  
398          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
399      }
400  }
401  
402  // Tests for packages containing transactions that have same-txid-different-witness equivalents in
403  // the mempool.
404  BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
405  {
406      // Mine blocks to mature coinbases.
407      mineBlocks(5);
408      MockMempoolMinFee(CFeeRate(5000));
409      LOCK(cs_main);
410  
411      // Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
412      // and the mempool entry's wtxid returned.
413      CScript witnessScript = CScript() << OP_DROP << OP_TRUE;
414      CScript scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
415      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
416                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
417                                                      /*output_destination=*/scriptPubKey,
418                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
419      CTransactionRef ptx_parent = MakeTransactionRef(mtx_parent);
420  
421      // Make two children with the same txid but different witnesses.
422      CScriptWitness witness1;
423      witness1.stack.emplace_back(1);
424      witness1.stack.emplace_back(witnessScript.begin(), witnessScript.end());
425  
426      CScriptWitness witness2(witness1);
427      witness2.stack.emplace_back(2);
428      witness2.stack.emplace_back(witnessScript.begin(), witnessScript.end());
429  
430      CKey child_key = GenerateRandomKey();
431      CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
432      CMutableTransaction mtx_child1;
433      mtx_child1.nVersion = 1;
434      mtx_child1.vin.resize(1);
435      mtx_child1.vin[0].prevout.hash = ptx_parent->GetHash();
436      mtx_child1.vin[0].prevout.n = 0;
437      mtx_child1.vin[0].scriptSig = CScript();
438      mtx_child1.vin[0].scriptWitness = witness1;
439      mtx_child1.vout.resize(1);
440      mtx_child1.vout[0].nValue = CAmount(48 * COIN);
441      mtx_child1.vout[0].scriptPubKey = child_locking_script;
442  
443      CMutableTransaction mtx_child2{mtx_child1};
444      mtx_child2.vin[0].scriptWitness = witness2;
445  
446      CTransactionRef ptx_child1 = MakeTransactionRef(mtx_child1);
447      CTransactionRef ptx_child2 = MakeTransactionRef(mtx_child2);
448  
449      // child1 and child2 have the same txid
450      BOOST_CHECK_EQUAL(ptx_child1->GetHash(), ptx_child2->GetHash());
451      // child1 and child2 have different wtxids
452      BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
453  
454      // Try submitting Package1{parent, child1} and Package2{parent, child2} where the children are
455      // same-txid-different-witness.
456      {
457          Package package_parent_child1{ptx_parent, ptx_child1};
458          const auto submit_witness1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
459                                                         package_parent_child1, /*test_accept=*/false, /*client_maxfeerate=*/{});
460          if (auto err_witness1{CheckPackageMempoolAcceptResult(package_parent_child1, submit_witness1, /*expect_valid=*/true, m_node.mempool.get())}) {
461              BOOST_ERROR(err_witness1.value());
462          }
463  
464          // Child2 would have been validated individually.
465          Package package_parent_child2{ptx_parent, ptx_child2};
466          const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
467                                                         package_parent_child2, /*test_accept=*/false, /*client_maxfeerate=*/{});
468          if (auto err_witness2{CheckPackageMempoolAcceptResult(package_parent_child2, submit_witness2, /*expect_valid=*/true, m_node.mempool.get())}) {
469              BOOST_ERROR(err_witness2.value());
470          } else {
471              auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
472              auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
473              BOOST_CHECK(it_parent2_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
474              BOOST_CHECK(it_child2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
475              BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
476          }
477  
478          // Deduplication should work when wtxid != txid. Submit package with the already-in-mempool
479          // transactions again, which should not fail.
480          const auto submit_segwit_dedup = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
481                                                             package_parent_child1, /*test_accept=*/false, /*client_maxfeerate=*/{});
482          if (auto err_segwit_dedup{CheckPackageMempoolAcceptResult(package_parent_child1, submit_segwit_dedup, /*expect_valid=*/true, m_node.mempool.get())}) {
483              BOOST_ERROR(err_segwit_dedup.value());
484          } else {
485              auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
486              auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
487              BOOST_CHECK(it_parent_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
488              BOOST_CHECK(it_child_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
489          }
490      }
491  
492      // Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as
493      // the in-mempool transaction, child1. Since child1 exists in the mempool and its outputs are
494      // available, child2 should be ignored and grandchild should be accepted.
495      //
496      // This tests a potential censorship vector in which an attacker broadcasts a competing package
497      // where a parent's witness is mutated. The honest package should be accepted despite the fact
498      // that we don't allow witness replacement.
499      CKey grandchild_key = GenerateRandomKey();
500      CScript grandchild_locking_script = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
501      auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/ptx_child2, /*input_vout=*/0,
502                                                          /*input_height=*/0, /*input_signing_key=*/child_key,
503                                                          /*output_destination=*/grandchild_locking_script,
504                                                          /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
505      CTransactionRef ptx_grandchild = MakeTransactionRef(mtx_grandchild);
506  
507      // We already submitted child1 above.
508      {
509          Package package_child2_grandchild{ptx_child2, ptx_grandchild};
510          const auto submit_spend_ignored = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
511                                                              package_child2_grandchild, /*test_accept=*/false, /*client_maxfeerate=*/{});
512          if (auto err_spend_ignored{CheckPackageMempoolAcceptResult(package_child2_grandchild, submit_spend_ignored, /*expect_valid=*/true, m_node.mempool.get())}) {
513              BOOST_ERROR(err_spend_ignored.value());
514          } else {
515              auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
516              auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
517              BOOST_CHECK(it_child2_ignored->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
518              BOOST_CHECK(it_grandchild->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
519          }
520      }
521  
522      // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of
523      // identical-tx-in-mempool, same-txid-different-witness-in-mempool, and new transactions.
524      Package package_mixed;
525  
526      // Give all the parents anyone-can-spend scripts so we don't have to deal with signing the child.
527      CScript acs_script = CScript() << OP_TRUE;
528      CScript acs_spk = GetScriptForDestination(WitnessV0ScriptHash(acs_script));
529      CScriptWitness acs_witness;
530      acs_witness.stack.emplace_back(acs_script.begin(), acs_script.end());
531  
532      // parent1 will already be in the mempool
533      auto mtx_parent1 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
534                                                       /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
535                                                       /*output_destination=*/acs_spk,
536                                                       /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
537      CTransactionRef ptx_parent1 = MakeTransactionRef(mtx_parent1);
538      package_mixed.push_back(ptx_parent1);
539  
540      // parent2 will have a same-txid-different-witness tx already in the mempool
541      CScript grandparent2_script = CScript() << OP_DROP << OP_TRUE;
542      CScript grandparent2_spk = GetScriptForDestination(WitnessV0ScriptHash(grandparent2_script));
543      CScriptWitness parent2_witness1;
544      parent2_witness1.stack.emplace_back(1);
545      parent2_witness1.stack.emplace_back(grandparent2_script.begin(), grandparent2_script.end());
546      CScriptWitness parent2_witness2;
547      parent2_witness2.stack.emplace_back(2);
548      parent2_witness2.stack.emplace_back(grandparent2_script.begin(), grandparent2_script.end());
549  
550      // Create grandparent2 creating an output with multiple spending paths. Submit to mempool.
551      auto mtx_grandparent2 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
552                                                            /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
553                                                            /*output_destination=*/grandparent2_spk,
554                                                            /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
555      CTransactionRef ptx_grandparent2 = MakeTransactionRef(mtx_grandparent2);
556  
557      CMutableTransaction mtx_parent2_v1;
558      mtx_parent2_v1.nVersion = 1;
559      mtx_parent2_v1.vin.resize(1);
560      mtx_parent2_v1.vin[0].prevout.hash = ptx_grandparent2->GetHash();
561      mtx_parent2_v1.vin[0].prevout.n = 0;
562      mtx_parent2_v1.vin[0].scriptSig = CScript();
563      mtx_parent2_v1.vin[0].scriptWitness = parent2_witness1;
564      mtx_parent2_v1.vout.resize(1);
565      mtx_parent2_v1.vout[0].nValue = CAmount(48 * COIN);
566      mtx_parent2_v1.vout[0].scriptPubKey = acs_spk;
567  
568      CMutableTransaction mtx_parent2_v2{mtx_parent2_v1};
569      mtx_parent2_v2.vin[0].scriptWitness = parent2_witness2;
570  
571      CTransactionRef ptx_parent2_v1 = MakeTransactionRef(mtx_parent2_v1);
572      CTransactionRef ptx_parent2_v2 = MakeTransactionRef(mtx_parent2_v2);
573      // Put parent2_v1 in the package, submit parent2_v2 to the mempool.
574      const MempoolAcceptResult parent2_v2_result = m_node.chainman->ProcessTransaction(ptx_parent2_v2);
575      BOOST_CHECK(parent2_v2_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
576      package_mixed.push_back(ptx_parent2_v1);
577  
578      // parent3 will be a new transaction. Put a low feerate to make it invalid on its own.
579      auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[3], /*input_vout=*/0,
580                                                       /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
581                                                       /*output_destination=*/acs_spk,
582                                                       /*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false);
583      CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3);
584      package_mixed.push_back(ptx_parent3);
585      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*ptx_parent3)) > low_fee_amt);
586      BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*ptx_parent3)) <= low_fee_amt);
587  
588      // child spends parent1, parent2, and parent3
589      CKey mixed_grandchild_key = GenerateRandomKey();
590      CScript mixed_child_spk = GetScriptForDestination(WitnessV0KeyHash(mixed_grandchild_key.GetPubKey()));
591  
592      CMutableTransaction mtx_mixed_child;
593      mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent1->GetHash(), 0));
594      mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent2_v1->GetHash(), 0));
595      mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent3->GetHash(), 0));
596      mtx_mixed_child.vin[0].scriptWitness = acs_witness;
597      mtx_mixed_child.vin[1].scriptWitness = acs_witness;
598      mtx_mixed_child.vin[2].scriptWitness = acs_witness;
599      mtx_mixed_child.vout.emplace_back((48 + 49 + 50 - 1) * COIN, mixed_child_spk);
600      CTransactionRef ptx_mixed_child = MakeTransactionRef(mtx_mixed_child);
601      package_mixed.push_back(ptx_mixed_child);
602  
603      // Submit package:
604      // parent1 should be ignored
605      // parent2_v1 should be ignored (and v2 wtxid returned)
606      // parent3 should be accepted
607      // child should be accepted
608      {
609          const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false, /*client_maxfeerate=*/{});
610          if (auto err_mixed{CheckPackageMempoolAcceptResult(package_mixed, mixed_result, /*expect_valid=*/true, m_node.mempool.get())}) {
611              BOOST_ERROR(err_mixed.value());
612          } else {
613              auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
614              auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
615              auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
616              auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
617  
618              BOOST_CHECK(it_parent1->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
619              BOOST_CHECK(it_parent2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
620              BOOST_CHECK(it_parent3->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
621              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
622              BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
623  
624              // package feerate should include parent3 and child. It should not include parent1 or parent2_v1.
625              const CFeeRate expected_feerate(1 * COIN, GetVirtualTransactionSize(*ptx_parent3) + GetVirtualTransactionSize(*ptx_mixed_child));
626              BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
627              BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
628              std::vector<Wtxid> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
629              BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
630              BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
631          }
632      }
633  }
634  
635  BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
636  {
637      mineBlocks(5);
638      MockMempoolMinFee(CFeeRate(5000));
639      LOCK(::cs_main);
640      size_t expected_pool_size = m_node.mempool->size();
641      CKey child_key = GenerateRandomKey();
642      CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
643      CKey grandchild_key = GenerateRandomKey();
644      CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
645  
646      // low-fee parent and high-fee child package
647      const CAmount coinbase_value{50 * COIN};
648      const CAmount parent_value{coinbase_value - low_fee_amt};
649      const CAmount child_value{parent_value - COIN};
650  
651      Package package_cpfp;
652      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
653                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
654                                                      /*output_destination=*/parent_spk,
655                                                      /*output_amount=*/parent_value, /*submit=*/false);
656      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
657      package_cpfp.push_back(tx_parent);
658  
659      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
660                                                     /*input_height=*/101, /*input_signing_key=*/child_key,
661                                                     /*output_destination=*/child_spk,
662                                                     /*output_amount=*/child_value, /*submit=*/false);
663      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
664      package_cpfp.push_back(tx_child);
665  
666      // Package feerate is calculated using modified fees, and prioritisetransaction accepts negative
667      // fee deltas. This should be taken into account. De-prioritise the parent transaction
668      // to bring the package feerate to 0.
669      m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), child_value - coinbase_value);
670      {
671          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
672          const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
673                                                     package_cpfp, /*test_accept=*/ false, /*client_maxfeerate=*/{});
674          if (auto err_cpfp_deprio{CheckPackageMempoolAcceptResult(package_cpfp, submit_cpfp_deprio, /*expect_valid=*/false, m_node.mempool.get())}) {
675              BOOST_ERROR(err_cpfp_deprio.value());
676          } else {
677              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_TX);
678              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetResult(),
679                                TxValidationResult::TX_MEMPOOL_POLICY);
680              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_child->GetWitnessHash())->second.m_state.GetResult(),
681                                TxValidationResult::TX_MISSING_INPUTS);
682              BOOST_CHECK(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetRejectReason() == "min relay fee not met");
683              BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
684          }
685      }
686  
687      // Clear the prioritisation of the parent transaction.
688      WITH_LOCK(m_node.mempool->cs, m_node.mempool->ClearPrioritisation(tx_parent->GetHash()));
689  
690      // Package CPFP: Even though the parent's feerate is below the mempool minimum feerate, the
691      // child pays enough for the package feerate to meet the threshold.
692      {
693          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
694          const auto submit_cpfp = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
695                                                     package_cpfp, /*test_accept=*/ false, /*client_maxfeerate=*/{});
696          if (auto err_cpfp{CheckPackageMempoolAcceptResult(package_cpfp, submit_cpfp, /*expect_valid=*/true, m_node.mempool.get())}) {
697              BOOST_ERROR(err_cpfp.value());
698          } else {
699              auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
700              auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
701              BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
702              BOOST_CHECK(it_parent->second.m_base_fees.value() == coinbase_value - parent_value);
703              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
704              BOOST_CHECK(it_child->second.m_base_fees.value() == COIN);
705  
706              const CFeeRate expected_feerate(coinbase_value - child_value,
707                                              GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
708              BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
709              BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
710              std::vector<Wtxid> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
711              BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
712              BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
713              BOOST_CHECK(expected_feerate.GetFeePerK() > 1000);
714          }
715          expected_pool_size += 2;
716          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
717      }
718  
719      // Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
720      // The mempool minimum feerate is 5sat/vB, but this package just pays 800 satoshis total.
721      // The child fees would be able to pay for itself, but isn't enough for the entire package.
722      Package package_still_too_low;
723      const CAmount parent_fee{200};
724      const CAmount child_fee{600};
725      auto mtx_parent_cheap = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
726                                                            /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
727                                                            /*output_destination=*/parent_spk,
728                                                            /*output_amount=*/coinbase_value - parent_fee, /*submit=*/false);
729      CTransactionRef tx_parent_cheap = MakeTransactionRef(mtx_parent_cheap);
730      package_still_too_low.push_back(tx_parent_cheap);
731      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) > parent_fee);
732      BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) <= parent_fee);
733  
734      auto mtx_child_cheap = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_cheap, /*input_vout=*/0,
735                                                           /*input_height=*/101, /*input_signing_key=*/child_key,
736                                                           /*output_destination=*/child_spk,
737                                                           /*output_amount=*/coinbase_value - parent_fee - child_fee, /*submit=*/false);
738      CTransactionRef tx_child_cheap = MakeTransactionRef(mtx_child_cheap);
739      package_still_too_low.push_back(tx_child_cheap);
740      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_child_cheap)) <= child_fee);
741      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)) > parent_fee + child_fee);
742      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
743  
744      // Cheap package should fail for being too low fee.
745      {
746          const auto submit_package_too_low = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
747                                                     package_still_too_low, /*test_accept=*/false, /*client_maxfeerate=*/{});
748          if (auto err_package_too_low{CheckPackageMempoolAcceptResult(package_still_too_low, submit_package_too_low, /*expect_valid=*/false, m_node.mempool.get())}) {
749              BOOST_ERROR(err_package_too_low.value());
750          } else {
751              // Individual feerate of parent is too low.
752              BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_state.GetResult(),
753                                TxValidationResult::TX_RECONSIDERABLE);
754              BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_effective_feerate.value() ==
755                          CFeeRate(parent_fee, GetVirtualTransactionSize(*tx_parent_cheap)));
756              // Package feerate of parent + child is too low.
757              BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_state.GetResult(),
758                                TxValidationResult::TX_RECONSIDERABLE);
759              BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_effective_feerate.value() ==
760                          CFeeRate(parent_fee + child_fee, GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)));
761          }
762          BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetResult(), PackageValidationResult::PCKG_TX);
763          BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(), "transaction failed");
764          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
765      }
766  
767      // Package feerate includes the modified fees of the transactions.
768      // This means a child with its fee delta from prioritisetransaction can pay for a parent.
769      m_node.mempool->PrioritiseTransaction(tx_child_cheap->GetHash(), 1 * COIN);
770      // Now that the child's fees have "increased" by 1 BTC, the cheap package should succeed.
771      {
772          const auto submit_prioritised_package = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
773                                                                    package_still_too_low, /*test_accept=*/false, /*client_maxfeerate=*/{});
774          if (auto err_prioritised{CheckPackageMempoolAcceptResult(package_still_too_low, submit_prioritised_package, /*expect_valid=*/true, m_node.mempool.get())}) {
775              BOOST_ERROR(err_prioritised.value());
776          } else {
777              const CFeeRate expected_feerate(1 * COIN + parent_fee + child_fee,
778                  GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
779              BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
780              auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
781              auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
782              BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
783              BOOST_CHECK(it_parent->second.m_base_fees.value() == parent_fee);
784              BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
785              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
786              BOOST_CHECK(it_child->second.m_base_fees.value() == child_fee);
787              BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
788              std::vector<Wtxid> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
789              BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
790              BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
791          }
792          expected_pool_size += 2;
793          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
794      }
795  
796      // Package feerate is calculated without topology in mind; it's just aggregating fees and sizes.
797      // However, this should not allow parents to pay for children. Each transaction should be
798      // validated individually first, eliminating sufficient-feerate parents before they are unfairly
799      // included in the package feerate. It's also important that the low-fee child doesn't prevent
800      // the parent from being accepted.
801      Package package_rich_parent;
802      const CAmount high_parent_fee{1 * COIN};
803      auto mtx_parent_rich = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
804                                                           /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
805                                                           /*output_destination=*/parent_spk,
806                                                           /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
807      CTransactionRef tx_parent_rich = MakeTransactionRef(mtx_parent_rich);
808      package_rich_parent.push_back(tx_parent_rich);
809  
810      auto mtx_child_poor = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_rich, /*input_vout=*/0,
811                                                          /*input_height=*/101, /*input_signing_key=*/child_key,
812                                                          /*output_destination=*/child_spk,
813                                                          /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
814      CTransactionRef tx_child_poor = MakeTransactionRef(mtx_child_poor);
815      package_rich_parent.push_back(tx_child_poor);
816  
817      // Parent pays 1 BTC and child pays none. The parent should be accepted without the child.
818      {
819          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
820          const auto submit_rich_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
821                                                            package_rich_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
822          if (auto err_rich_parent{CheckPackageMempoolAcceptResult(package_rich_parent, submit_rich_parent, /*expect_valid=*/false, m_node.mempool.get())}) {
823              BOOST_ERROR(err_rich_parent.value());
824          } else {
825              // The child would have been validated on its own and failed.
826              BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_TX);
827              BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "transaction failed");
828  
829              auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
830              auto it_child = submit_rich_parent.m_tx_results.find(tx_child_poor->GetWitnessHash());
831              BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
832              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
833              BOOST_CHECK(it_parent->second.m_state.GetRejectReason() == "");
834              BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
835                      strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
836              BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich)));
837              BOOST_CHECK_EQUAL(it_child->second.m_result_type, MempoolAcceptResult::ResultType::INVALID);
838              BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MEMPOOL_POLICY);
839              BOOST_CHECK(it_child->second.m_state.GetRejectReason() == "min relay fee not met");
840          }
841          expected_pool_size += 1;
842          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
843      }
844  }
845  BOOST_AUTO_TEST_SUITE_END()