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()