diff options
-rw-r--r-- | src/test/transaction_tests.cpp | 2 | ||||
-rw-r--r-- | src/validation.cpp | 29 |
2 files changed, 25 insertions, 6 deletions
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 5329c6ac99..7e48bee269 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -790,7 +790,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.nVersion = 0; CheckIsNotStandard(t, "version"); - t.nVersion = 3; + t.nVersion = TX_MAX_STANDARD_VERSION + 1; CheckIsNotStandard(t, "version"); // Allowed nVersion diff --git a/src/validation.cpp b/src/validation.cpp index 5c0c92114f..b223af821f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -29,6 +29,7 @@ #include <logging/timer.h> #include <node/blockstorage.h> #include <node/utxo_snapshot.h> +#include <policy/v3_policy.h> #include <policy/policy.h> #include <policy/rbf.h> #include <policy/settings.h> @@ -332,7 +333,9 @@ void Chainstate::MaybeUpdateMempoolForReorg( // Also updates valid entries' cached LockPoints if needed. // If false, the tx is still valid and its lockpoints are updated. // If true, the tx would be invalid in the next block; remove this entry and all of its descendants. - const auto filter_final_and_mature = [this](CTxMemPool::txiter it) + // Note that v3 rules are not applied here, so reorgs may cause violations of v3 inheritance or + // topology restrictions. + const auto filter_final_and_mature = [&](CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) { AssertLockHeld(m_mempool->cs); AssertLockHeld(::cs_main); @@ -760,9 +763,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // check all unconfirmed ancestors; otherwise an opt-in ancestor // might be replaced, causing removal of this descendant. // - // If replaceability signaling is ignored due to node setting, - // replacement is always allowed. - if (!m_pool.m_full_rbf && !SignalsOptInRBF(*ptxConflicting)) { + // All V3 transactions are considered replaceable. + // + // Replaceability signaling of the original transactions may be + // ignored due to node setting. + const bool allow_rbf{m_pool.m_full_rbf || SignalsOptInRBF(*ptxConflicting) || ptxConflicting->nVersion == 3}; + if (!allow_rbf) { return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict"); } @@ -864,7 +870,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // while a tx could be package CPFP'd when entering the mempool, we do not have a DoS-resistant // method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear // due to a replacement. - if (!bypass_limits && ws.m_modified_fees < m_pool.m_min_relay_feerate.GetFee(ws.m_vsize)) { + // The only exception is v3 transactions. + if (!bypass_limits && ws.m_ptx->nVersion != 3 && ws.m_modified_fees < m_pool.m_min_relay_feerate.GetFee(ws.m_vsize)) { // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not // TX_RECONSIDERABLE, because it cannot be bypassed using package validation. return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", @@ -946,6 +953,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) } ws.m_ancestors = *ancestors; + if (const auto err_string{SingleV3Checks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "v3-rule-violation", *err_string); + } // A transaction that spends outputs that would be replaced by it is invalid. Now // that we have the set of all ancestors we can detect this @@ -1306,6 +1316,15 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: m_viewmempool.PackageAddTransaction(ws.m_ptx); } + // At this point we have all in-mempool ancestors, and we know every transaction's vsize. + // Run the v3 checks on the package. + for (Workspace& ws : workspaces) { + if (auto err{PackageV3Checks(ws.m_ptx, ws.m_vsize, txns, ws.m_ancestors)}) { + package_state.Invalid(PackageValidationResult::PCKG_POLICY, "v3-violation", err.value()); + return PackageMempoolAcceptResult(package_state, {}); + } + } + // Transactions must meet two minimum feerates: the mempool minimum fee and min relay fee. // For transactions consisting of exactly one child and its parents, it suffices to use the // package feerate (total modified fees / total virtual size) to check this requirement. |