LCOV - code coverage report
Current view: top level - src/policy - rbf.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 93.8 % 48 45
Test Date: 2025-11-28 05:09:59 Functions: 83.3 % 6 5
Branches: 66.7 % 54 36

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2016-2022 The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <policy/rbf.h>
       6                 :             : 
       7                 :             : #include <consensus/amount.h>
       8                 :             : #include <kernel/mempool_entry.h>
       9                 :             : #include <policy/feerate.h>
      10                 :             : #include <primitives/transaction.h>
      11                 :             : #include <sync.h>
      12                 :             : #include <tinyformat.h>
      13                 :             : #include <txmempool.h>
      14                 :             : #include <uint256.h>
      15                 :             : #include <util/check.h>
      16                 :             : #include <util/moneystr.h>
      17                 :             : #include <util/rbf.h>
      18                 :             : 
      19                 :             : #include <limits>
      20                 :             : #include <vector>
      21                 :             : 
      22                 :             : #include <compare>
      23                 :             : 
      24                 :        9350 : RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
      25                 :             : {
      26                 :        9350 :     AssertLockHeld(pool.cs);
      27                 :             : 
      28                 :             :     // First check the transaction itself.
      29         [ +  + ]:        9350 :     if (SignalsOptInRBF(tx)) {
      30                 :             :         return RBFTransactionState::REPLACEABLE_BIP125;
      31                 :             :     }
      32                 :             : 
      33                 :             :     // If this transaction is not in our mempool, then we can't be sure
      34                 :             :     // we will know about all its inputs.
      35         [ +  + ]:        1527 :     if (!pool.exists(tx.GetHash())) {
      36                 :             :         return RBFTransactionState::UNKNOWN;
      37                 :             :     }
      38                 :             : 
      39                 :             :     // If all the inputs have nSequence >= maxint-1, it still might be
      40                 :             :     // signaled for RBF if any unconfirmed parents have signaled.
      41         [ -  + ]:        1315 :     const auto& entry{*Assert(pool.GetEntry(tx.GetHash()))};
      42                 :        1315 :     auto ancestors{pool.CalculateMemPoolAncestors(entry)};
      43                 :             : 
      44         [ +  + ]:        1327 :     for (CTxMemPool::txiter it : ancestors) {
      45   [ +  -  +  + ]:          14 :         if (SignalsOptInRBF(it->GetTx())) {
      46                 :             :             return RBFTransactionState::REPLACEABLE_BIP125;
      47                 :             :         }
      48                 :             :     }
      49                 :             :     return RBFTransactionState::FINAL;
      50                 :        1315 : }
      51                 :             : 
      52                 :           0 : RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx)
      53                 :             : {
      54                 :             :     // If we don't have a local mempool we can only check the transaction itself.
      55         [ #  # ]:           0 :     return SignalsOptInRBF(tx) ? RBFTransactionState::REPLACEABLE_BIP125 : RBFTransactionState::UNKNOWN;
      56                 :             : }
      57                 :             : 
      58                 :        1329 : std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,
      59                 :             :                                                   CTxMemPool& pool,
      60                 :             :                                                   const CTxMemPool::setEntries& iters_conflicting,
      61                 :             :                                                   CTxMemPool::setEntries& all_conflicts)
      62                 :             : {
      63                 :        1329 :     AssertLockHeld(pool.cs);
      64                 :             :     // Rule #5: don't consider replacements that conflict directly with more
      65                 :             :     // than MAX_REPLACEMENT_CANDIDATES distinct clusters. This implies a bound
      66                 :             :     // on how many mempool clusters might need to be re-sorted in order to
      67                 :             :     // process the replacement (though the actual number of clusters we
      68                 :             :     // relinearize may be greater than this number, due to cluster splitting).
      69                 :        1329 :     auto num_clusters = pool.GetUniqueClusterCount(iters_conflicting);
      70         [ +  + ]:        1329 :     if (num_clusters > MAX_REPLACEMENT_CANDIDATES) {
      71                 :           5 :         return strprintf("rejecting replacement %s; too many conflicting clusters (%u > %d)",
      72         [ +  - ]:          10 :                 tx.GetHash().ToString(),
      73                 :             :                 num_clusters,
      74                 :           5 :                 MAX_REPLACEMENT_CANDIDATES);
      75                 :             :     }
      76                 :             :     // Calculate the set of all transactions that would have to be evicted.
      77         [ +  + ]:        3403 :     for (CTxMemPool::txiter it : iters_conflicting) {
      78                 :             :         // The cluster count limit ensures that we won't do too much work on a
      79                 :             :         // single invocation of this function.
      80                 :        2079 :         pool.CalculateDescendants(it, all_conflicts);
      81                 :             :     }
      82                 :        1324 :     return std::nullopt;
      83                 :             : }
      84                 :             : 
      85                 :        1259 : std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
      86                 :             :                                                    const std::set<Txid>& direct_conflicts,
      87                 :             :                                                    const Txid& txid)
      88                 :             : {
      89         [ +  + ]:        1738 :     for (CTxMemPool::txiter ancestorIt : ancestors) {
      90                 :         487 :         const Txid& hashAncestor = ancestorIt->GetTx().GetHash();
      91         [ +  + ]:         487 :         if (direct_conflicts.count(hashAncestor)) {
      92                 :          16 :             return strprintf("%s spends conflicting transaction %s",
      93         [ +  - ]:          16 :                              txid.ToString(),
      94         [ +  - ]:          24 :                              hashAncestor.ToString());
      95                 :             :         }
      96                 :             :     }
      97                 :        1251 :     return std::nullopt;
      98                 :             : }
      99                 :             : 
     100                 :        1330 : 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         [ +  + ]:        1330 :     if (replacement_fees < original_fees) {
     110                 :          29 :         return strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
     111   [ +  -  +  - ]:         116 :                          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                 :        1301 :     CAmount additional_fees = replacement_fees - original_fees;
     118         [ +  + ]:        1301 :     if (additional_fees < relay_fee.GetFee(replacement_vsize)) {
     119                 :          18 :         return strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
     120         [ +  - ]:          36 :                          txid.ToString(),
     121         [ +  - ]:          36 :                          FormatMoney(additional_fees),
     122                 :          54 :                          FormatMoney(relay_fee.GetFee(replacement_vsize)));
     123                 :             :     }
     124                 :        1283 :     return std::nullopt;
     125                 :             : }
     126                 :             : 
     127                 :        1273 : std::optional<std::pair<DiagramCheckError, std::string>> ImprovesFeerateDiagram(CTxMemPool::ChangeSet& changeset)
     128                 :             : {
     129                 :             :     // Require that the replacement strictly improves the mempool's feerate diagram.
     130                 :        1273 :     const auto chunk_results{changeset.CalculateChunksForRBF()};
     131                 :             : 
     132         [ -  + ]:        1273 :     if (!chunk_results.has_value()) {
     133         [ #  # ]:           0 :         return std::make_pair(DiagramCheckError::UNCALCULABLE, util::ErrorString(chunk_results).original);
     134                 :             :     }
     135                 :             : 
     136   [ -  +  -  +  :        1273 :     if (!std::is_gt(CompareChunks(chunk_results.value().second, chunk_results.value().first))) {
             +  -  +  + ]
     137         [ +  - ]:           7 :         return std::make_pair(DiagramCheckError::FAILURE, "insufficient feerate: does not improve feerate diagram");
     138                 :             :     }
     139                 :        1266 :     return std::nullopt;
     140                 :        1273 : }
        

Generated by: LCOV version 2.0-1