Merge 5d045c31a5 into merged_master (Bitcoin PR bitcoin/bitcoin#28950)

This commit is contained in:
ivanlele 2026-02-16 12:56:07 +00:00
commit 1e1ba55cfb
No known key found for this signature in database
9 changed files with 124 additions and 30 deletions

View file

@ -489,6 +489,11 @@ public:
* policies such as mempool min fee and min relay fee.
*/
const bool m_package_feerates;
/** Used for local submission of transactions to catch "absurd" fees
* due to fee miscalculation by wallets. std:nullopt implies unset, allowing any feerates.
* Any individual transaction failing this check causes immediate failure.
*/
const std::optional<CFeeRate> m_client_maxfeerate;
/** Parameters for single transaction mempool validation. */
static ATMPArgs SingleAccept(const CChainParams& chainparams, int64_t accept_time,
@ -502,6 +507,7 @@ public:
/* m_allow_replacement */ true,
/* m_package_submission */ false,
/* m_package_feerates */ false,
/* m_client_maxfeerate */ {}, // checked by caller
};
}
@ -516,12 +522,13 @@ public:
/* m_allow_replacement */ false,
/* m_package_submission */ false, // not submitting to mempool
/* m_package_feerates */ false,
/* m_client_maxfeerate */ {}, // checked by caller
};
}
/** Parameters for child-with-unconfirmed-parents package validation. */
static ATMPArgs PackageChildWithParents(const CChainParams& chainparams, int64_t accept_time,
std::vector<COutPoint>& coins_to_uncache) {
std::vector<COutPoint>& coins_to_uncache, std::optional<CFeeRate>& client_maxfeerate) {
return ATMPArgs{/* m_chainparams */ chainparams,
/* m_accept_time */ accept_time,
/* m_bypass_limits */ false,
@ -530,6 +537,7 @@ public:
/* m_allow_replacement */ false,
/* m_package_submission */ true,
/* m_package_feerates */ true,
/* m_client_maxfeerate */ client_maxfeerate,
};
}
@ -543,6 +551,7 @@ public:
/* m_allow_replacement */ true,
/* m_package_submission */ true, // do not LimitMempoolSize in Finalize()
/* m_package_feerates */ false, // only 1 transaction
/* m_client_maxfeerate */ package_args.m_client_maxfeerate,
};
}
@ -556,7 +565,8 @@ public:
bool test_accept,
bool allow_replacement,
bool package_submission,
bool package_feerates)
bool package_feerates,
std::optional<CFeeRate> client_maxfeerate)
: m_chainparams{chainparams},
m_accept_time{accept_time},
m_bypass_limits{bypass_limits},
@ -564,7 +574,8 @@ public:
m_test_accept{test_accept},
m_allow_replacement{allow_replacement},
m_package_submission{package_submission},
m_package_feerates{package_feerates}
m_package_feerates{package_feerates},
m_client_maxfeerate{client_maxfeerate}
{
}
};
@ -1520,6 +1531,12 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
return MempoolAcceptResult::Failure(ws.m_state);
}
// Individual modified feerate exceeded caller-defined max; abort
if (args.m_client_maxfeerate && CFeeRate(ws.m_modified_fees, ws.m_vsize) > args.m_client_maxfeerate.value()) {
ws.m_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "max feerate exceeded", "");
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
@ -1580,6 +1597,16 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
return PackageMempoolAcceptResult(package_state, std::move(results));
}
// Individual modified feerate exceeded caller-defined max; abort
// N.B. this doesn't take into account CPFPs. Chunk-aware validation may be more robust.
if (args.m_client_maxfeerate && CFeeRate(ws.m_modified_fees, ws.m_vsize) > args.m_client_maxfeerate.value()) {
package_state.Invalid(PackageValidationResult::PCKG_TX, "max feerate exceeded");
// Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished.
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
return PackageMempoolAcceptResult(package_state, std::move(results));
}
// Make the coins created by this transaction available for subsequent transactions in the
// package to spend. Since we already checked conflicts in the package and we don't allow
// replacements, we don't need to track the coins spent. Note that this logic will need to be
@ -1924,7 +1951,7 @@ MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTra
}
PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool,
const Package& package, bool test_accept)
const Package& package, bool test_accept, std::optional<CFeeRate> client_maxfeerate)
{
AssertLockHeld(cs_main);
assert(!package.empty());
@ -1938,7 +1965,7 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM
auto args = MemPoolAccept::ATMPArgs::PackageTestAccept(chainparams, GetTime(), coins_to_uncache);
return MemPoolAccept(pool, active_chainstate).AcceptMultipleTransactions(package, args);
} else {
auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents(chainparams, GetTime(), coins_to_uncache);
auto args = MemPoolAccept::ATMPArgs::PackageChildWithParents(chainparams, GetTime(), coins_to_uncache, client_maxfeerate);
return MemPoolAccept(pool, active_chainstate).AcceptPackage(package, args);
}
}();