/ src / test / txpackage_tests.cpp
txpackage_tests.cpp
   1  // Copyright (c) 2021-present 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 <policy/rbf.h>
  10  #include <primitives/transaction.h>
  11  #include <script/script.h>
  12  #include <serialize.h>
  13  #include <streams.h>
  14  #include <test/util/common.h>
  15  #include <test/util/random.h>
  16  #include <test/util/script.h>
  17  #include <test/util/setup_common.h>
  18  #include <util/strencodings.h>
  19  #include <test/util/txmempool.h>
  20  #include <validation.h>
  21  
  22  #include <boost/test/unit_test.hpp>
  23  
  24  using namespace util::hex_literals;
  25  
  26  // A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these
  27  // unit tests.
  28  static const CAmount low_fee_amt{200};
  29  
  30  struct TxPackageTest : TestChain100Setup {
  31  // Create placeholder transactions that have no meaning.
  32  inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
  33  {
  34      CMutableTransaction mtx = CMutableTransaction();
  35      mtx.vin.resize(num_inputs);
  36      mtx.vout.resize(num_outputs);
  37      auto random_script = CScript() << ToByteVector(m_rng.rand256()) << ToByteVector(m_rng.rand256());
  38      for (size_t i{0}; i < num_inputs; ++i) {
  39          mtx.vin[i].prevout.hash = Txid::FromUint256(m_rng.rand256());
  40          mtx.vin[i].prevout.n = 0;
  41          mtx.vin[i].scriptSig = random_script;
  42      }
  43      for (size_t o{0}; o < num_outputs; ++o) {
  44          mtx.vout[o].nValue = 1 * CENT;
  45          mtx.vout[o].scriptPubKey = random_script;
  46      }
  47      return MakeTransactionRef(mtx);
  48  }
  49  }; // struct TxPackageTest
  50  
  51  BOOST_FIXTURE_TEST_SUITE(txpackage_tests, TxPackageTest)
  52  
  53  BOOST_AUTO_TEST_CASE(package_hash_tests)
  54  {
  55      // Random real segwit transaction
  56      DataStream stream_1{
  57          "02000000000101964b8aa63509579ca6086e6012eeaa4c2f4dd1e283da29b67c8eea38b3c6fd220000000000fdffffff0294c618000000000017a9145afbbb42f4e83312666d0697f9e66259912ecde38768fa2c0000000000160014897388a0889390fd0e153a22bb2cf9d8f019faf50247304402200547406380719f84d68cf4e96cc3e4a1688309ef475b150be2b471c70ea562aa02206d255f5acc40fd95981874d77201d2eb07883657ce1c796513f32b6079545cdf0121023ae77335cefcb5ab4c1dc1fb0d2acfece184e593727d7d5906c78e564c7c11d125cf0c00"_hex,
  58      };
  59      CTransaction tx_1(deserialize, TX_WITH_WITNESS, stream_1);
  60      CTransactionRef ptx_1{MakeTransactionRef(tx_1)};
  61  
  62      // Random real nonsegwit transaction
  63      DataStream stream_2{
  64          "01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"_hex,
  65      };
  66      CTransaction tx_2(deserialize, TX_WITH_WITNESS, stream_2);
  67      CTransactionRef ptx_2{MakeTransactionRef(tx_2)};
  68  
  69      // Random real segwit transaction
  70      DataStream stream_3{
  71          "0200000000010177862801f77c2c068a70372b4c435ef8dd621291c36a64eb4dd491f02218f5324600000000fdffffff014a0100000000000022512035ea312034cfac01e956a269f3bf147f569c2fbb00180677421262da042290d803402be713325ff285e66b0380f53f2fae0d0fb4e16f378a440fed51ce835061437566729d4883bc917632f3cff474d6384bc8b989961a1d730d4a87ed38ad28bd337b20f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7fac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800357b2270223a226272632d3230222c226f70223a226d696e74222c227469636b223a224342414c222c22616d74223a2236393639227d6821c1f1d658c6c138b1c312e072b4446f50f01ae0da03a42e6274f8788aae53416a7f00000000"_hex,
  72      };
  73      CTransaction tx_3(deserialize, TX_WITH_WITNESS, stream_3);
  74      CTransactionRef ptx_3{MakeTransactionRef(tx_3)};
  75  
  76      // It's easy to see that wtxids are sorted in lexicographical order:
  77      constexpr Wtxid wtxid_1{"85cd1a31eb38f74ed5742ec9cb546712ab5aaf747de28a9168b53e846cbda17f"};
  78      constexpr Wtxid wtxid_2{"b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"};
  79      constexpr Wtxid wtxid_3{"e065bac15f62bb4e761d761db928ddee65a47296b2b776785abb912cdec474e3"};
  80      BOOST_CHECK_EQUAL(tx_1.GetWitnessHash(), wtxid_1);
  81      BOOST_CHECK_EQUAL(tx_2.GetWitnessHash(), wtxid_2);
  82      BOOST_CHECK_EQUAL(tx_3.GetWitnessHash(), wtxid_3);
  83  
  84      BOOST_CHECK(wtxid_1.GetHex() < wtxid_2.GetHex());
  85      BOOST_CHECK(wtxid_2.GetHex() < wtxid_3.GetHex());
  86  
  87      // The txids are not (we want to test that sorting and hashing use wtxid, not txid):
  88      constexpr Txid txid_1{"bd0f71c1d5e50589063e134fad22053cdae5ab2320db5bf5e540198b0b5a4e69"};
  89      constexpr Txid txid_2{"b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"};
  90      constexpr Txid txid_3{"ee707be5201160e32c4fc715bec227d1aeea5940fb4295605e7373edce3b1a93"};
  91      BOOST_CHECK_EQUAL(tx_1.GetHash(), txid_1);
  92      BOOST_CHECK_EQUAL(tx_2.GetHash(), txid_2);
  93      BOOST_CHECK_EQUAL(tx_3.GetHash(), txid_3);
  94  
  95      BOOST_CHECK(txid_2.GetHex() < txid_1.GetHex());
  96  
  97      BOOST_CHECK(txid_1.ToUint256() != wtxid_1.ToUint256());
  98      BOOST_CHECK(txid_2.ToUint256() == wtxid_2.ToUint256());
  99      BOOST_CHECK(txid_3.ToUint256() != wtxid_3.ToUint256());
 100  
 101      // We are testing that both functions compare using GetHex() and not uint256.
 102      // (in this pair of wtxids, hex string order != uint256 order)
 103      BOOST_CHECK(wtxid_2 < wtxid_1);
 104      // (in this pair of wtxids, hex string order == uint256 order)
 105      BOOST_CHECK(wtxid_2 < wtxid_3);
 106  
 107      // All permutations of the package containing ptx_1, ptx_2, ptx_3 have the same package hash
 108      std::vector<CTransactionRef> package_123{ptx_1, ptx_2, ptx_3};
 109      std::vector<CTransactionRef> package_132{ptx_1, ptx_3, ptx_2};
 110      std::vector<CTransactionRef> package_231{ptx_2, ptx_3, ptx_1};
 111      std::vector<CTransactionRef> package_213{ptx_2, ptx_1, ptx_3};
 112      std::vector<CTransactionRef> package_312{ptx_3, ptx_1, ptx_2};
 113      std::vector<CTransactionRef> package_321{ptx_3, ptx_2, ptx_1};
 114  
 115      uint256 calculated_hash_123 = (HashWriter() << wtxid_1 << wtxid_2 << wtxid_3).GetSHA256();
 116  
 117      uint256 hash_if_by_txid = (HashWriter() << wtxid_2 << wtxid_1 << wtxid_3).GetSHA256();
 118      BOOST_CHECK(hash_if_by_txid != calculated_hash_123);
 119  
 120      uint256 hash_if_use_txid = (HashWriter() << txid_2 << txid_1 << txid_3).GetSHA256();
 121      BOOST_CHECK(hash_if_use_txid != calculated_hash_123);
 122  
 123      uint256 hash_if_use_int_order = (HashWriter() << wtxid_2 << wtxid_1 << wtxid_3).GetSHA256();
 124      BOOST_CHECK(hash_if_use_int_order != calculated_hash_123);
 125  
 126      BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_123));
 127      BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_132));
 128      BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_231));
 129      BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_213));
 130      BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_312));
 131      BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_321));
 132  }
 133  
 134  BOOST_AUTO_TEST_CASE(package_sanitization_tests)
 135  {
 136      // Packages can't have more than 25 transactions.
 137      Package package_too_many;
 138      package_too_many.reserve(MAX_PACKAGE_COUNT + 1);
 139      for (size_t i{0}; i < MAX_PACKAGE_COUNT + 1; ++i) {
 140          package_too_many.emplace_back(create_placeholder_tx(1, 1));
 141      }
 142      PackageValidationState state_too_many;
 143      BOOST_CHECK(!IsWellFormedPackage(package_too_many, state_too_many));
 144      BOOST_CHECK_EQUAL(state_too_many.GetResult(), PackageValidationResult::PCKG_POLICY);
 145      BOOST_CHECK_EQUAL(state_too_many.GetRejectReason(), "package-too-many-transactions");
 146  
 147      // Packages can't have a total weight of more than 404'000WU.
 148      CTransactionRef large_ptx = create_placeholder_tx(150, 150);
 149      Package package_too_large;
 150      auto size_large = GetTransactionWeight(*large_ptx);
 151      size_t total_weight{0};
 152      while (total_weight <= MAX_PACKAGE_WEIGHT) {
 153          package_too_large.push_back(large_ptx);
 154          total_weight += size_large;
 155      }
 156      BOOST_CHECK(package_too_large.size() <= MAX_PACKAGE_COUNT);
 157      PackageValidationState state_too_large;
 158      BOOST_CHECK(!IsWellFormedPackage(package_too_large, state_too_large));
 159      BOOST_CHECK_EQUAL(state_too_large.GetResult(), PackageValidationResult::PCKG_POLICY);
 160      BOOST_CHECK_EQUAL(state_too_large.GetRejectReason(), "package-too-large");
 161  
 162      // Packages can't contain transactions with the same txid.
 163      Package package_duplicate_txids_empty;
 164      for (auto i{0}; i < 3; ++i) {
 165          CMutableTransaction empty_tx;
 166          package_duplicate_txids_empty.emplace_back(MakeTransactionRef(empty_tx));
 167      }
 168      PackageValidationState state_duplicates;
 169      BOOST_CHECK(!IsWellFormedPackage(package_duplicate_txids_empty, state_duplicates));
 170      BOOST_CHECK_EQUAL(state_duplicates.GetResult(), PackageValidationResult::PCKG_POLICY);
 171      BOOST_CHECK_EQUAL(state_duplicates.GetRejectReason(), "package-contains-duplicates");
 172      BOOST_CHECK(!IsConsistentPackage(package_duplicate_txids_empty));
 173  
 174      // Packages can't have transactions spending the same prevout
 175      CMutableTransaction tx_zero_1;
 176      CMutableTransaction tx_zero_2;
 177      COutPoint same_prevout{Txid::FromUint256(m_rng.rand256()), 0};
 178      tx_zero_1.vin.emplace_back(same_prevout);
 179      tx_zero_2.vin.emplace_back(same_prevout);
 180      // Different vouts (not the same tx)
 181      tx_zero_1.vout.emplace_back(CENT, P2WSH_OP_TRUE);
 182      tx_zero_2.vout.emplace_back(2 * CENT, P2WSH_OP_TRUE);
 183      Package package_conflicts{MakeTransactionRef(tx_zero_1), MakeTransactionRef(tx_zero_2)};
 184      BOOST_CHECK(!IsConsistentPackage(package_conflicts));
 185      // Transactions are considered sorted when they have no dependencies.
 186      BOOST_CHECK(IsTopoSortedPackage(package_conflicts));
 187      PackageValidationState state_conflicts;
 188      BOOST_CHECK(!IsWellFormedPackage(package_conflicts, state_conflicts));
 189      BOOST_CHECK_EQUAL(state_conflicts.GetResult(), PackageValidationResult::PCKG_POLICY);
 190      BOOST_CHECK_EQUAL(state_conflicts.GetRejectReason(), "conflict-in-package");
 191  
 192      // IsConsistentPackage only cares about conflicts between transactions, not about a transaction
 193      // conflicting with itself (i.e. duplicate prevouts in vin).
 194      CMutableTransaction dup_tx;
 195      const COutPoint rand_prevout{Txid::FromUint256(m_rng.rand256()), 0};
 196      dup_tx.vin.emplace_back(rand_prevout);
 197      dup_tx.vin.emplace_back(rand_prevout);
 198      Package package_with_dup_tx{MakeTransactionRef(dup_tx)};
 199      BOOST_CHECK(IsConsistentPackage(package_with_dup_tx));
 200      package_with_dup_tx.emplace_back(create_placeholder_tx(1, 1));
 201      BOOST_CHECK(IsConsistentPackage(package_with_dup_tx));
 202  }
 203  
 204  BOOST_AUTO_TEST_CASE(package_validation_tests)
 205  {
 206      LOCK(cs_main);
 207      unsigned int initialPoolSize = m_node.mempool->size();
 208  
 209      // Parent and Child Package
 210      CKey parent_key = GenerateRandomKey();
 211      CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
 212      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
 213                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 214                                                      /*output_destination=*/parent_locking_script,
 215                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
 216      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
 217  
 218      CKey child_key = GenerateRandomKey();
 219      CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
 220      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
 221                                                     /*input_height=*/101, /*input_signing_key=*/parent_key,
 222                                                     /*output_destination=*/child_locking_script,
 223                                                     /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
 224      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
 225      Package package_parent_child{tx_parent, tx_child};
 226      const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_parent_child, /*test_accept=*/true, /*client_maxfeerate=*/{});
 227      if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_parent_child, result_parent_child, /*expect_valid=*/true, nullptr)}) {
 228          BOOST_ERROR(err_parent_child.value());
 229      } else {
 230          auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
 231          auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
 232  
 233          BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == COIN);
 234          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
 235          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
 236  
 237          BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == COIN);
 238          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
 239          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
 240      }
 241      // A single, giant transaction submitted through ProcessNewPackage fails on single tx policy.
 242      CTransactionRef giant_ptx = create_placeholder_tx(999, 999);
 243      BOOST_CHECK(GetVirtualTransactionSize(*giant_ptx) > DEFAULT_CLUSTER_SIZE_LIMIT_KVB * 1000);
 244      Package package_single_giant{giant_ptx};
 245      auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_single_giant, /*test_accept=*/true, /*client_maxfeerate=*/{});
 246      if (auto err_single_large{CheckPackageMempoolAcceptResult(package_single_giant, result_single_large, /*expect_valid=*/false, nullptr)}) {
 247          BOOST_ERROR(err_single_large.value());
 248      } else {
 249          BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX);
 250          BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(), "transaction failed");
 251          auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
 252          BOOST_CHECK_EQUAL(it_giant_tx->second.m_state.GetRejectReason(), "tx-size");
 253      }
 254  
 255      // Check that mempool size hasn't changed.
 256      BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
 257  }
 258  
 259  BOOST_AUTO_TEST_CASE(noncontextual_package_tests)
 260  {
 261      // The signatures won't be verified so we can just use a placeholder
 262      CKey placeholder_key = GenerateRandomKey();
 263      CScript spk = GetScriptForDestination(PKHash(placeholder_key.GetPubKey()));
 264      CKey placeholder_key_2 = GenerateRandomKey();
 265      CScript spk2 = GetScriptForDestination(PKHash(placeholder_key_2.GetPubKey()));
 266  
 267      // Parent and Child Package
 268      {
 269          auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
 270                                                          CAmount(49 * COIN), /*submit=*/false);
 271          CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
 272  
 273          auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
 274                                                         CAmount(48 * COIN), /*submit=*/false);
 275          CTransactionRef tx_child = MakeTransactionRef(mtx_child);
 276  
 277          PackageValidationState state;
 278          BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_child}, state));
 279          BOOST_CHECK(!IsWellFormedPackage({tx_child, tx_parent}, state));
 280          BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);
 281          BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
 282          BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
 283          BOOST_CHECK(IsChildWithParentsTree({tx_parent, tx_child}));
 284          BOOST_CHECK(GetPackageHash({tx_parent}) != GetPackageHash({tx_child}));
 285          BOOST_CHECK(GetPackageHash({tx_child, tx_child}) != GetPackageHash({tx_child}));
 286          BOOST_CHECK(GetPackageHash({tx_child, tx_parent}) != GetPackageHash({tx_child, tx_child}));
 287          BOOST_CHECK(!IsChildWithParents({}));
 288          BOOST_CHECK(!IsChildWithParentsTree({}));
 289      }
 290  
 291      // 24 Parents and 1 Child
 292      {
 293          Package package;
 294          CMutableTransaction child;
 295          for (int i{0}; i < 24; ++i) {
 296              auto parent = MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
 297                                               0, 0, coinbaseKey, spk, CAmount(48 * COIN), false));
 298              package.emplace_back(parent);
 299              child.vin.emplace_back(COutPoint(parent->GetHash(), 0));
 300          }
 301          child.vout.emplace_back(47 * COIN, spk2);
 302  
 303          // The child must be in the package.
 304          BOOST_CHECK(!IsChildWithParents(package));
 305  
 306          // The parents can be in any order.
 307          FastRandomContext rng;
 308          std::shuffle(package.begin(), package.end(), rng);
 309          package.push_back(MakeTransactionRef(child));
 310  
 311          PackageValidationState state;
 312          BOOST_CHECK(IsWellFormedPackage(package, state));
 313          BOOST_CHECK(IsChildWithParents(package));
 314          BOOST_CHECK(IsChildWithParentsTree(package));
 315  
 316          package.erase(package.begin());
 317          BOOST_CHECK(IsChildWithParents(package));
 318  
 319          // The package cannot have unrelated transactions.
 320          package.insert(package.begin(), m_coinbase_txns[0]);
 321          BOOST_CHECK(!IsChildWithParents(package));
 322      }
 323  
 324      // 2 Parents and 1 Child where one parent depends on the other.
 325      {
 326          CMutableTransaction mtx_parent;
 327          mtx_parent.vin.emplace_back(COutPoint(m_coinbase_txns[0]->GetHash(), 0));
 328          mtx_parent.vout.emplace_back(20 * COIN, spk);
 329          mtx_parent.vout.emplace_back(20 * COIN, spk2);
 330          CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
 331  
 332          CMutableTransaction mtx_parent_also_child;
 333          mtx_parent_also_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 0));
 334          mtx_parent_also_child.vout.emplace_back(20 * COIN, spk);
 335          CTransactionRef tx_parent_also_child = MakeTransactionRef(mtx_parent_also_child);
 336  
 337          CMutableTransaction mtx_child;
 338          mtx_child.vin.emplace_back(COutPoint(tx_parent->GetHash(), 1));
 339          mtx_child.vin.emplace_back(COutPoint(tx_parent_also_child->GetHash(), 0));
 340          mtx_child.vout.emplace_back(39 * COIN, spk);
 341          CTransactionRef tx_child = MakeTransactionRef(mtx_child);
 342  
 343          PackageValidationState state;
 344          BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child}));
 345          BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
 346          BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child, tx_child}));
 347          BOOST_CHECK(!IsChildWithParentsTree({tx_parent, tx_parent_also_child, tx_child}));
 348          // IsChildWithParents does not detect unsorted parents.
 349          BOOST_CHECK(IsChildWithParents({tx_parent_also_child, tx_parent, tx_child}));
 350          BOOST_CHECK(IsWellFormedPackage({tx_parent, tx_parent_also_child, tx_child}, state));
 351          BOOST_CHECK(!IsWellFormedPackage({tx_parent_also_child, tx_parent, tx_child}, state));
 352          BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);
 353          BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
 354      }
 355  }
 356  
 357  BOOST_AUTO_TEST_CASE(package_submission_tests)
 358  {
 359      // Mine blocks to mature coinbases.
 360      mineBlocks(3);
 361      MockMempoolMinFee(CFeeRate(5000), *m_node.mempool);
 362      LOCK(cs_main);
 363      unsigned int expected_pool_size = m_node.mempool->size();
 364      CKey parent_key = GenerateRandomKey();
 365      CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
 366  
 367      // Unrelated transactions are not allowed in package submission.
 368      Package package_unrelated;
 369      for (size_t i{0}; i < 10; ++i) {
 370          auto mtx = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[i + 25], /*input_vout=*/0,
 371                                                   /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 372                                                   /*output_destination=*/parent_locking_script,
 373                                                   /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
 374          package_unrelated.emplace_back(MakeTransactionRef(mtx));
 375      }
 376      auto result_unrelated_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 377                                                       package_unrelated, /*test_accept=*/false, /*client_maxfeerate=*/{});
 378      // We don't expect m_tx_results for each transaction when basic sanity checks haven't passed.
 379      BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
 380      BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
 381      BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
 382      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 383  
 384      // Parent and Child (and Grandchild) Package
 385      Package package_parent_child;
 386      Package package_3gen;
 387      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
 388                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 389                                                      /*output_destination=*/parent_locking_script,
 390                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
 391      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
 392      package_parent_child.push_back(tx_parent);
 393      package_3gen.push_back(tx_parent);
 394  
 395      CKey child_key = GenerateRandomKey();
 396      CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
 397      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
 398                                                     /*input_height=*/101, /*input_signing_key=*/parent_key,
 399                                                     /*output_destination=*/child_locking_script,
 400                                                     /*output_amount=*/CAmount(48 * COIN), /*submit=*/false);
 401      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
 402      package_parent_child.push_back(tx_child);
 403      package_3gen.push_back(tx_child);
 404  
 405      CKey grandchild_key = GenerateRandomKey();
 406      CScript grandchild_locking_script = GetScriptForDestination(PKHash(grandchild_key.GetPubKey()));
 407      auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/tx_child, /*input_vout=*/0,
 408                                                         /*input_height=*/101, /*input_signing_key=*/child_key,
 409                                                         /*output_destination=*/grandchild_locking_script,
 410                                                         /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
 411      CTransactionRef tx_grandchild = MakeTransactionRef(mtx_grandchild);
 412      package_3gen.push_back(tx_grandchild);
 413  
 414      // 3 Generations is not allowed.
 415      {
 416          auto result_3gen_submit = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 417                                                      package_3gen, /*test_accept=*/false, /*client_maxfeerate=*/{});
 418          BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
 419          BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
 420          BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(), "package-not-child-with-parents");
 421          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 422      }
 423  
 424      // Parent and child package where transactions are invalid for reasons other than fee and
 425      // missing inputs, so the package validation isn't expected to happen.
 426      {
 427          CScriptWitness bad_witness;
 428          bad_witness.stack.emplace_back(1);
 429          CMutableTransaction mtx_parent_invalid{mtx_parent};
 430          mtx_parent_invalid.vin[0].scriptWitness = bad_witness;
 431          CTransactionRef tx_parent_invalid = MakeTransactionRef(mtx_parent_invalid);
 432          Package package_invalid_parent{tx_parent_invalid, tx_child};
 433          auto result_quit_early = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 434                                                     package_invalid_parent, /*test_accept=*/ false, /*client_maxfeerate=*/{});
 435          if (auto err_parent_invalid{CheckPackageMempoolAcceptResult(package_invalid_parent, result_quit_early, /*expect_valid=*/false, m_node.mempool.get())}) {
 436              BOOST_ERROR(err_parent_invalid.value());
 437          } else {
 438              auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
 439              auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
 440              BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_WITNESS_MUTATED);
 441              BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(), "bad-witness-nonstandard");
 442              BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);
 443              BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");
 444          }
 445          BOOST_CHECK_EQUAL(result_quit_early.m_state.GetResult(), PackageValidationResult::PCKG_TX);
 446      }
 447  
 448      // Submit package with parent + child.
 449      {
 450          const auto submit_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 451                                                             package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
 452          expected_pool_size += 2;
 453          BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
 454                              "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
 455          BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
 456          auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
 457          auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
 458          BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
 459          BOOST_CHECK(it_parent->second.m_state.IsValid());
 460          BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_parent)));
 461          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
 462          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
 463          BOOST_CHECK(it_child->second.m_effective_feerate == CFeeRate(1 * COIN, GetVirtualTransactionSize(*tx_child)));
 464          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
 465          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
 466  
 467          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 468      }
 469  
 470      // Already-in-mempool transactions should be detected and de-duplicated.
 471      {
 472          const auto submit_deduped = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 473                                                        package_parent_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
 474          if (auto err_deduped{CheckPackageMempoolAcceptResult(package_parent_child, submit_deduped, /*expect_valid=*/true, m_node.mempool.get())}) {
 475              BOOST_ERROR(err_deduped.value());
 476          } else {
 477              auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
 478              auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
 479              BOOST_CHECK(it_parent_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 480              BOOST_CHECK(it_child_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 481          }
 482  
 483          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 484      }
 485  
 486      // In-mempool parent and child with missing parent.
 487      {
 488          auto tx_parent_1 = MakeTransactionRef(CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
 489                                                                              /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 490                                                                              /*output_destination=*/parent_locking_script,
 491                                                                              /*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false));
 492          auto tx_parent_2 = MakeTransactionRef(CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
 493                                                                              /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 494                                                                              /*output_destination=*/parent_locking_script,
 495                                                                              /*output_amount=*/CAmount(50 * COIN - 800), /*submit=*/false));
 496  
 497          auto tx_child_missing_parent = MakeTransactionRef(CreateValidMempoolTransaction({tx_parent_1, tx_parent_2},
 498                                                                                          {{tx_parent_1->GetHash(), 0}, {tx_parent_2->GetHash(), 0}},
 499                                                                                          /*input_height=*/0, {parent_key},
 500                                                                                          {{49 * COIN, child_locking_script}}, /*submit=*/false));
 501  
 502          Package package_missing_parent{tx_parent_1, tx_child_missing_parent};
 503  
 504          const auto result_missing_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 505                                                               package_missing_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
 506          if (auto err_missing_parent{CheckPackageMempoolAcceptResult(package_missing_parent, result_missing_parent, /*expect_valid=*/false, m_node.mempool.get())}) {
 507              BOOST_ERROR(err_missing_parent.value());
 508          } else {
 509              auto it_parent = result_missing_parent.m_tx_results.find(tx_parent_1->GetWitnessHash());
 510              auto it_child = result_missing_parent.m_tx_results.find(tx_child_missing_parent->GetWitnessHash());
 511  
 512              BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetResult(), PackageValidationResult::PCKG_TX);
 513              BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(), "transaction failed");
 514  
 515              BOOST_CHECK_EQUAL(it_parent->second.m_state.GetResult(), TxValidationResult::TX_RECONSIDERABLE);
 516              BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MISSING_INPUTS);
 517              BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "bad-txns-inputs-missingorspent");
 518              BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 519          }
 520  
 521          // Submit parent2 ahead of time, should become ok.
 522          Package package_just_parent2{tx_parent_2};
 523          expected_pool_size += 1;
 524          const auto result_just_parent2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 525                                                             package_just_parent2, /*test_accept=*/false, /*client_maxfeerate=*/{});
 526          if (auto err_parent2{CheckPackageMempoolAcceptResult(package_just_parent2, result_just_parent2, /*expect_valid=*/true, m_node.mempool.get())}) {
 527              BOOST_ERROR(err_parent2.value());
 528          }
 529          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 530  
 531          const auto result_parent_already_in = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 532                                                                  package_missing_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
 533          expected_pool_size += 2;
 534          if (auto err_parent_already_in{CheckPackageMempoolAcceptResult(package_missing_parent, result_parent_already_in, /*expect_valid=*/true, m_node.mempool.get())}) {
 535              BOOST_ERROR(err_parent_already_in.value());
 536          }
 537          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 538      }
 539  }
 540  
 541  // Tests for packages containing a single transaction
 542  BOOST_AUTO_TEST_CASE(package_single_tx)
 543  {
 544      // Mine blocks to mature coinbases.
 545      mineBlocks(3);
 546      LOCK(cs_main);
 547      auto expected_pool_size{m_node.mempool->size()};
 548  
 549      const CAmount high_fee{1000};
 550  
 551      // No unconfirmed parents
 552      CKey single_key = GenerateRandomKey();
 553      CScript single_locking_script = GetScriptForDestination(PKHash(single_key.GetPubKey()));
 554      auto mtx_single = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
 555                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 556                                                      /*output_destination=*/single_locking_script,
 557                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
 558      CTransactionRef tx_single = MakeTransactionRef(mtx_single);
 559      Package package_tx_single{tx_single};
 560      const auto result_single_tx = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 561                                                      package_tx_single, /*test_accept=*/false, /*client_maxfeerate=*/{});
 562      expected_pool_size += 1;
 563      BOOST_CHECK_MESSAGE(result_single_tx.m_state.IsValid(),
 564                          "Package validation unexpectedly failed: " << result_single_tx.m_state.ToString());
 565      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 566  
 567      // Parent and Child. Both submitted by themselves through the ProcessNewPackage interface.
 568      CKey parent_key = GenerateRandomKey();
 569      CScript parent_locking_script = GetScriptForDestination(WitnessV0KeyHash(parent_key.GetPubKey()));
 570      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
 571                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 572                                                      /*output_destination=*/parent_locking_script,
 573                                                      /*output_amount=*/CAmount(50 * COIN) - high_fee, /*submit=*/false);
 574      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
 575      Package package_just_parent{tx_parent};
 576      const auto result_just_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_just_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
 577      if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_just_parent, result_just_parent, /*expect_valid=*/true, nullptr)}) {
 578          BOOST_ERROR(err_parent_child.value());
 579      } else {
 580          auto it_parent = result_just_parent.m_tx_results.find(tx_parent->GetWitnessHash());
 581          BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(), it_parent->second.m_state.ToString());
 582          BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == high_fee);
 583          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
 584          BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
 585      }
 586      expected_pool_size += 1;
 587      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 588  
 589      CKey child_key = GenerateRandomKey();
 590      CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
 591      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
 592                                                     /*input_height=*/101, /*input_signing_key=*/parent_key,
 593                                                     /*output_destination=*/child_locking_script,
 594                                                     /*output_amount=*/CAmount(50 * COIN) - 2 * high_fee, /*submit=*/false);
 595      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
 596      Package package_just_child{tx_child};
 597      const auto result_just_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_just_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
 598      if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_just_child, result_just_child, /*expect_valid=*/true, nullptr)}) {
 599          BOOST_ERROR(err_parent_child.value());
 600      } else {
 601          auto it_child = result_just_child.m_tx_results.find(tx_child->GetWitnessHash());
 602          BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(), it_child->second.m_state.ToString());
 603          BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == high_fee);
 604          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
 605          BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
 606      }
 607      expected_pool_size += 1;
 608      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 609  
 610      // Too-low fee to RBF tx_single
 611      auto mtx_single_low_fee = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
 612                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 613                                                      /*output_destination=*/single_locking_script,
 614                                                      /*output_amount=*/CAmount(49 * COIN - 1), /*submit=*/false);
 615      CTransactionRef tx_single_low_fee = MakeTransactionRef(mtx_single_low_fee);
 616      Package package_tx_single_low_fee{tx_single_low_fee};
 617      const auto result_single_tx_low_fee = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 618                                                      package_tx_single_low_fee, /*test_accept=*/false, /*client_maxfeerate=*/{});
 619  
 620      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 621  
 622      BOOST_CHECK(!result_single_tx_low_fee.m_state.IsValid());
 623      BOOST_CHECK_EQUAL(result_single_tx_low_fee.m_state.GetResult(), PackageValidationResult::PCKG_TX);
 624      auto it_low_fee = result_single_tx_low_fee.m_tx_results.find(tx_single_low_fee->GetWitnessHash());
 625      BOOST_CHECK_EQUAL(it_low_fee->second.m_state.GetResult(), TxValidationResult::TX_RECONSIDERABLE);
 626      if (auto err_single{CheckPackageMempoolAcceptResult(package_tx_single_low_fee, result_single_tx_low_fee, /*expect_valid=*/false, m_node.mempool.get())}) {
 627          BOOST_ERROR(err_single.value());
 628      }
 629      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 630  }
 631  
 632  // Tests for packages containing transactions that have same-txid-different-witness equivalents in
 633  // the mempool.
 634  BOOST_AUTO_TEST_CASE(package_witness_swap_tests)
 635  {
 636      // Mine blocks to mature coinbases.
 637      mineBlocks(5);
 638      MockMempoolMinFee(CFeeRate(5000), *m_node.mempool);
 639      LOCK(cs_main);
 640  
 641      // Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
 642      // and the mempool entry's wtxid returned.
 643      CScript witnessScript = CScript() << OP_DROP << OP_TRUE;
 644      CScript scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
 645      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
 646                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 647                                                      /*output_destination=*/scriptPubKey,
 648                                                      /*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
 649      CTransactionRef ptx_parent = MakeTransactionRef(mtx_parent);
 650  
 651      // Make two children with the same txid but different witnesses.
 652      CScriptWitness witness1;
 653      witness1.stack.emplace_back(1);
 654      witness1.stack.emplace_back(witnessScript.begin(), witnessScript.end());
 655  
 656      CScriptWitness witness2(witness1);
 657      witness2.stack.emplace_back(2);
 658      witness2.stack.emplace_back(witnessScript.begin(), witnessScript.end());
 659  
 660      CKey child_key = GenerateRandomKey();
 661      CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
 662      CMutableTransaction mtx_child1;
 663      mtx_child1.version = 1;
 664      mtx_child1.vin.resize(1);
 665      mtx_child1.vin[0].prevout.hash = ptx_parent->GetHash();
 666      mtx_child1.vin[0].prevout.n = 0;
 667      mtx_child1.vin[0].scriptSig = CScript();
 668      mtx_child1.vin[0].scriptWitness = witness1;
 669      mtx_child1.vout.resize(1);
 670      mtx_child1.vout[0].nValue = CAmount(48 * COIN);
 671      mtx_child1.vout[0].scriptPubKey = child_locking_script;
 672  
 673      CMutableTransaction mtx_child2{mtx_child1};
 674      mtx_child2.vin[0].scriptWitness = witness2;
 675  
 676      CTransactionRef ptx_child1 = MakeTransactionRef(mtx_child1);
 677      CTransactionRef ptx_child2 = MakeTransactionRef(mtx_child2);
 678  
 679      // child1 and child2 have the same txid
 680      BOOST_CHECK_EQUAL(ptx_child1->GetHash(), ptx_child2->GetHash());
 681      // child1 and child2 have different wtxids
 682      BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
 683      // Check that they have different package hashes
 684      BOOST_CHECK(GetPackageHash({ptx_parent, ptx_child1}) != GetPackageHash({ptx_parent, ptx_child2}));
 685  
 686      // Try submitting Package1{parent, child1} and Package2{parent, child2} where the children are
 687      // same-txid-different-witness.
 688      {
 689          Package package_parent_child1{ptx_parent, ptx_child1};
 690          const auto submit_witness1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 691                                                         package_parent_child1, /*test_accept=*/false, /*client_maxfeerate=*/{});
 692          if (auto err_witness1{CheckPackageMempoolAcceptResult(package_parent_child1, submit_witness1, /*expect_valid=*/true, m_node.mempool.get())}) {
 693              BOOST_ERROR(err_witness1.value());
 694          }
 695  
 696          // Child2 would have been validated individually.
 697          Package package_parent_child2{ptx_parent, ptx_child2};
 698          const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 699                                                         package_parent_child2, /*test_accept=*/false, /*client_maxfeerate=*/{});
 700          if (auto err_witness2{CheckPackageMempoolAcceptResult(package_parent_child2, submit_witness2, /*expect_valid=*/true, m_node.mempool.get())}) {
 701              BOOST_ERROR(err_witness2.value());
 702          } else {
 703              auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
 704              auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
 705              BOOST_CHECK(it_parent2_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 706              BOOST_CHECK(it_child2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
 707              BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
 708          }
 709  
 710          // Deduplication should work when wtxid != txid. Submit package with the already-in-mempool
 711          // transactions again, which should not fail.
 712          const auto submit_segwit_dedup = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 713                                                             package_parent_child1, /*test_accept=*/false, /*client_maxfeerate=*/{});
 714          if (auto err_segwit_dedup{CheckPackageMempoolAcceptResult(package_parent_child1, submit_segwit_dedup, /*expect_valid=*/true, m_node.mempool.get())}) {
 715              BOOST_ERROR(err_segwit_dedup.value());
 716          } else {
 717              auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
 718              auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
 719              BOOST_CHECK(it_parent_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 720              BOOST_CHECK(it_child_dup->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 721          }
 722      }
 723  
 724      // Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as
 725      // the in-mempool transaction, child1. Since child1 exists in the mempool and its outputs are
 726      // available, child2 should be ignored and grandchild should be accepted.
 727      //
 728      // This tests a potential censorship vector in which an attacker broadcasts a competing package
 729      // where a parent's witness is mutated. The honest package should be accepted despite the fact
 730      // that we don't allow witness replacement.
 731      CKey grandchild_key = GenerateRandomKey();
 732      CScript grandchild_locking_script = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
 733      auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/ptx_child2, /*input_vout=*/0,
 734                                                          /*input_height=*/0, /*input_signing_key=*/child_key,
 735                                                          /*output_destination=*/grandchild_locking_script,
 736                                                          /*output_amount=*/CAmount(47 * COIN), /*submit=*/false);
 737      CTransactionRef ptx_grandchild = MakeTransactionRef(mtx_grandchild);
 738      // Check that they have different package hashes
 739      BOOST_CHECK(GetPackageHash({ptx_child1, ptx_grandchild}) != GetPackageHash({ptx_child2, ptx_grandchild}));
 740      // We already submitted child1 above.
 741      {
 742          Package package_child2_grandchild{ptx_child2, ptx_grandchild};
 743          const auto submit_spend_ignored = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 744                                                              package_child2_grandchild, /*test_accept=*/false, /*client_maxfeerate=*/{});
 745          if (auto err_spend_ignored{CheckPackageMempoolAcceptResult(package_child2_grandchild, submit_spend_ignored, /*expect_valid=*/true, m_node.mempool.get())}) {
 746              BOOST_ERROR(err_spend_ignored.value());
 747          } else {
 748              auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
 749              auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
 750              BOOST_CHECK(it_child2_ignored->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
 751              BOOST_CHECK(it_grandchild->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
 752          }
 753      }
 754  
 755      // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of
 756      // identical-tx-in-mempool, same-txid-different-witness-in-mempool, and new transactions.
 757      Package package_mixed;
 758  
 759      // Give all the parents anyone-can-spend scripts so we don't have to deal with signing the child.
 760      CScript acs_script = CScript() << OP_TRUE;
 761      CScript acs_spk = GetScriptForDestination(WitnessV0ScriptHash(acs_script));
 762      CScriptWitness acs_witness;
 763      acs_witness.stack.emplace_back(acs_script.begin(), acs_script.end());
 764  
 765      // parent1 will already be in the mempool
 766      auto mtx_parent1 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
 767                                                       /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 768                                                       /*output_destination=*/acs_spk,
 769                                                       /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
 770      CTransactionRef ptx_parent1 = MakeTransactionRef(mtx_parent1);
 771      package_mixed.push_back(ptx_parent1);
 772  
 773      // parent2 will have a same-txid-different-witness tx already in the mempool
 774      CScript grandparent2_script = CScript() << OP_DROP << OP_TRUE;
 775      CScript grandparent2_spk = GetScriptForDestination(WitnessV0ScriptHash(grandparent2_script));
 776      CScriptWitness parent2_witness1;
 777      parent2_witness1.stack.emplace_back(1);
 778      parent2_witness1.stack.emplace_back(grandparent2_script.begin(), grandparent2_script.end());
 779      CScriptWitness parent2_witness2;
 780      parent2_witness2.stack.emplace_back(2);
 781      parent2_witness2.stack.emplace_back(grandparent2_script.begin(), grandparent2_script.end());
 782  
 783      // Create grandparent2 creating an output with multiple spending paths. Submit to mempool.
 784      auto mtx_grandparent2 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
 785                                                            /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 786                                                            /*output_destination=*/grandparent2_spk,
 787                                                            /*output_amount=*/CAmount(49 * COIN), /*submit=*/true);
 788      CTransactionRef ptx_grandparent2 = MakeTransactionRef(mtx_grandparent2);
 789  
 790      CMutableTransaction mtx_parent2_v1;
 791      mtx_parent2_v1.version = 1;
 792      mtx_parent2_v1.vin.resize(1);
 793      mtx_parent2_v1.vin[0].prevout.hash = ptx_grandparent2->GetHash();
 794      mtx_parent2_v1.vin[0].prevout.n = 0;
 795      mtx_parent2_v1.vin[0].scriptSig = CScript();
 796      mtx_parent2_v1.vin[0].scriptWitness = parent2_witness1;
 797      mtx_parent2_v1.vout.resize(1);
 798      mtx_parent2_v1.vout[0].nValue = CAmount(48 * COIN);
 799      mtx_parent2_v1.vout[0].scriptPubKey = acs_spk;
 800  
 801      CMutableTransaction mtx_parent2_v2{mtx_parent2_v1};
 802      mtx_parent2_v2.vin[0].scriptWitness = parent2_witness2;
 803  
 804      CTransactionRef ptx_parent2_v1 = MakeTransactionRef(mtx_parent2_v1);
 805      CTransactionRef ptx_parent2_v2 = MakeTransactionRef(mtx_parent2_v2);
 806      // Put parent2_v1 in the package, submit parent2_v2 to the mempool.
 807      const MempoolAcceptResult parent2_v2_result = m_node.chainman->ProcessTransaction(ptx_parent2_v2);
 808      BOOST_CHECK(parent2_v2_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
 809      package_mixed.push_back(ptx_parent2_v1);
 810  
 811      // parent3 will be a new transaction. Put a low feerate to make it invalid on its own.
 812      auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[3], /*input_vout=*/0,
 813                                                       /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 814                                                       /*output_destination=*/acs_spk,
 815                                                       /*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false);
 816      CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3);
 817      package_mixed.push_back(ptx_parent3);
 818      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*ptx_parent3)) > low_fee_amt);
 819      BOOST_CHECK(m_node.mempool->m_opts.min_relay_feerate.GetFee(GetVirtualTransactionSize(*ptx_parent3)) <= low_fee_amt);
 820  
 821      // child spends parent1, parent2, and parent3
 822      CKey mixed_grandchild_key = GenerateRandomKey();
 823      CScript mixed_child_spk = GetScriptForDestination(WitnessV0KeyHash(mixed_grandchild_key.GetPubKey()));
 824  
 825      CMutableTransaction mtx_mixed_child;
 826      mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent1->GetHash(), 0));
 827      mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent2_v1->GetHash(), 0));
 828      mtx_mixed_child.vin.emplace_back(COutPoint(ptx_parent3->GetHash(), 0));
 829      mtx_mixed_child.vin[0].scriptWitness = acs_witness;
 830      mtx_mixed_child.vin[1].scriptWitness = acs_witness;
 831      mtx_mixed_child.vin[2].scriptWitness = acs_witness;
 832      mtx_mixed_child.vout.emplace_back((48 + 49 + 50 - 1) * COIN, mixed_child_spk);
 833      CTransactionRef ptx_mixed_child = MakeTransactionRef(mtx_mixed_child);
 834      package_mixed.push_back(ptx_mixed_child);
 835  
 836      // Submit package:
 837      // parent1 should be ignored
 838      // parent2_v1 should be ignored (and v2 wtxid returned)
 839      // parent3 should be accepted
 840      // child should be accepted
 841      {
 842          const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false, /*client_maxfeerate=*/{});
 843          if (auto err_mixed{CheckPackageMempoolAcceptResult(package_mixed, mixed_result, /*expect_valid=*/true, m_node.mempool.get())}) {
 844              BOOST_ERROR(err_mixed.value());
 845          } else {
 846              auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
 847              auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
 848              auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
 849              auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
 850  
 851              BOOST_CHECK(it_parent1->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 852              BOOST_CHECK(it_parent2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS);
 853              BOOST_CHECK(it_parent3->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
 854              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
 855              BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
 856  
 857              // package feerate should include parent3 and child. It should not include parent1 or parent2_v1.
 858              const CFeeRate expected_feerate(1 * COIN, GetVirtualTransactionSize(*ptx_parent3) + GetVirtualTransactionSize(*ptx_mixed_child));
 859              BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
 860              BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
 861              std::vector<Wtxid> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
 862              BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
 863              BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
 864          }
 865      }
 866  }
 867  
 868  BOOST_AUTO_TEST_CASE(package_cpfp_tests)
 869  {
 870      mineBlocks(5);
 871      MockMempoolMinFee(CFeeRate(5000), *m_node.mempool);
 872      LOCK(::cs_main);
 873      size_t expected_pool_size = m_node.mempool->size();
 874      CKey child_key = GenerateRandomKey();
 875      CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
 876      CKey grandchild_key = GenerateRandomKey();
 877      CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
 878  
 879      // low-fee parent and high-fee child package
 880      const CAmount coinbase_value{50 * COIN};
 881      const CAmount parent_value{coinbase_value - low_fee_amt};
 882      const CAmount child_value{parent_value - COIN};
 883  
 884      Package package_cpfp;
 885      auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
 886                                                      /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 887                                                      /*output_destination=*/parent_spk,
 888                                                      /*output_amount=*/parent_value, /*submit=*/false);
 889      CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
 890      package_cpfp.push_back(tx_parent);
 891  
 892      auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
 893                                                     /*input_height=*/101, /*input_signing_key=*/child_key,
 894                                                     /*output_destination=*/child_spk,
 895                                                     /*output_amount=*/child_value, /*submit=*/false);
 896      CTransactionRef tx_child = MakeTransactionRef(mtx_child);
 897      package_cpfp.push_back(tx_child);
 898  
 899      // Package feerate is calculated using modified fees, and prioritisetransaction accepts negative
 900      // fee deltas. This should be taken into account. De-prioritise the parent transaction
 901      // to bring the package feerate to 0.
 902      m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), child_value - coinbase_value);
 903      {
 904          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 905          const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 906                                                     package_cpfp, /*test_accept=*/ false, /*client_maxfeerate=*/{});
 907          if (auto err_cpfp_deprio{CheckPackageMempoolAcceptResult(package_cpfp, submit_cpfp_deprio, /*expect_valid=*/false, m_node.mempool.get())}) {
 908              BOOST_ERROR(err_cpfp_deprio.value());
 909          } else {
 910              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_TX);
 911              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetResult(),
 912                                TxValidationResult::TX_RECONSIDERABLE);
 913              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_child->GetWitnessHash())->second.m_state.GetResult(),
 914                                TxValidationResult::TX_RECONSIDERABLE);
 915              BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetRejectReason(), "mempool min fee not met");
 916              BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 917          }
 918      }
 919  
 920      // Clear the prioritisation of the parent transaction.
 921      WITH_LOCK(m_node.mempool->cs, m_node.mempool->ClearPrioritisation(tx_parent->GetHash()));
 922  
 923      // Package CPFP: Even though the parent's feerate is below the mempool minimum feerate, the
 924      // child pays enough for the package feerate to meet the threshold.
 925      {
 926          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 927          const auto submit_cpfp = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 928                                                     package_cpfp, /*test_accept=*/ false, /*client_maxfeerate=*/{});
 929          if (auto err_cpfp{CheckPackageMempoolAcceptResult(package_cpfp, submit_cpfp, /*expect_valid=*/true, m_node.mempool.get())}) {
 930              BOOST_ERROR(err_cpfp.value());
 931          } else {
 932              auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
 933              auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
 934              BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
 935              BOOST_CHECK(it_parent->second.m_base_fees.value() == coinbase_value - parent_value);
 936              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
 937              BOOST_CHECK(it_child->second.m_base_fees.value() == COIN);
 938  
 939              const CFeeRate expected_feerate(coinbase_value - child_value,
 940                                              GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
 941              BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
 942              BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
 943              std::vector<Wtxid> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
 944              BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
 945              BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
 946              BOOST_CHECK(expected_feerate.GetFeePerK() > 1000);
 947          }
 948          expected_pool_size += 2;
 949          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 950      }
 951  
 952      // Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
 953      // The mempool minimum feerate is 5sat/vB, but this package just pays 800 satoshis total.
 954      // The child fees would be able to pay for itself, but isn't enough for the entire package.
 955      Package package_still_too_low;
 956      const CAmount parent_fee{200};
 957      const CAmount child_fee{600};
 958      auto mtx_parent_cheap = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
 959                                                            /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
 960                                                            /*output_destination=*/parent_spk,
 961                                                            /*output_amount=*/coinbase_value - parent_fee, /*submit=*/false);
 962      CTransactionRef tx_parent_cheap = MakeTransactionRef(mtx_parent_cheap);
 963      package_still_too_low.push_back(tx_parent_cheap);
 964      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) > parent_fee);
 965      BOOST_CHECK(m_node.mempool->m_opts.min_relay_feerate.GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) <= parent_fee);
 966  
 967      auto mtx_child_cheap = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_cheap, /*input_vout=*/0,
 968                                                           /*input_height=*/101, /*input_signing_key=*/child_key,
 969                                                           /*output_destination=*/child_spk,
 970                                                           /*output_amount=*/coinbase_value - parent_fee - child_fee, /*submit=*/false);
 971      CTransactionRef tx_child_cheap = MakeTransactionRef(mtx_child_cheap);
 972      package_still_too_low.push_back(tx_child_cheap);
 973      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_child_cheap)) <= child_fee);
 974      BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)) > parent_fee + child_fee);
 975      BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 976  
 977      // Cheap package should fail for being too low fee.
 978      {
 979          const auto submit_package_too_low = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
 980                                                     package_still_too_low, /*test_accept=*/false, /*client_maxfeerate=*/{});
 981          if (auto err_package_too_low{CheckPackageMempoolAcceptResult(package_still_too_low, submit_package_too_low, /*expect_valid=*/false, m_node.mempool.get())}) {
 982              BOOST_ERROR(err_package_too_low.value());
 983          } else {
 984              // Individual feerate of parent is too low.
 985              BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_state.GetResult(),
 986                                TxValidationResult::TX_RECONSIDERABLE);
 987              BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_effective_feerate.value() ==
 988                          CFeeRate(parent_fee, GetVirtualTransactionSize(*tx_parent_cheap)));
 989              // Package feerate of parent + child is too low.
 990              BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_state.GetResult(),
 991                                TxValidationResult::TX_RECONSIDERABLE);
 992              BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_effective_feerate.value() ==
 993                          CFeeRate(parent_fee + child_fee, GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)));
 994          }
 995          BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetResult(), PackageValidationResult::PCKG_TX);
 996          BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(), "transaction failed");
 997          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
 998      }
 999  
1000      // Package feerate includes the modified fees of the transactions.
1001      // This means a child with its fee delta from prioritisetransaction can pay for a parent.
1002      m_node.mempool->PrioritiseTransaction(tx_child_cheap->GetHash(), 1 * COIN);
1003      // Now that the child's fees have "increased" by 1 BTC, the cheap package should succeed.
1004      {
1005          const auto submit_prioritised_package = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
1006                                                                    package_still_too_low, /*test_accept=*/false, /*client_maxfeerate=*/{});
1007          if (auto err_prioritised{CheckPackageMempoolAcceptResult(package_still_too_low, submit_prioritised_package, /*expect_valid=*/true, m_node.mempool.get())}) {
1008              BOOST_ERROR(err_prioritised.value());
1009          } else {
1010              const CFeeRate expected_feerate(1 * COIN + parent_fee + child_fee,
1011                  GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
1012              BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
1013              auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
1014              auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
1015              BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
1016              BOOST_CHECK(it_parent->second.m_base_fees.value() == parent_fee);
1017              BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
1018              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
1019              BOOST_CHECK(it_child->second.m_base_fees.value() == child_fee);
1020              BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
1021              std::vector<Wtxid> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
1022              BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
1023              BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
1024          }
1025          expected_pool_size += 2;
1026          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1027      }
1028  
1029      // Package feerate is calculated without topology in mind; it's just aggregating fees and sizes.
1030      // However, this should not allow parents to pay for children. Each transaction should be
1031      // validated individually first, eliminating sufficient-feerate parents before they are unfairly
1032      // included in the package feerate. It's also important that the low-fee child doesn't prevent
1033      // the parent from being accepted.
1034      Package package_rich_parent;
1035      const CAmount high_parent_fee{1 * COIN};
1036      auto mtx_parent_rich = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[2], /*input_vout=*/0,
1037                                                           /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
1038                                                           /*output_destination=*/parent_spk,
1039                                                           /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
1040      CTransactionRef tx_parent_rich = MakeTransactionRef(mtx_parent_rich);
1041      package_rich_parent.push_back(tx_parent_rich);
1042  
1043      auto mtx_child_poor = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_rich, /*input_vout=*/0,
1044                                                          /*input_height=*/101, /*input_signing_key=*/child_key,
1045                                                          /*output_destination=*/child_spk,
1046                                                          /*output_amount=*/coinbase_value - high_parent_fee, /*submit=*/false);
1047      CTransactionRef tx_child_poor = MakeTransactionRef(mtx_child_poor);
1048      package_rich_parent.push_back(tx_child_poor);
1049  
1050      // Parent pays 1 BTC and child pays none. The parent should be accepted without the child.
1051      {
1052          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1053          const auto submit_rich_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
1054                                                            package_rich_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
1055          if (auto err_rich_parent{CheckPackageMempoolAcceptResult(package_rich_parent, submit_rich_parent, /*expect_valid=*/false, m_node.mempool.get())}) {
1056              BOOST_ERROR(err_rich_parent.value());
1057          } else {
1058              // The child would have been validated on its own and failed.
1059              BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_TX);
1060              BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "transaction failed");
1061  
1062              auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
1063              auto it_child = submit_rich_parent.m_tx_results.find(tx_child_poor->GetWitnessHash());
1064              BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
1065              BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
1066              BOOST_CHECK(it_parent->second.m_state.GetRejectReason() == "");
1067              BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
1068                      strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
1069              BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich)));
1070              BOOST_CHECK_EQUAL(it_child->second.m_result_type, MempoolAcceptResult::ResultType::INVALID);
1071              BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_RECONSIDERABLE);
1072              BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(), "mempool min fee not met");
1073          }
1074          expected_pool_size += 1;
1075          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1076      }
1077  }
1078  
1079  BOOST_AUTO_TEST_CASE(package_rbf_tests)
1080  {
1081      mineBlocks(5);
1082      LOCK(::cs_main);
1083      size_t expected_pool_size = m_node.mempool->size();
1084      CKey child_key{GenerateRandomKey()};
1085      CScript parent_spk = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
1086      CKey grandchild_key{GenerateRandomKey()};
1087      CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
1088  
1089      const CAmount coinbase_value{50 * COIN};
1090      // Test that de-duplication works. This is not actually package rbf.
1091      {
1092          // 1 parent paying 200sat, 1 child paying 300sat
1093          Package package1;
1094          // 1 parent paying 200sat, 1 child paying 500sat
1095          Package package2;
1096          // Package1 and package2 have the same parent. The children conflict.
1097          auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
1098                                                          /*input_height=*/0, /*input_signing_key=*/coinbaseKey,
1099                                                          /*output_destination=*/parent_spk,
1100                                                          /*output_amount=*/coinbase_value - low_fee_amt, /*submit=*/false);
1101          CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
1102          package1.push_back(tx_parent);
1103          package2.push_back(tx_parent);
1104  
1105          CTransactionRef tx_child_1 = MakeTransactionRef(CreateValidMempoolTransaction(tx_parent, 0, 101, child_key, child_spk, coinbase_value - low_fee_amt - 300, false));
1106          package1.push_back(tx_child_1);
1107          CTransactionRef tx_child_2 = MakeTransactionRef(CreateValidMempoolTransaction(tx_parent, 0, 101, child_key, child_spk, coinbase_value - low_fee_amt - 500, false));
1108          package2.push_back(tx_child_2);
1109  
1110          LOCK(m_node.mempool->cs);
1111          const auto submit1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, /*test_accept=*/false, std::nullopt);
1112          if (auto err_1{CheckPackageMempoolAcceptResult(package1, submit1, /*expect_valid=*/true, m_node.mempool.get())}) {
1113              BOOST_ERROR(err_1.value());
1114          }
1115  
1116          // Check precise ResultTypes and mempool size. We know it_parent_1 and it_child_1 exist from above call
1117          auto it_parent_1 = submit1.m_tx_results.find(tx_parent->GetWitnessHash());
1118          auto it_child_1 = submit1.m_tx_results.find(tx_child_1->GetWitnessHash());
1119          BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1120          BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1121          expected_pool_size += 2;
1122          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1123  
1124          const auto submit2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package2, /*test_accept=*/false, std::nullopt);
1125          if (auto err_2{CheckPackageMempoolAcceptResult(package2, submit2, /*expect_valid=*/true, m_node.mempool.get())}) {
1126              BOOST_ERROR(err_2.value());
1127          }
1128  
1129          // Check precise ResultTypes and mempool size. We know it_parent_2 and it_child_2 exist from above call
1130          auto it_parent_2 = submit2.m_tx_results.find(tx_parent->GetWitnessHash());
1131          auto it_child_2 = submit2.m_tx_results.find(tx_child_2->GetWitnessHash());
1132          BOOST_CHECK_EQUAL(it_parent_2->second.m_result_type, MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
1133          BOOST_CHECK_EQUAL(it_child_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1134          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1135  
1136          // child1 has been replaced
1137          BOOST_CHECK(!m_node.mempool->exists(tx_child_1->GetHash()));
1138      }
1139  
1140      // Test package rbf.
1141      {
1142          CTransactionRef tx_parent_1 = MakeTransactionRef(CreateValidMempoolTransaction(
1143              m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0,
1144              coinbaseKey, parent_spk, coinbase_value - 200, /*submit=*/false));
1145          CTransactionRef tx_child_1 = MakeTransactionRef(CreateValidMempoolTransaction(
1146              tx_parent_1, /*input_vout=*/0, /*input_height=*/101,
1147              child_key, child_spk, coinbase_value - 400, /*submit=*/false));
1148  
1149          CTransactionRef tx_parent_2 = MakeTransactionRef(CreateValidMempoolTransaction(
1150              m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0,
1151              coinbaseKey, parent_spk, coinbase_value - 800, /*submit=*/false));
1152          CTransactionRef tx_child_2 = MakeTransactionRef(CreateValidMempoolTransaction(
1153              tx_parent_2, /*input_vout=*/0, /*input_height=*/101,
1154              child_key, child_spk, coinbase_value - 800 - 200, /*submit=*/false));
1155  
1156          CTransactionRef tx_parent_3 = MakeTransactionRef(CreateValidMempoolTransaction(
1157              m_coinbase_txns[1], /*input_vout=*/0, /*input_height=*/0,
1158              coinbaseKey, parent_spk, coinbase_value - 199, /*submit=*/false));
1159          CTransactionRef tx_child_3 = MakeTransactionRef(CreateValidMempoolTransaction(
1160              tx_parent_3, /*input_vout=*/0, /*input_height=*/101,
1161              child_key, child_spk, coinbase_value - 199 - 1300, /*submit=*/false));
1162  
1163          // In all packages, the parents conflict with each other
1164          BOOST_CHECK(tx_parent_1->GetHash() != tx_parent_2->GetHash() && tx_parent_2->GetHash() != tx_parent_3->GetHash());
1165  
1166          // 1 parent paying 200sat, 1 child paying 200sat.
1167          Package package1{tx_parent_1, tx_child_1};
1168          // 1 parent paying 800sat, 1 child paying 200sat.
1169          Package package2{tx_parent_2, tx_child_2};
1170          // 1 parent paying 199sat, 1 child paying 1300sat.
1171          Package package3{tx_parent_3, tx_child_3};
1172  
1173          const auto submit1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt);
1174          if (auto err_1{CheckPackageMempoolAcceptResult(package1, submit1, /*expect_valid=*/true, m_node.mempool.get())}) {
1175              BOOST_ERROR(err_1.value());
1176          }
1177          auto it_parent_1 = submit1.m_tx_results.find(tx_parent_1->GetWitnessHash());
1178          auto it_child_1 = submit1.m_tx_results.find(tx_child_1->GetWitnessHash());
1179          BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1180          BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1181          expected_pool_size += 2;
1182          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1183  
1184          // This replacement is actually not package rbf; the parent carries enough fees
1185          // to replace the entire package on its own.
1186          const auto submit2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package2, false, std::nullopt);
1187          if (auto err_2{CheckPackageMempoolAcceptResult(package2, submit2, /*expect_valid=*/true, m_node.mempool.get())}) {
1188              BOOST_ERROR(err_2.value());
1189          }
1190          auto it_parent_2 = submit2.m_tx_results.find(tx_parent_2->GetWitnessHash());
1191          auto it_child_2 = submit2.m_tx_results.find(tx_child_2->GetWitnessHash());
1192          BOOST_CHECK_EQUAL(it_parent_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1193          BOOST_CHECK_EQUAL(it_child_2->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1194          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1195  
1196          // Package RBF, in which the replacement transaction's child sponsors the fees to meet RBF feerate rules
1197          const auto submit3 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package3, false, std::nullopt);
1198          if (auto err_3{CheckPackageMempoolAcceptResult(package3, submit3, /*expect_valid=*/true, m_node.mempool.get())}) {
1199              BOOST_ERROR(err_3.value());
1200          }
1201          auto it_parent_3 = submit3.m_tx_results.find(tx_parent_3->GetWitnessHash());
1202          auto it_child_3 = submit3.m_tx_results.find(tx_child_3->GetWitnessHash());
1203          BOOST_CHECK_EQUAL(it_parent_3->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1204          BOOST_CHECK_EQUAL(it_child_3->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1205  
1206          // package3 was considered as a package to replace both package2 transactions
1207          BOOST_CHECK(it_parent_3->second.m_replaced_transactions.size() == 2);
1208          BOOST_CHECK(it_child_3->second.m_replaced_transactions.empty());
1209  
1210          std::vector<Wtxid> expected_package3_wtxids({tx_parent_3->GetWitnessHash(), tx_child_3->GetWitnessHash()});
1211          const auto package3_total_vsize{GetVirtualTransactionSize(*tx_parent_3) + GetVirtualTransactionSize(*tx_child_3)};
1212          BOOST_CHECK(it_parent_3->second.m_wtxids_fee_calculations.value() == expected_package3_wtxids);
1213          BOOST_CHECK(it_child_3->second.m_wtxids_fee_calculations.value() == expected_package3_wtxids);
1214          BOOST_CHECK_EQUAL(it_parent_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300);
1215          BOOST_CHECK_EQUAL(it_child_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300);
1216  
1217          BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
1218  
1219          // Finally, check that we can prioritise tx_child_1 to get package1 into the mempool.
1220          // It should not be possible to resubmit package1 and get it in without prioritisation.
1221          const auto submit4 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt);
1222          if (auto err_4{CheckPackageMempoolAcceptResult(package1, submit4, /*expect_valid=*/false, m_node.mempool.get())}) {
1223              BOOST_ERROR(err_4.value());
1224          }
1225          m_node.mempool->PrioritiseTransaction(tx_child_1->GetHash(), 1363);
1226          const auto submit5 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt);
1227          if (auto err_5{CheckPackageMempoolAcceptResult(package1, submit5, /*expect_valid=*/true, m_node.mempool.get())}) {
1228              BOOST_ERROR(err_5.value());
1229          }
1230          it_parent_1 = submit5.m_tx_results.find(tx_parent_1->GetWitnessHash());
1231          it_child_1 = submit5.m_tx_results.find(tx_child_1->GetWitnessHash());
1232          BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1233          BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
1234          LOCK(m_node.mempool->cs);
1235          BOOST_CHECK(m_node.mempool->GetIter(tx_parent_1->GetHash()).has_value());
1236          BOOST_CHECK(m_node.mempool->GetIter(tx_child_1->GetHash()).has_value());
1237      }
1238  }
1239  BOOST_AUTO_TEST_SUITE_END()