Bitcoin ABC  0.29.2
P2P Digital Currency
disconnected_transactions.h
Go to the documentation of this file.
1 // Copyright (c) 2023 The Bitcoin Core developers
2 // Copyright (c) 2024 The Bitcoin developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #ifndef BITCOIN_KERNEL_DISCONNECTED_TRANSACTIONS_H
7 #define BITCOIN_KERNEL_DISCONNECTED_TRANSACTIONS_H
8 
9 #include <consensus/amount.h>
10 #include <memusage.h>
11 #include <threadsafety.h>
12 #include <txmempool.h>
13 #include <util/hasher.h>
14 
15 #include <boost/multi_index/hashed_index.hpp>
16 #include <boost/multi_index/sequenced_index.hpp>
17 #include <boost/multi_index_container.hpp>
18 
19 #include <cassert>
20 #include <unordered_map>
21 #include <vector>
22 
41 // multi_index tag names
42 struct txid_index {};
43 struct insertion_order {};
44 
46 private:
47  typedef boost::multi_index_container<
48  CTransactionRef, boost::multi_index::indexed_by<
49  // hashed by txid
50  boost::multi_index::hashed_unique<
51  boost::multi_index::tag<txid_index>,
53  // sorted by order in the blockchain
54  boost::multi_index::sequenced<
55  boost::multi_index::tag<insertion_order>>>>
57 
59  uint64_t cachedInnerUsage = 0;
60 
61  struct TxInfo {
62  const std::chrono::seconds time;
64  const unsigned height;
65  TxInfo(const std::chrono::seconds &time_, Amount feeDelta_,
66  unsigned height_) noexcept
67  : time(time_), feeDelta(feeDelta_), height(height_) {}
68  };
69 
70  using TxInfoMap = std::unordered_map<TxId, TxInfo, SaltedTxIdHasher>;
73 
74  void addTransaction(const CTransactionRef &tx) {
75  queuedTx.insert(tx);
77  }
78 
82  const TxInfo *getTxInfo(const CTransactionRef &tx) const;
83 
84 public:
85  // It's almost certainly a logic bug if we don't clear out queuedTx before
86  // destruction, as we add to it while disconnecting blocks, and then we
87  // need to re-process remaining transactions to ensure mempool consistency.
88  // For now, assert() that we've emptied out this object on destruction.
89  // This assert() can always be removed if the reorg-processing code were
90  // to be refactored such that this assumption is no longer true (for
91  // instance if there was some other way we cleaned up the mempool after a
92  // reorg, besides draining this object).
94 
95  // Estimate the overhead of queuedTx to be 6 pointers + an allocation, as
96  // no exact formula for boost::multi_index_contained is implemented.
97  size_t DynamicMemoryUsage() const {
98  return memusage::MallocUsage(sizeof(CTransactionRef) +
99  6 * sizeof(void *)) *
100  queuedTx.size() +
102  }
103 
105  return queuedTx;
106  }
107 
108  // Import mempool entries in topological order into queuedTx and clear the
109  // mempool. Caller should call updateMempoolForReorg to reprocess these
110  // transactions
112 
113  // Add entries for a block while reconstructing the topological ordering so
114  // they can be added back to the mempool simply.
115  void addForBlock(const std::vector<CTransactionRef> &vtx, CTxMemPool &pool)
116  EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
117 
118  // Remove entries based on txid_index, and update memory usage.
119  void removeForBlock(const std::vector<CTransactionRef> &vtx) {
120  // Short-circuit in the common case of a block being added to the tip
121  if (queuedTx.empty()) {
122  return;
123  }
124  for (auto const &tx : vtx) {
125  auto it = queuedTx.find(tx->GetId());
126  if (it != queuedTx.end()) {
128  queuedTx.erase(it);
129  txInfo.erase(tx->GetId());
130  }
131  }
132  }
133 
134  void removeForBlock(const std::vector<CTransactionRef> &vtx,
135  CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
136 
137  // Remove an entry by insertion_order index, and update memory usage.
138  void removeEntry(indexed_disconnected_transactions::index<
139  insertion_order>::type::iterator entry) {
141  txInfo.erase((*entry)->GetId());
142  queuedTx.get<insertion_order>().erase(entry);
143  }
144 
145  bool isEmpty() const { return queuedTx.empty(); }
146 
147  void clear() {
148  cachedInnerUsage = 0;
149  queuedTx.clear();
150  txInfo.clear();
151  }
152 
166  void updateMempoolForReorg(Chainstate &active_chainstate,
167  bool fAddToMempool, CTxMemPool &pool)
169 };
170 
171 #endif // BITCOIN_KERNEL_DISCONNECTED_TRANSACTIONS_H
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:209
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:629
std::unordered_map< TxId, TxInfo, SaltedTxIdHasher > TxInfoMap
void removeEntry(indexed_disconnected_transactions::index< insertion_order >::type::iterator entry)
indexed_disconnected_transactions queuedTx
TxInfoMap txInfo
populated by importMempool(); the original tx entry times and feeDeltas
void removeForBlock(const std::vector< CTransactionRef > &vtx)
boost::multi_index_container< CTransactionRef, boost::multi_index::indexed_by< boost::multi_index::hashed_unique< boost::multi_index::tag< txid_index >, mempoolentry_txid, SaltedTxIdHasher >, boost::multi_index::sequenced< boost::multi_index::tag< insertion_order > > > > indexed_disconnected_transactions
const TxInfo * getTxInfo(const CTransactionRef &tx) const
void addTransaction(const CTransactionRef &tx)
void updateMempoolForReorg(Chainstate &active_chainstate, bool fAddToMempool, CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main
Make mempool consistent after a reorg, by re-adding or recursively erasing disconnected block transac...
const indexed_disconnected_transactions & GetQueuedTx() const
void addForBlock(const std::vector< CTransactionRef > &vtx, CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
void importMempool(CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
static size_t RecursiveDynamicUsage(const CScript &script)
Definition: core_memusage.h:12
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
static size_t DynamicUsage(const int8_t &v)
Dynamic memory usage for built-in types is zero.
Definition: memusage.h:26
static size_t MallocUsage(size_t alloc)
Compute the total memory used by allocating alloc bytes.
Definition: memusage.h:72
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
Definition: amount.h:19
TxInfo(const std::chrono::seconds &time_, Amount feeDelta_, unsigned height_) noexcept
DisconnectedBlockTransactions.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
assert(!tx.IsCoinBase())