| 98 | } |
| 99 | |
| 100 | std::optional<std::string> PaysForRBF(CAmount original_fees, |
| 101 | CAmount replacement_fees, |
| 102 | size_t replacement_vsize, |
| 103 | CFeeRate relay_fee, |
| 104 | const Txid& txid) |
| 105 | { |
| 106 | // Rule #3: The replacement fees must be greater than or equal to fees of the |
| 107 | // transactions it replaces, otherwise the bandwidth used by those conflicting transactions |
| 108 | // would not be paid for. |
| 109 | if (replacement_fees < original_fees) { |
| 110 | return strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s", |
| 111 | txid.ToString(), FormatMoney(replacement_fees), FormatMoney(original_fees)); |
| 112 | } |
| 113 | |
| 114 | // Rule #4: The new transaction must pay for its own bandwidth. Otherwise, we have a DoS |
| 115 | // vector where attackers can cause a transaction to be replaced (and relayed) repeatedly by |
| 116 | // increasing the fee by tiny amounts. |
| 117 | CAmount additional_fees = replacement_fees - original_fees; |
| 118 | if (additional_fees < relay_fee.GetFee(replacement_vsize)) { |
| 119 | return strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s", |
| 120 | txid.ToString(), |
| 121 | FormatMoney(additional_fees), |
| 122 | FormatMoney(relay_fee.GetFee(replacement_vsize))); |
| 123 | } |
| 124 | return std::nullopt; |
| 125 | } |
| 126 | |
| 127 | std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool::ChangeSet& changeset) |
| 128 | { |