From 876a05dc9dbef9ec4f5f1e56e0c413556bde9f06 Mon Sep 17 00:00:00 2001 From: Greg Sanders Date: Thu, 7 Dec 2023 16:48:06 -0500 Subject: [PATCH] CheckPackageMempoolAcceptResult: Check rbf invariants --- src/test/util/txmempool.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp index 379c3c9329a92d..0e3f9e72cf8a01 100644 --- a/src/test/util/txmempool.cpp +++ b/src/test/util/txmempool.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -66,10 +67,24 @@ std::optional CheckPackageMempoolAcceptResult(const Package& txns, return strprintf("tx %s unexpectedly failed: %s", wtxid.ToString(), atmp_result.m_state.ToString()); } - //m_replaced_transactions should exist iff the result was VALID - if (atmp_result.m_replaced_transactions.has_value() != valid) { - return strprintf("tx %s result should %shave m_replaced_transactions", + if (atmp_result.m_replaced_transactions.has_value()) { + // m_replaced_transactions should exist iff the result was VALID + if (!valid) { + return strprintf("tx %s result should %shave m_replaced_transactions", wtxid.ToString(), valid ? "" : "not "); + } + // Each subpackage is allowed MAX_REPLACEMENT_CANDIDATES replacements (only checking individually here) + if (atmp_result.m_replaced_transactions.value().size() > MAX_REPLACEMENT_CANDIDATES) { + return strprintf("tx %s result replaced too many transactions", + wtxid.ToString()); + } + + // Replacements can't happen for subpackages larger than 2 + if (!atmp_result.m_replaced_transactions.value().empty() && + atmp_result.m_wtxids_fee_calculations.has_value() && atmp_result.m_wtxids_fee_calculations.value().size() > 2) { + return strprintf("tx %s was part of a too-large package RBF subpackage", + wtxid.ToString()); + } } // m_vsize and m_base_fees should exist iff the result was VALID or MEMPOOL_ENTRY @@ -112,6 +127,13 @@ std::optional CheckPackageMempoolAcceptResult(const Package& txns, return strprintf("wtxid %s should not be in mempool", wtxid.ToString()); } } + if (atmp_result.m_replaced_transactions.has_value()) { + for (const auto& tx_ref : atmp_result.m_replaced_transactions.value()) { + if (mempool->exists(GenTxid::Txid(tx_ref->GetHash()))) { + return strprintf("tx %s should not be in mempool as it was replaced", tx_ref->GetWitnessHash().ToString()); + } + } + } } } return std::nullopt;