rbf.cpp raw

   1  // Copyright (c) 2016-present 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  RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
  25  {
  26      AssertLockHeld(pool.cs);
  27  
  28      // First check the transaction itself.
  29      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      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      const auto& entry{*Assert(pool.GetEntry(tx.GetHash()))};
  42      auto ancestors{pool.CalculateMemPoolAncestors(entry)};
  43  
  44      for (CTxMemPool::txiter it : ancestors) {
  45          if (SignalsOptInRBF(it->GetTx())) {
  46              return RBFTransactionState::REPLACEABLE_BIP125;
  47          }
  48      }
  49      return RBFTransactionState::FINAL;
  50  }
  51  
  52  RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx)
  53  {
  54      // If we don't have a local mempool we can only check the transaction itself.
  55      return SignalsOptInRBF(tx) ? RBFTransactionState::REPLACEABLE_BIP125 : RBFTransactionState::UNKNOWN;
  56  }
  57  
  58  std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,
  59                                                    CTxMemPool& pool,
  60                                                    const CTxMemPool::setEntries& iters_conflicting,
  61                                                    CTxMemPool::setEntries& all_conflicts)
  62  {
  63      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      auto num_clusters = pool.GetUniqueClusterCount(iters_conflicting);
  70      if (num_clusters > MAX_REPLACEMENT_CANDIDATES) {
  71          return strprintf("rejecting replacement %s; too many conflicting clusters (%u > %d)",
  72                  tx.GetHash().ToString(),
  73                  num_clusters,
  74                  MAX_REPLACEMENT_CANDIDATES);
  75      }
  76      // Calculate the set of all transactions that would have to be evicted.
  77      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          pool.CalculateDescendants(it, all_conflicts);
  81      }
  82      return std::nullopt;
  83  }
  84  
  85  std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
  86                                                     const std::set<Txid>& direct_conflicts,
  87                                                     const Txid& txid)
  88  {
  89      for (CTxMemPool::txiter ancestorIt : ancestors) {
  90          const Txid& hashAncestor = ancestorIt->GetTx().GetHash();
  91          if (direct_conflicts.contains(hashAncestor)) {
  92              return strprintf("%s spends conflicting transaction %s",
  93                               txid.ToString(),
  94                               hashAncestor.ToString());
  95          }
  96      }
  97      return std::nullopt;
  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  {
 129      // Require that the replacement strictly improves the mempool's feerate diagram.
 130      const auto chunk_results{changeset.CalculateChunksForRBF()};
 131  
 132      if (!chunk_results.has_value()) {
 133          return std::make_pair(DiagramCheckError::UNCALCULABLE, util::ErrorString(chunk_results).original);
 134      }
 135  
 136      if (!std::is_gt(CompareChunks(chunk_results.value().second, chunk_results.value().first))) {
 137          return std::make_pair(DiagramCheckError::FAILURE, "insufficient feerate: does not improve feerate diagram");
 138      }
 139      return std::nullopt;
 140  }
 141