Skip to content

Commit 9c2f9f8

Browse files
committed
MOVEONLY: check that fees > direct conflicts to policy/rbf
1 parent 3f033f0 commit 9c2f9f8

File tree

3 files changed

+43
-24
lines changed

3 files changed

+43
-24
lines changed

src/policy/rbf.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,35 @@ std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries&
129129
}
130130
return std::nullopt;
131131
}
132+
133+
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& setIterConflicting,
134+
CFeeRate newFeeRate,
135+
const uint256& hash)
136+
{
137+
for (const auto& mi : setIterConflicting) {
138+
// Don't allow the replacement to reduce the feerate of the
139+
// mempool.
140+
//
141+
// We usually don't want to accept replacements with lower
142+
// feerates than what they replaced as that would lower the
143+
// feerate of the next block. Requiring that the feerate always
144+
// be increased is also an easy-to-reason about way to prevent
145+
// DoS attacks via replacements.
146+
//
147+
// We only consider the feerates of transactions being directly
148+
// replaced, not their indirect descendants. While that does
149+
// mean high feerate children are ignored when deciding whether
150+
// or not to replace, we do require the replacement to pay more
151+
// overall fees too, mitigating most cases.
152+
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
153+
if (newFeeRate <= oldFeeRate)
154+
{
155+
return strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
156+
hash.ToString(),
157+
newFeeRate.ToString(),
158+
oldFeeRate.ToString());
159+
}
160+
}
161+
return std::nullopt;
162+
}
163+

src/policy/rbf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,13 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTx
6969
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& setAncestors,
7070
const std::set<uint256>& setConflicts,
7171
const uint256& txid);
72+
73+
/** Check that the feerate of the replacement transaction(s) is higher than the feerate of each
74+
* of the transactions in setIterConflicting.
75+
* @param[in] setIterConflicting The set of mempool entries.
76+
* @returns error message if fees insufficient, otherwise std::nullopt.
77+
*/
78+
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& setIterConflicting,
79+
CFeeRate newFeeRate, const uint256& hash);
80+
7281
#endif // BITCOIN_POLICY_RBF_H

src/validation.cpp

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -782,30 +782,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
782782
if (fReplacementTransaction)
783783
{
784784
CFeeRate newFeeRate(nModifiedFees, nSize);
785-
for (const auto& mi : setIterConflicting) {
786-
// Don't allow the replacement to reduce the feerate of the
787-
// mempool.
788-
//
789-
// We usually don't want to accept replacements with lower
790-
// feerates than what they replaced as that would lower the
791-
// feerate of the next block. Requiring that the feerate always
792-
// be increased is also an easy-to-reason about way to prevent
793-
// DoS attacks via replacements.
794-
//
795-
// We only consider the feerates of transactions being directly
796-
// replaced, not their indirect descendants. While that does
797-
// mean high feerate children are ignored when deciding whether
798-
// or not to replace, we do require the replacement to pay more
799-
// overall fees too, mitigating most cases.
800-
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
801-
if (newFeeRate <= oldFeeRate)
802-
{
803-
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee",
804-
strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
805-
hash.ToString(),
806-
newFeeRate.ToString(),
807-
oldFeeRate.ToString()));
808-
}
785+
if (const auto err_string{PaysMoreThanConflicts(setIterConflicting, newFeeRate, hash)}) {
786+
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
809787
}
810788

811789
// Calculate all conflicting entries and enforce Rule #5.

0 commit comments

Comments
 (0)