24 #include <util/time.h> 34 #include <string_view> 59 std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef>
ret;
63 auto iter = mapNextTx.lower_bound(
COutPoint(hash, 0));
64 for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) {
65 ret.emplace_back(*(iter->second));
69 auto removed = std::ranges::unique(
ret, [](
auto& a,
auto& b) noexcept {
return &a.get() == &b.get(); });
70 ret.erase(removed.begin(), removed.end());
77 std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef>
ret;
78 std::set<Txid> inputs;
79 for (
const auto& txin : entry.
GetTx().
vin) {
80 inputs.insert(txin.prevout.hash);
82 for (
const auto& hash : inputs) {
83 std::optional<txiter> piter =
GetIter(hash);
85 ret.emplace_back(**piter);
97 for (
const Txid& hash : vHashesToUpdate | std::views::reverse) {
99 txiter it = mapTx.find(hash);
100 if (it == mapTx.end()) {
103 auto iter = mapNextTx.lower_bound(
COutPoint(hash, 0));
105 for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) {
106 txiter childIter = iter->second;
107 assert(childIter != mapTx.end());
110 m_txgraph->AddDependency(*it, *childIter);
115 auto txs_to_remove = m_txgraph->Trim();
116 for (
auto txptr : txs_to_remove) {
126 if (!entry)
return false;
134 if (ancestors.size() > 0) {
135 for (
auto ancestor : ancestors) {
136 if (ancestor != &entry) {
137 ret.insert(mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*ancestor)));
149 for (
unsigned int i = 0; i < tx.
vin.size(); i++) {
150 std::optional<txiter> piter =
GetIter(tx.
vin[i].prevout.hash);
152 staged_parents.insert(*piter);
156 for (
const auto& parent : staged_parents) {
158 for (
auto ancestor : parent_ancestors) {
159 ret.insert(mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*ancestor)));
168 opts.
check_ratio = std::clamp<int>(opts.check_ratio, 0, 1
'000'000);
169 int64_t cluster_limit_bytes = opts.limits.cluster_size_vbytes * 40;
170 if (opts.max_size_bytes < 0 || (opts.max_size_bytes > 0 && opts.max_size_bytes < cluster_limit_bytes)) {
171 error =
strprintf(
_(
"-maxmempool must be at least %d MB"), std::ceil(cluster_limit_bytes / 1
'000'000.0));
173 return std::move(opts);
177 : m_opts{
Flatten(std::move(opts), error)}
180 m_opts.limits.cluster_count,
184 const Txid& txid_a = static_cast<const CTxMemPoolEntry&>(a).GetTx().GetHash();
185 const Txid& txid_b = static_cast<const CTxMemPoolEntry&>(b).GetTx().GetHash();
186 return txid_a <=> txid_b;
193 return mapNextTx.count(outpoint);
209 m_txgraph->CommitStaging();
213 for (
size_t i=0; i<changeset->
m_entry_vec.size(); ++i) {
216 auto node_handle = changeset->
m_to_add.extract(tx_entry);
217 auto result = mapTx.insert(std::move(node_handle));
239 for (
unsigned int i = 0; i < tx.
vin.size(); i++) {
240 mapNextTx.insert(std::make_pair(&tx.
vin[i].prevout, newit));
251 m_total_fee += entry.
GetFee();
254 newit->idx_randomized = txns_randomized.size() - 1;
277 it->GetTx().GetHash().data(),
281 std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).
count()
284 for (
const CTxIn& txin : it->GetTx().vin)
285 mapNextTx.erase(txin.prevout);
289 if (txns_randomized.size() > 1) {
291 txns_randomized[it->idx_randomized] = std::move(txns_randomized.back());
292 txns_randomized[it->idx_randomized].second->idx_randomized = it->idx_randomized;
293 txns_randomized.pop_back();
294 if (txns_randomized.size() * 2 < txns_randomized.capacity()) {
295 txns_randomized.shrink_to_fit();
298 txns_randomized.clear();
301 totalTxSize -= it->GetTxSize();
302 m_total_fee -= it->GetFee();
303 cachedInnerUsage -= it->DynamicMemoryUsage();
318 setDescendants.insert(mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*tx)));
320 return mapTx.iterator_to(entry);
326 Assume(!m_have_changeset);
328 for (
auto tx: descendants) {
329 removeUnchecked(mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*tx)), reason);
337 Assume(!m_have_changeset);
339 if (origit != mapTx.end()) {
347 std::vector<const TxGraph::Ref*> to_remove;
348 while (iter != mapNextTx.end() && iter->first->hash == origTx.
GetHash()) {
349 to_remove.emplace_back(&*(iter->second));
353 for (
auto ref : all_removes) {
354 auto tx = mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*ref));
365 Assume(!m_have_changeset);
367 std::vector<const TxGraph::Ref*> to_remove;
368 for (
txiter it = mapTx.begin(); it != mapTx.end(); it++) {
369 if (check_final_and_mature(it)) {
370 to_remove.emplace_back(&*it);
376 for (
auto ref : all_to_remove) {
377 auto it = mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*ref));
380 for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
393 auto it = mapNextTx.find(txin.
prevout);
394 if (it != mapNextTx.end()) {
409 Assume(!m_have_changeset);
410 std::vector<RemovedMempoolTransactionInfo> txs_removed_for_block;
411 if (mapTx.size() || mapNextTx.size() || mapDeltas.size()) {
412 txs_removed_for_block.reserve(vtx.size());
413 for (
const auto& tx : vtx) {
414 txiter it = mapTx.find(tx->GetHash());
415 if (it != mapTx.end()) {
416 txs_removed_for_block.emplace_back(*it);
426 lastRollingFeeUpdate =
GetTime();
427 blockSinceLastRollingFeeBump =
true;
441 LogDebug(
BCLog::MEMPOOL,
"Checking mempool with %u transactions and %u inputs\n", (
unsigned int)mapTx.size(), (
unsigned int)mapNextTx.size());
443 uint64_t checkTotal = 0;
445 CAmount check_total_modified_fee{0};
446 int64_t check_total_adjusted_weight{0};
447 uint64_t innerUsage = 0;
450 m_txgraph->SanityCheck();
452 CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(&active_coins_tip));
458 assert(diagram.size() <= score_with_topo.size() + 1);
459 assert(diagram.size() >= 1);
461 std::optional<Wtxid> last_wtxid = std::nullopt;
462 auto diagram_iter = diagram.cbegin();
464 for (
const auto& it : score_with_topo) {
471 assert(diagram_iter->size >= check_total_adjusted_weight);
472 if (diagram_iter->fee == check_total_modified_fee &&
473 diagram_iter->size == check_total_adjusted_weight) {
476 checkTotal += it->GetTxSize();
477 check_total_adjusted_weight += it->GetAdjustedWeight();
478 check_total_fee += it->GetFee();
479 check_total_modified_fee += it->GetModifiedFee();
480 innerUsage += it->DynamicMemoryUsage();
489 std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setParentCheck;
490 std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setParentsStored;
493 indexed_transaction_set::const_iterator it2 = mapTx.find(txin.
prevout.
hash);
494 if (it2 != mapTx.end()) {
497 setParentCheck.insert(*it2);
505 auto it3 = mapNextTx.find(txin.
prevout);
506 assert(it3 != mapNextTx.end());
508 assert(&it3->second->GetTx() == &tx);
514 setParentsStored.insert(dynamic_cast<const CTxMemPoolEntry&>(txentry.get()));
516 assert(setParentCheck.size() == setParentsStored.size());
517 assert(std::equal(setParentCheck.begin(), setParentCheck.end(), setParentsStored.begin(), comp));
520 std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setChildrenCheck;
521 std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setChildrenStored;
522 auto iter = mapNextTx.lower_bound(
COutPoint(it->GetTx().GetHash(), 0));
523 for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) {
524 txiter childit = iter->second;
525 assert(childit != mapTx.end());
526 setChildrenCheck.insert(*childit);
529 setChildrenStored.insert(dynamic_cast<const CTxMemPoolEntry&>(txentry.get()));
531 assert(setChildrenCheck.size() == setChildrenStored.size());
532 assert(std::equal(setChildrenCheck.begin(), setChildrenCheck.end(), setChildrenStored.begin(), comp));
538 for (
const auto& input: tx.
vin) mempoolDuplicate.SpendCoin(input.prevout);
539 AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max());
541 for (
auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) {
542 indexed_transaction_set::const_iterator it2 = it->second;
543 assert(it2 != mapTx.end());
547 assert(diagram_iter == diagram.cend());
549 assert(totalTxSize == checkTotal);
550 assert(m_total_fee == check_total_fee);
551 assert(diagram.back().fee == check_total_modified_fee);
552 assert(diagram.back().size == check_total_adjusted_weight);
553 assert(innerUsage == cachedInnerUsage);
565 if (!j.has_value())
return false;
567 if (!i.has_value())
return true;
569 return m_txgraph->CompareMainOrder(*i.value(), *j.value()) < 0;
574 std::vector<indexed_transaction_set::const_iterator> iters;
577 iters.reserve(mapTx.size());
579 for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) {
583 return m_txgraph->CompareMainOrder(*a, *b) < 0;
592 std::vector<CTxMemPoolEntryRef>
ret;
593 ret.reserve(mapTx.size());
595 ret.emplace_back(*it);
605 std::vector<TxMempoolInfo>
ret;
606 ret.reserve(mapTx.size());
607 for (
auto it : iters) {
617 const auto i = mapTx.find(txid);
618 return i == mapTx.end() ? nullptr : &(*i);
624 indexed_transaction_set::const_iterator i = mapTx.find(hash);
625 if (i == mapTx.end())
627 return i->GetSharedTx();
634 CAmount &delta = mapDeltas[hash];
636 txiter it = mapTx.find(hash);
637 if (it != mapTx.end()) {
640 it->UpdateModifiedFee(nFeeDelta);
641 m_txgraph->SetTransactionFee(*it, it->GetModifiedFee());
645 mapDeltas.erase(hash);
646 LogInfo(
"PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.
ToString(), it == mapTx.end() ?
"not " :
"");
648 LogInfo(
"PrioritiseTransaction: %s (%sin mempool) fee += %s, new delta=%s\n",
650 it == mapTx.end() ?
"not " :
"",
660 std::map<Txid, CAmount>::const_iterator pos = mapDeltas.find(hash);
661 if (pos == mapDeltas.end())
663 const CAmount &delta = pos->second;
670 mapDeltas.erase(hash);
677 std::vector<delta_info>
result;
678 result.reserve(mapDeltas.size());
679 for (
const auto& [txid, delta] : mapDeltas) {
680 const auto iter{mapTx.find(txid)};
681 const bool in_mempool{iter != mapTx.end()};
682 std::optional<CAmount> modified_fee;
683 if (in_mempool) modified_fee = iter->GetModifiedFee();
691 const auto it = mapNextTx.find(prevout);
692 return it == mapNextTx.end() ? nullptr : &(it->second->GetTx());
698 auto it = mapTx.find(txid);
699 return it != mapTx.end() ? std::make_optional(it) : std::nullopt;
705 auto it{mapTx.project<0>(mapTx.get<
index_by_wtxid>().find(wtxid))};
706 return it != mapTx.end() ? std::make_optional(it) : std::nullopt;
712 for (
const auto& h : hashes) {
714 if (mi)
ret.insert(*mi);
722 std::vector<txiter>
ret;
723 ret.reserve(txids.size());
724 for (
const auto& txid : txids) {
734 for (
unsigned int i = 0; i < tx.
vin.size(); i++)
755 if (outpoint.
n < ptx->vout.size()) {
767 for (
unsigned int n = 0; n < tx->vout.size(); ++n) {
787 if (m_unbroadcast_txids.erase(txid))
789 LogDebug(
BCLog::MEMPOOL,
"Removed %i from set of unbroadcast txns%s\n", txid.
GetHex(), (unchecked ?
" before confirmation that txn was sent out" :
""));
807 (void) changeset->StageAddition(tx, 0, 0, 0, 0,
false, 0,
LockPoints{});
808 return changeset->CheckMemPoolPolicyLimits();
814 Assume(!m_have_changeset);
815 indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<
entry_time>().begin();
817 while (it != mapTx.get<
entry_time>().end() && it->GetTime() < time) {
818 toremove.insert(mapTx.project<0>(it));
822 for (
txiter removeit : toremove) {
831 if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
832 return CFeeRate(llround(rollingMinimumFeeRate));
835 if (time > lastRollingFeeUpdate + 10) {
842 rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
843 lastRollingFeeUpdate = time;
846 rollingMinimumFeeRate = 0;
855 if (rate.
GetFeePerK() > rollingMinimumFeeRate) {
857 blockSinceLastRollingFeeBump =
false;
863 Assume(!m_have_changeset);
865 unsigned nTxnRemoved = 0;
869 const auto &[worst_chunk, feeperweight] = m_txgraph->GetWorstMainChunk();
879 maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
881 nTxnRemoved += worst_chunk.size();
883 std::vector<CTransaction> txn;
884 if (pvNoSpendsRemaining) {
885 txn.reserve(worst_chunk.size());
886 for (
auto ref : worst_chunk) {
887 txn.emplace_back(static_cast<const CTxMemPoolEntry&>(*ref).GetTx());
892 for (
auto ref : worst_chunk) {
893 stage.insert(mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*ref)));
895 for (
auto e : stage) {
898 if (pvNoSpendsRemaining) {
902 pvNoSpendsRemaining->push_back(txin.
prevout);
908 if (maxFeeRateRemoved >
CFeeRate(0)) {
917 size_t ancestor_count = ancestors.size();
918 size_t ancestor_size = 0;
920 for (
auto tx: ancestors) {
925 return {ancestor_count, ancestor_size, ancestor_fees};
931 size_t descendant_count = descendants.size();
932 size_t descendant_size = 0;
935 for (
auto tx: descendants) {
940 return {descendant_count, descendant_size, descendant_fees};
945 auto it = mapTx.find(txid);
946 ancestors = cluster_count = 0;
947 if (it != mapTx.end()) {
949 ancestors = ancestor_count;
950 if (ancestorsize) *ancestorsize = ancestor_size;
951 if (ancestorfees) *ancestorfees = ancestor_fees;
965 m_load_tried = load_tried;
972 std::vector<CTxMemPool::txiter>
ret;
973 std::set<const CTxMemPoolEntry*> unique_cluster_representatives;
974 for (
auto txid : txids) {
975 auto it = mapTx.find(txid);
976 if (it != mapTx.end()) {
981 if (unique_cluster_representatives.insert(static_cast<const CTxMemPoolEntry*>(&(**cluster.begin()))).second) {
982 for (
auto tx : cluster) {
983 ret.emplace_back(mapTx.iterator_to(static_cast<const CTxMemPoolEntry&>(*tx)));
988 if (
ret.size() > 500) {
1002 return m_pool->m_txgraph->GetMainStagingDiagrams();
1008 Assume(m_to_add.find(tx->GetHash()) == m_to_add.end());
1009 Assume(!m_dependencies_processed);
1012 m_dependencies_processed =
false;
1015 m_pool->ApplyDelta(tx->GetHash(), delta);
1018 auto newit = m_to_add.emplace(tx,
fee, time, entry_height, entry_sequence, spends_coinbase, sigops_cost,
lp).first;
1019 m_pool->m_txgraph->AddTransaction(const_cast<CTxMemPoolEntry&>(*newit), feerate);
1021 newit->UpdateModifiedFee(delta);
1022 m_pool->m_txgraph->SetTransactionFee(*newit, newit->GetModifiedFee());
1025 m_entry_vec.push_back(newit);
1033 m_pool->m_txgraph->RemoveTransaction(*it);
1034 m_to_remove.insert(it);
1040 if (!m_dependencies_processed) {
1041 ProcessDependencies();
1043 m_pool->Apply(
this);
1045 m_to_remove.clear();
1046 m_entry_vec.clear();
1047 m_ancestors.clear();
1053 Assume(!m_dependencies_processed);
1054 for (
const auto& entryptr : m_entry_vec) {
1055 for (
const auto &txin : entryptr->GetSharedTx()->vin) {
1056 std::optional<txiter> piter = m_pool->GetIter(txin.
prevout.
hash);
1059 if (it != m_to_add.end()) {
1060 piter = std::make_optional(it);
1064 m_pool->m_txgraph->AddDependency(**piter, *entryptr);
1068 m_dependencies_processed =
true;
1075 if (!m_dependencies_processed) {
1076 ProcessDependencies();
1085 std::vector<FeePerWeight>
ret;
1087 ret.emplace_back(zero);
1091 std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> dummy;
1095 last_selection +=
ret.back();
1096 ret.emplace_back(last_selection);
std::shared_ptr< const CTransaction > CTransactionRef
std::string GetHex() const
void IncludeBuilderChunk() const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::unordered_set< COutPoint, SaltedOutpointHasher > m_non_base_coins
Set of all coins that have been fetched from mempool or created using PackageAddTransaction (not base...
Always refers to the main graph, whether staging is present or not.
bool CheckTxInputs(const CTransaction &tx, TxValidationState &state, const CCoinsViewCache &inputs, int nSpendHeight, CAmount &txfee)
Check whether all inputs of this transaction are valid (no double spends and amounts) This does not m...
std::string RemovalReasonToString(const MemPoolRemovalReason &r) noexcept
CTxMemPool(Options opts, bilingual_str &error)
Create a new CTxMemPool.
static const int WITNESS_SCALE_FACTOR
indexed_transaction_set::nth_index< 0 >::type::const_iterator txiter
std::vector< TxMempoolInfo > infoAll() const
int32_t GetTxSize() const
void Apply(CTxMemPool::ChangeSet *changeset) EXCLUSIVE_LOCKS_REQUIRED(cs)
std::vector< indexed_transaction_set::const_iterator > GetSortedScoreWithTopology() const EXCLUSIVE_LOCKS_REQUIRED(cs)
An in-memory indexed chain of blocks.
void CalculateDescendants(txiter it, setEntries &setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Populate setDescendants with all in-mempool descendants of given transaction.
static size_t DynamicUsage(const int8_t &v)
Dynamic memory usage for built-in types is zero.
size_t DynamicMemoryUsage() const
std::vector< txiter > GatherClusters(const std::vector< Txid > &txids) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Collect the entire cluster of connected transactions for each transaction in txids.
ValidationSignals * signals
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal...
int64_t GetTime()
DEPRECATED, see GetTime.
void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs)
Removed for conflict with in-block transaction.
void StartBlockBuilding() const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::unique_ptr< ChangeSet > GetChangeSet() EXCLUSIVE_LOCKS_REQUIRED(cs)
std::set< txiter, CompareIteratorByHash > setEntries
CTransactionRef get(const Txid &hash) const
std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetParents(const CTxMemPoolEntry &entry) const
std::atomic< unsigned int > nTransactionsUpdated
Used by getblocktemplate to trigger CreateNewBlock() invocation.
void check(const CCoinsViewCache &active_coins_tip, int64_t spendheight) const EXCLUSIVE_LOCKS_REQUIRED(void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
If sanity-checking is turned on, check makes sure the pool is consistent (does not contain two transa...
std::vector< txiter > GetIterVec(const std::vector< Txid > &txids) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Translate a list of hashes into a list of mempool iterators to avoid repeated lookups.
void SetLoadTried(bool load_tried)
Set whether or not an initial attempt to load the persisted mempool was made (regardless of whether t...
void StageRemoval(CTxMemPool::txiter it)
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
consteval auto _(util::TranslatedLiteral str)
std::optional< txiter > GetIter(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
std::tuple< size_t, size_t, CAmount > CalculateAncestorData(const CTxMemPoolEntry &entry) const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
GetCoin, returning whether it exists and is not spent.
static int32_t GetTransactionWeight(const CTransaction &tx)
CTxMemPool::indexed_transaction_set m_to_add
void StopBlockBuilding() const EXCLUSIVE_LOCKS_REQUIRED(cs)
CAmount GetModifiedFee() const
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it)
void PrioritiseTransaction(const Txid &hash, const CAmount &nFeeDelta)
Affect CreateNewBlock prioritisation of transactions.
bool isSpent(const COutPoint &outpoint) const
const std::vector< CTxIn > vin
void removeForReorg(CChain &chain, std::function< bool(txiter)> filter_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs
After reorg, filter the entries that would no longer be valid in the next block, and update the entri...
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
void ApplyDelta(const Txid &hash, CAmount &nFeeDelta) const EXCLUSIVE_LOCKS_REQUIRED(cs)
int64_t CAmount
Amount in satoshis (Can be negative)
void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight, bool check_for_overwrite)
Utility function to add all of a transaction's outputs to a cache.
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coin to signify they are only in the memory pool (since 0...
util::Result< std::pair< std::vector< FeeFrac >, std::vector< FeeFrac > > > CalculateChunksForRBF()
Calculate the sorted chunks for the old and new mempool relating to the clusters that would be affect...
int64_t GetSigOpsAdjustedWeight(int64_t weight, int64_t sigop_cost, unsigned int bytes_per_sigop)
bool CompareMiningScoreWithTopology(const Wtxid &hasha, const Wtxid &hashb) const
static constexpr uint64_t POST_CHANGE_COST
How much work we ask TxGraph to do after a mempool change occurs (either due to a changeset being app...
static constexpr uint64_t ACCEPTABLE_COST
How much linearization cost required for TxGraph clusters to have "acceptable" quality, if they cannot be optimally linearized with less cost.
Abstract view on the open txout dataset.
size_t DynamicMemoryUsage() const
int Expire(std::chrono::seconds time) EXCLUSIVE_LOCKS_REQUIRED(cs)
Expire all transaction (and their dependencies) in the mempool older than time.
An input of a transaction.
Removed for reorganization.
const CAmount & GetFee() const
std::vector< CTxMemPool::txiter > m_entry_vec
TRACEPOINT_SEMAPHORE(mempool, added)
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
void removeUnchecked(txiter entry, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
setEntries CalculateMemPoolAncestors(const CTxMemPoolEntry &entry) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Calculate all in-mempool ancestors of entry (not including the tx itself)
const std::vector< CTxOut > vout
Removed in size limiting.
std::string ToString() const
bool TestLockPointValidity(CChain &active_chain, const LockPoints &lp)
Test whether the LockPoints height and time are still valid on the current chain. ...
std::vector< delta_info > GetPrioritisedTransactions() const EXCLUSIVE_LOCKS_REQUIRED(!cs)
Return a vector of all entries in mapDeltas with their corresponding delta_info.
CTxMemPool::txiter TxHandle
static const int ROLLING_FEE_HALFLIFE
constexpr const std::byte * data() const
const CTransaction * GetConflictTx(const COutPoint &prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Get the transaction in the pool that spends the same prevout.
An outpoint - a combination of a transaction hash and an index n into its vout.
void AddTransactionsUpdated(unsigned int n)
#define Assume(val)
Assume is the identity function.
static size_t MallocUsage(size_t alloc)
Compute the total memory used by allocating alloc bytes.
bool exists(const Txid &txid) const
std::vector< FeePerWeight > GetFeerateDiagram() const EXCLUSIVE_LOCKS_REQUIRED(cs)
bool GetLoadTried() const
std::string ToString(FeeRateFormat fee_rate_format=FeeRateFormat::BTC_KVB) const
static FeePerVSize ToFeePerVSize(FeePerWeight feerate)
#define LogDebug(category,...)
std::string FormatMoney(const CAmount n)
Money parsing/formatting utilities.
void Apply() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
T SaturatingAdd(const T i, const T j) noexcept
const CTxMemPoolEntry * GetEntry(const Txid &txid) const LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(cs)
uint64_t GetAndIncrementSequence() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Guards this internal counter for external reporting.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
unsigned int nBytesPerSigOp
void UpdateTransactionsFromBlock(const std::vector< Txid > &vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs
UpdateTransactionsFromBlock is called when adding transactions from a disconnected block back to the ...
void MempoolTransactionsRemovedForBlock(const std::vector< RemovedMempoolTransactionInfo > &, unsigned int nBlockHeight)
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
void RemoveUnbroadcastTx(const Txid &txid, bool unchecked=false)
Removes a transaction from the unbroadcast set.
void GetTransactionAncestry(const Txid &txid, size_t &ancestors, size_t &cluster_count, size_t *ancestorsize=nullptr, CAmount *ancestorfees=nullptr) const
Calculate the ancestor and cluster count for the given transaction.
bool HasNoInputsOf(const CTransaction &tx) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Check that none of this transactions inputs are in the mempool, and thus the tx is not dependent on o...
FeePerWeight GetBlockBuilderChunk(std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > &entries) const EXCLUSIVE_LOCKS_REQUIRED(cs)
CTxMemPool::setEntries m_to_remove
void Reset()
Clear m_temp_added and m_non_base_coins.
TxHandle StageAddition(const CTransactionRef &tx, CAmount fee, int64_t time, unsigned int entry_height, uint64_t entry_sequence, bool spends_coinbase, int64_t sigops_cost, LockPoints lp)
std::tuple< size_t, size_t, CAmount > CalculateDescendantData(const CTxMemPoolEntry &entry) const EXCLUSIVE_LOCKS_REQUIRED(cs)
const CTransaction & GetTx() const
#define TRACEPOINT(context,...)
std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetChildren(const CTxMemPoolEntry &entry) const
virtual std::optional< Coin > GetCoin(const COutPoint &outpoint) const
Retrieve the Coin (unspent transaction output) for a given outpoint.
bool CheckMemPoolPolicyLimits()
Check if any cluster limits are exceeded.
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
#define AssertLockNotHeld(cs)
unsigned int GetTransactionsUpdated() const
std::unique_ptr< TxGraph > MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size, uint64_t acceptable_cost, const std::function< std::strong_ordering(const TxGraph::Ref &, const TxGraph::Ref &)> &fallback_order) noexcept
Construct a new TxGraph with the specified limit on the number of transactions within a cluster...
void PackageAddTransaction(const CTransactionRef &tx)
Add the coins created by this transaction.
static CTxMemPool::Options && Flatten(CTxMemPool::Options &&opts, bilingual_str &error)
void TrimToSize(size_t sizelimit, std::vector< COutPoint > *pvNoSpendsRemaining=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Remove transactions from the mempool until its dynamic size is <= sizelimit.
void trackPackageRemoved(const CFeeRate &rate) EXCLUSIVE_LOCKS_REQUIRED(cs)
CCoinsViewMemPool(CCoinsView *baseIn, const CTxMemPool &mempoolIn)
Options struct containing options for constructing a CTxMemPool.
The basic transaction that is broadcasted on the network and contained in blocks. ...
CCoinsView backed by another CCoinsView.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
const CTxMemPool & mempool
bool HasDescendants(const Txid &txid) const
bool CheckPolicyLimits(const CTransactionRef &tx)
CBlockIndex * maxInputBlock
void RemoveStaged(setEntries &stage, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
Remove a set of transactions from the mempool.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
void addNewTransaction(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(cs)
void ClearPrioritisation(const Txid &hash) EXCLUSIVE_LOCKS_REQUIRED(cs)
void removeForBlock(const std::vector< CTransactionRef > &vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs)
setEntries GetIterSet(const std::set< Txid > &hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Translate a set of hashes into a set of pool iterators to avoid repeated lookups. ...
Refers to staging if it exists, main otherwise.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
std::unordered_map< COutPoint, Coin, SaltedOutpointHasher > m_temp_added
Coins made available by transactions being validated.
const Wtxid & GetWitnessHash() const LIFETIMEBOUND
std::vector< CTxMemPoolEntryRef > entryAll() const EXCLUSIVE_LOCKS_REQUIRED(cs)
void ProcessDependencies()
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
const Txid & GetHash() const LIFETIMEBOUND
CFeeRate incremental_relay_feerate
void TransactionRemovedFromMempool(const CTransactionRef &, MemPoolRemovalReason, uint64_t mempool_sequence)