@@ -916,6 +916,10 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
916
916
AssertLockHeld (cs_main);
917
917
AssertLockHeld (m_pool.cs );
918
918
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
+
919
923
std::string err_string;
920
924
if (!m_pool.CheckPackageLimits (txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants,
921
925
m_limit_descendant_size, err_string)) {
@@ -1238,7 +1242,49 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1238
1242
m_view.SetBackend (m_dummy);
1239
1243
1240
1244
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;
1242
1288
}
1243
1289
1244
1290
} // anon namespace
0 commit comments