@@ -916,6 +916,10 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
916916 AssertLockHeld (cs_main);
917917 AssertLockHeld (m_pool.cs );
918918
919+ // CheckPackageLimits expects the package transactions to not already be in the mempool.
920+ assert (std::all_of (txns.cbegin (), txns.cend (), [this ](const auto & tx)
921+ { return !m_pool.exists (GenTxid::Txid (tx->GetHash ()));}));
922+
919923 std::string err_string;
920924 if (!m_pool.CheckPackageLimits (txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants,
921925 m_limit_descendant_size, err_string)) {
@@ -1238,7 +1242,49 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
12381242 m_view.SetBackend (m_dummy);
12391243
12401244 LOCK (m_pool.cs );
1241- return AcceptMultipleTransactions (package, args);
1245+ std::map<const uint256, const MempoolAcceptResult> results;
1246+ // As node operators are free to set their mempool policies however they please, it's possible
1247+ // for package transaction(s) to already be in the mempool, and we don't want to reject the
1248+ // entire package in that case (as that could be a censorship vector). Filter the transactions
1249+ // that are already in mempool and add their information to results, since we already have them.
1250+ std::vector<CTransactionRef> txns_new;
1251+ for (const auto & tx : package) {
1252+ const auto & wtxid = tx->GetWitnessHash ();
1253+ const auto & txid = tx->GetHash ();
1254+ // There are 3 possibilities: already in mempool, same-txid-diff-wtxid already in mempool,
1255+ // or not in mempool. An already confirmed tx is treated as one not in mempool, because all
1256+ // we know is that the inputs aren't available.
1257+ if (m_pool.exists (GenTxid::Wtxid (wtxid))) {
1258+ // Exact transaction already exists in the mempool.
1259+ auto iter = m_pool.GetIter (wtxid);
1260+ assert (iter != std::nullopt );
1261+ results.emplace (wtxid, MempoolAcceptResult::MempoolTx (iter.value ()->GetTxSize (), iter.value ()->GetFee ()));
1262+ } else if (m_pool.exists (GenTxid::Txid (txid))) {
1263+ // Transaction with the same non-witness data but different witness (same txid,
1264+ // different wtxid) already exists in the mempool.
1265+ //
1266+ // We don't allow replacement transactions right now, so just swap the package
1267+ // transaction for the mempool one. Note that we are ignoring the validity of the
1268+ // package transaction passed in.
1269+ // TODO: allow witness replacement in packages.
1270+ auto iter = m_pool.GetIter (wtxid);
1271+ assert (iter != std::nullopt );
1272+ results.emplace (txid, MempoolAcceptResult::MempoolTx (iter.value ()->GetTxSize (), iter.value ()->GetFee ()));
1273+ } else {
1274+ // Transaction does not already exist in the mempool.
1275+ txns_new.push_back (tx);
1276+ }
1277+ }
1278+
1279+ // Nothing to do if the entire package has already been submitted.
1280+ if (txns_new.empty ()) return PackageMempoolAcceptResult (package_state, std::move (results));
1281+ // Validate the (deduplicated) transactions as a package.
1282+ auto submission_result = AcceptMultipleTransactions (txns_new, args);
1283+ // Include already-in-mempool transaction results in the final result.
1284+ for (const auto & [wtxid, mempoolaccept_res] : results) {
1285+ submission_result.m_tx_results .emplace (wtxid, mempoolaccept_res);
1286+ }
1287+ return submission_result;
12421288}
12431289
12441290} // anon namespace
0 commit comments