MOVEONLY: mempool checks to their own functions

No change in behavior, because package transactions would not be going
through the rbf logic in PreChecks anyway (BIP125 is currently disabled
for package acceptance, see ATMPArgs).

We draw the line here because each individual transaction in package
validation still goes through all PreChecks. For example, checking that
one's own conflicts and dependencies are disjoint (a consensus check)
and individual transaction mempool ancestor/descendant limits.
This commit is contained in:
glozow
2021-08-09 11:56:57 +01:00
parent 9e910d8152
commit c9b1439ca9

View File

@ -541,6 +541,14 @@ private:
// only tests that are fast should be done here (to avoid CPU DoS). // only tests that are fast should be done here (to avoid CPU DoS).
bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Run checks for mempool replace-by-fee.
bool ReplacementChecks(Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Enforce package mempool ancestor/descendant limits (distinct from individual
// ancestor/descendant limits done in PreChecks).
bool PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
PackageValidationState& package_state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Run the script checks using our policy flags. As this can be slow, we should // Run the script checks using our policy flags. As this can be slow, we should
// only invoke this on transactions that have otherwise passed policy checks. // only invoke this on transactions that have otherwise passed policy checks.
bool PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); bool PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
@ -823,7 +831,18 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
} }
m_rbf = !ws.m_conflicts.empty(); m_rbf = !ws.m_conflicts.empty();
if (m_rbf) { return true;
}
bool MemPoolAccept::ReplacementChecks(Workspace& ws)
{
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash;
TxValidationState& state = ws.m_state;
CFeeRate newFeeRate(ws.m_modified_fees, ws.m_vsize); CFeeRate newFeeRate(ws.m_modified_fees, ws.m_vsize);
// It's possible that the replacement pays more fees than its direct conflicts but not more // It's possible that the replacement pays more fees than its direct conflicts but not more
// than all conflicts (i.e. the direct conflicts have high-fee descendants). However, if the // than all conflicts (i.e. the direct conflicts have high-fee descendants). However, if the
@ -845,7 +864,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
"replacement-adds-unconfirmed", *err_string); "replacement-adds-unconfirmed", *err_string);
} }
// Check if it's economically rational to mine this transaction rather than the ones it // Check if it's economically rational to mine this transaction rather than the ones it
// replaces and pays for its own relay fees. Enforce BIP125 Rules #3 and #4. // replaces and pays for its own relay fees. Enforce BIP125 Rules #3 and #4.
for (CTxMemPool::txiter it : ws.m_all_conflicting) { for (CTxMemPool::txiter it : ws.m_all_conflicting) {
@ -856,6 +874,20 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
::incrementalRelayFee, hash)}) { ::incrementalRelayFee, hash)}) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string); return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
} }
return true;
}
bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
PackageValidationState& package_state)
{
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
std::string err_string;
if (!m_pool.CheckPackageLimits(txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants,
m_limit_descendant_size, err_string)) {
// This is a package-wide error, separate from an individual transaction error.
return package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", err_string);
} }
return true; return true;
} }
@ -966,6 +998,8 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state); if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
if (m_rbf && !ReplacementChecks(ws)) return MempoolAcceptResult::Failure(ws.m_state);
// Perform the inexpensive checks first and avoid hashing and signature verification unless // Perform the inexpensive checks first and avoid hashing and signature verification unless
// those checks pass, to mitigate CPU exhaustion denial-of-service attacks. // those checks pass, to mitigate CPU exhaustion denial-of-service attacks.
if (!PolicyScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state); if (!PolicyScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
@ -1020,12 +1054,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
// because it's unnecessary. Also, CPFP carve out can increase the limit for individual // because it's unnecessary. Also, CPFP carve out can increase the limit for individual
// transactions, but this exemption is not extended to packages in CheckPackageLimits(). // transactions, but this exemption is not extended to packages in CheckPackageLimits().
std::string err_string; std::string err_string;
if (txns.size() > 1 && if (txns.size() > 1 && !PackageMempoolChecks(txns, package_state)) {
!m_pool.CheckPackageLimits(txns, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants,
m_limit_descendant_size, err_string)) {
// All transactions must have individually passed mempool ancestor and descendant limits
// inside of PreChecks(), so this is separate from an individual transaction error.
package_state.Invalid(PackageValidationResult::PCKG_POLICY, "package-mempool-limits", err_string);
return PackageMempoolAcceptResult(package_state, std::move(results)); return PackageMempoolAcceptResult(package_state, std::move(results));
} }