MOVEONLY: fee checks (Rules 3 and 4) to policy/rbf

This commit is contained in:
glozow 2021-08-11 15:51:41 +01:00
parent 9c2f9f8984
commit ac761f0a23
3 changed files with 43 additions and 22 deletions

View file

@ -161,3 +161,29 @@ std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& s
return std::nullopt;
}
std::optional<std::string> PaysForRBF(CAmount nConflictingFees,
CAmount nModifiedFees,
size_t nSize,
const uint256& hash)
{
// The replacement must pay greater fees than the transactions it
// replaces - if we did the bandwidth used by those conflicting
// transactions would not be paid for.
if (nModifiedFees < nConflictingFees)
{
return strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees));
}
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
{
return strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
FormatMoney(::incrementalRelayFee.GetFee(nSize)));
}
return std::nullopt;
}

View file

@ -78,4 +78,18 @@ std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries&
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& setIterConflicting,
CFeeRate newFeeRate, const uint256& hash);
/** Enforce BIP125 Rule #3 "The replacement transaction pays an absolute fee of at least the sum
* paid by the original transactions." Enforce BIP125 Rule #4 "The replacement transaction must also
* pay for its own bandwidth at or above the rate set by the node's minimum relay fee setting."
* @param[in] nConflictingFees Total modified fees of original transaction(s).
* @param[in] nModifiedFees Total modified fees of replacement transaction(s).
* @param[in] nSize Total virtual size of replacement transaction(s).
* @param[in] hash Transaction ID, included in the error message if violation occurs.
* @returns error string if fees are insufficient, otherwise std::nullopt.
*/
std::optional<std::string> PaysForRBF(CAmount nConflictingFees,
CAmount nModifiedFees,
size_t nSize,
const uint256& hash);
#endif // BITCOIN_POLICY_RBF_H

View file

@ -798,32 +798,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
// Check if it's economically rational to mine this transaction rather
// than the ones it replaces.
// than the ones it replaces. Enforce Rules #3 and #4.
for (CTxMemPool::txiter it : allConflicting) {
nConflictingFees += it->GetModifiedFee();
nConflictingSize += it->GetTxSize();
}
// The replacement must pay greater fees than the transactions it
// replaces - if we did the bandwidth used by those conflicting
// transactions would not be paid for.
if (nModifiedFees < nConflictingFees)
{
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee",
strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)));
}
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
{
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee",
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
FormatMoney(::incrementalRelayFee.GetFee(nSize))));
if (const auto err_string{PaysForRBF(nConflictingFees, nModifiedFees, nSize, hash)}) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
}
}
return true;