diff --git a/src/validation.cpp b/src/validation.cpp index 446eac5aa1c..ae3171fa140 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1342,6 +1342,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // the new transactions. This ensures we don't double-count transaction counts and sizes when // checking ancestor/descendant limits, or double-count transaction fees for fee-related policy. ATMPArgs single_args = ATMPArgs::SingleInPackageAccept(args); + bool quit_early{false}; std::vector txns_new; for (const auto& tx : package) { const auto& wtxid = tx->GetWitnessHash(); @@ -1375,6 +1376,18 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // in package validation, because its fees should only be "used" once. assert(m_pool.exists(GenTxid::Wtxid(wtxid))); results.emplace(wtxid, single_res); + } else if (single_res.m_state.GetResult() != TxValidationResult::TX_MEMPOOL_POLICY && + single_res.m_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { + // Package validation policy only differs from individual policy in its evaluation + // of feerate. For example, if a transaction fails here due to violation of a + // consensus rule, the result will not change when it is submitted as part of a + // package. To minimize the amount of repeated work, unless the transaction fails + // due to feerate or missing inputs (its parent is a previous transaction in the + // package that failed due to feerate), don't run package validation. Note that this + // decision might not make sense if different types of packages are allowed in the + // future. Continue individually validating the rest of the transactions, because + // some of them may still be valid. + quit_early = true; } else { txns_new.push_back(tx); } @@ -1382,7 +1395,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, } // Nothing to do if the entire package has already been submitted. - if (txns_new.empty()) { + if (quit_early || txns_new.empty()) { // No package feerate when no package validation was done. return PackageMempoolAcceptResult(package_state, std::move(results)); }