mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
MOVEONLY: check that fees > direct conflicts to policy/rbf
This commit is contained in:
parent
3f033f01a6
commit
9c2f9f8984
3 changed files with 43 additions and 24 deletions
|
@ -129,3 +129,35 @@ std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries&
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& setIterConflicting,
|
||||||
|
CFeeRate newFeeRate,
|
||||||
|
const uint256& hash)
|
||||||
|
{
|
||||||
|
for (const auto& mi : setIterConflicting) {
|
||||||
|
// Don't allow the replacement to reduce the feerate of the
|
||||||
|
// mempool.
|
||||||
|
//
|
||||||
|
// We usually don't want to accept replacements with lower
|
||||||
|
// feerates than what they replaced as that would lower the
|
||||||
|
// feerate of the next block. Requiring that the feerate always
|
||||||
|
// be increased is also an easy-to-reason about way to prevent
|
||||||
|
// DoS attacks via replacements.
|
||||||
|
//
|
||||||
|
// We only consider the feerates of transactions being directly
|
||||||
|
// replaced, not their indirect descendants. While that does
|
||||||
|
// mean high feerate children are ignored when deciding whether
|
||||||
|
// or not to replace, we do require the replacement to pay more
|
||||||
|
// overall fees too, mitigating most cases.
|
||||||
|
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
|
||||||
|
if (newFeeRate <= oldFeeRate)
|
||||||
|
{
|
||||||
|
return strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
|
||||||
|
hash.ToString(),
|
||||||
|
newFeeRate.ToString(),
|
||||||
|
oldFeeRate.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,4 +69,13 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTx
|
||||||
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& setAncestors,
|
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& setAncestors,
|
||||||
const std::set<uint256>& setConflicts,
|
const std::set<uint256>& setConflicts,
|
||||||
const uint256& txid);
|
const uint256& txid);
|
||||||
|
|
||||||
|
/** Check that the feerate of the replacement transaction(s) is higher than the feerate of each
|
||||||
|
* of the transactions in setIterConflicting.
|
||||||
|
* @param[in] setIterConflicting The set of mempool entries.
|
||||||
|
* @returns error message if fees insufficient, otherwise std::nullopt.
|
||||||
|
*/
|
||||||
|
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& setIterConflicting,
|
||||||
|
CFeeRate newFeeRate, const uint256& hash);
|
||||||
|
|
||||||
#endif // BITCOIN_POLICY_RBF_H
|
#endif // BITCOIN_POLICY_RBF_H
|
||||||
|
|
|
@ -782,30 +782,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||||
if (fReplacementTransaction)
|
if (fReplacementTransaction)
|
||||||
{
|
{
|
||||||
CFeeRate newFeeRate(nModifiedFees, nSize);
|
CFeeRate newFeeRate(nModifiedFees, nSize);
|
||||||
for (const auto& mi : setIterConflicting) {
|
if (const auto err_string{PaysMoreThanConflicts(setIterConflicting, newFeeRate, hash)}) {
|
||||||
// Don't allow the replacement to reduce the feerate of the
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
|
||||||
// mempool.
|
|
||||||
//
|
|
||||||
// We usually don't want to accept replacements with lower
|
|
||||||
// feerates than what they replaced as that would lower the
|
|
||||||
// feerate of the next block. Requiring that the feerate always
|
|
||||||
// be increased is also an easy-to-reason about way to prevent
|
|
||||||
// DoS attacks via replacements.
|
|
||||||
//
|
|
||||||
// We only consider the feerates of transactions being directly
|
|
||||||
// replaced, not their indirect descendants. While that does
|
|
||||||
// mean high feerate children are ignored when deciding whether
|
|
||||||
// or not to replace, we do require the replacement to pay more
|
|
||||||
// overall fees too, mitigating most cases.
|
|
||||||
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
|
|
||||||
if (newFeeRate <= oldFeeRate)
|
|
||||||
{
|
|
||||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee",
|
|
||||||
strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
|
|
||||||
hash.ToString(),
|
|
||||||
newFeeRate.ToString(),
|
|
||||||
oldFeeRate.ToString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate all conflicting entries and enforce Rule #5.
|
// Calculate all conflicting entries and enforce Rule #5.
|
||||||
|
|
Loading…
Add table
Reference in a new issue