aboutsummaryrefslogtreecommitdiff
path: root/src/policy
diff options
context:
space:
mode:
Diffstat (limited to 'src/policy')
-rw-r--r--src/policy/rbf.cpp32
-rw-r--r--src/policy/rbf.h9
2 files changed, 41 insertions, 0 deletions
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 95b74123c9..5d1db6b58d 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -129,3 +129,35 @@ std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries&
}
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;
+}
+
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 6c4e218959..2c548152b5 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -69,4 +69,13 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTx
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& setAncestors,
const std::set<uint256>& setConflicts,
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