Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
501// Check whether its inputs are marked in mapNextTx.502auto it3 = mapNextTx.find(txin.prevout);503assert(it3 != mapNextTx.end());504assert(it3->first == &txin.prevout);505assert(&it3->second->GetTx() == &tx);506}507auto comp = [](const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) -> bool {508return a.GetTx().GetHash() == b.GetTx().GetHash();509};510for (auto &txentry : GetParents(*it)) {511setParentsStored.insert(dynamic_cast<const CTxMemPoolEntry&>(txentry.get()));512}513assert(setParentCheck.size() == setParentsStored.size());514assert(std::equal(setParentCheck.begin(), setParentCheck.end(), setParentsStored.begin(), comp));516// Check children against mapNextTx517std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setChildrenCheck;518std::set<CTxMemPoolEntry::CTxMemPoolEntryRef, CompareIteratorByHash> setChildrenStored;519auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));520for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) {521txiter childit = iter->second;522assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions523setChildrenCheck.insert(*childit);524}525for (auto &txentry : GetChildren(*it)) {526setChildrenStored.insert(dynamic_cast<const CTxMemPoolEntry&>(txentry.get()));527}528assert(setChildrenCheck.size() == setChildrenStored.size());529assert(std::equal(setChildrenCheck.begin(), setChildrenCheck.end(), setChildrenStored.begin(), comp));531TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass532CAmount txfee = 0;533assert(!tx.IsCoinBase());534assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee));535for (const auto& input: tx.vin) mempoolDuplicate.SpendCoin(input.prevout);536AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max());537}538for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) {539indexed_transaction_set::const_iterator it2 = it->second;540assert(it2 != mapTx.end());541}543++diagram_iter;544assert(diagram_iter == diagram.cend());546assert(totalTxSize == checkTotal);547assert(m_total_fee == check_total_fee);548assert(diagram.back().fee == check_total_modified_fee);549assert(diagram.back().size == check_total_adjusted_weight);550assert(innerUsage == cachedInnerUsage);551}553std::vector<CTxMemPool::txiter> CTxMemPool::ExtractBestByMiningScoreWithTopology(std::vector<Wtxid>& wtxids, size_t n_to_sort) const554{555/* This function takes a vector of `wtxids`, and returns the556* best mempool entries corresponding to those `wtxids` (by mining557* score/topology). It updates the input `wtxids` so that multiple558* calls with the same vector will drain that vector to empty.559*560* It operates under the following constraints:561* - wtxids that do not correspond to a mempool entry are dropped562* - the return vector contains no duplicates, either with itself563* or with the updated `wtxids` input.564* - the return vector will have `n_to_sort` entries (or `wtxids`565will become empty).566* - the `wtxids` vector will be reduced by at least `n_to_sort`567* entries (or will become empty).568*/570auto cmp = [&](const auto& a, const auto& b) EXCLUSIVE_LOCKS_REQUIRED(cs) noexcept { return m_txgraph->CompareMainOrder(*a, *b) < 0; };572std::vector<txiter> res;574n_to_sort = std::min(wtxids.size(), n_to_sort);575if (n_to_sort > 0) {576res.reserve(wtxids.size());577std::sort(wtxids.begin(), wtxids.end());578for (auto it = wtxids.begin(); it != wtxids.end(); ++it) {579// skip duplicates580auto itnext = it + 1;581if (itnext != wtxids.end() && *it == *itnext) continue;583if (auto i{GetIter(*it)}; i.has_value()) {584res.push_back(i.value());585}586}587wtxids.clear();589if (!res.empty()) {590auto begin = res.begin();591auto end = res.end();592auto middle = end;593if (n_to_sort >= res.size()) {594// use regular sort when sorting everything595std::sort(begin, end, cmp);596} else {597middle = begin + n_to_sort;598std::partial_sort(begin, middle, end, cmp);599}600auto it = middle;601while (it != end) {602wtxids.push_back((*it)->GetTx().GetWitnessHash());603++it;604}605res.erase(middle, end);606}607}608return res;609}611std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedScoreWithTopology() const612{613std::vector<indexed_transaction_set::const_iterator> iters;614AssertLockHeld(cs);616iters.reserve(mapTx.size());618for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) {619iters.push_back(mi);620}621std::sort(iters.begin(), iters.end(), [this](const auto& a, const auto& b) EXCLUSIVE_LOCKS_REQUIRED(cs) noexcept {622return m_txgraph->CompareMainOrder(*a, *b) < 0;623});624return iters;625}627std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const628{629AssertLockHeld(cs);631std::vector<CTxMemPoolEntryRef> ret;632ret.reserve(mapTx.size());633for (const auto& it : GetSortedScoreWithTopology()) {634ret.emplace_back(*it);635}636return ret;637}639std::vector<TxMempoolInfo> CTxMemPool::infoAll() const640{641LOCK(cs);642auto iters = GetSortedScoreWithTopology();644std::vector<TxMempoolInfo> ret;645ret.reserve(mapTx.size());646for (auto it : iters) {647ret.push_back(GetInfo(it));648}650return ret;651}653const CTxMemPoolEntry* CTxMemPool::GetEntry(const Txid& txid) const654{655AssertLockHeld(cs);656const auto i = mapTx.find(txid);657return i == mapTx.end() ? nullptr : &(*i);658}660CTransactionRef CTxMemPool::get(const Txid& hash) const661{662LOCK(cs);663indexed_transaction_set::const_iterator i = mapTx.find(hash);664if (i == mapTx.end())665return nullptr;666return i->GetSharedTx();667}669CTransactionRef CTxMemPool::get(const Wtxid& hash) const670{671LOCK(cs);672const auto& wtxid_map{mapTx.get<index_by_wtxid>()};673const auto it{wtxid_map.find(hash)};674if (it == wtxid_map.end()) return nullptr;675return it->GetSharedTx();676}678void CTxMemPool::PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelta)679{680{681LOCK(cs);682CAmount &delta = mapDeltas[hash];683delta = SaturatingAdd(delta, nFeeDelta);684txiter it = mapTx.find(hash);685if (it != mapTx.end()) {686// PrioritiseTransaction calls stack on previous ones. Set the new687// transaction fee to be current modified fee + feedelta.688it->UpdateModifiedFee(nFeeDelta);689m_txgraph->SetTransactionFee(*it, it->GetModifiedFee());690++nTransactionsUpdated;691}692if (delta == 0) {693mapDeltas.erase(hash);694LogInfo("PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.ToString(), it == mapTx.end() ? "not " : "");695} else {696LogInfo("PrioritiseTransaction: %s (%sin mempool) fee += %s, new delta=%s\n",697hash.ToString(),698it == mapTx.end() ? "not " : "",699FormatMoney(nFeeDelta),700FormatMoney(delta));701}702}703}705void CTxMemPool::ApplyDelta(const Txid& hash, CAmount &nFeeDelta) const706{707AssertLockHeld(cs);708std::map<Txid, CAmount>::const_iterator pos = mapDeltas.find(hash);709if (pos == mapDeltas.end())710return;711const CAmount &delta = pos->second;712nFeeDelta += delta;713}715void CTxMemPool::ClearPrioritisation(const Txid& hash)716{717AssertLockHeld(cs);718mapDeltas.erase(hash);719}721std::vector<CTxMemPool::delta_info> CTxMemPool::GetPrioritisedTransactions() const722{723AssertLockNotHeld(cs);724LOCK(cs);725std::vector<delta_info> result;726result.reserve(mapDeltas.size());727for (const auto& [txid, delta] : mapDeltas) {728const auto iter{mapTx.find(txid)};729const bool in_mempool{iter != mapTx.end()};730std::optional<CAmount> modified_fee;731if (in_mempool) modified_fee = iter->GetModifiedFee();732result.emplace_back(delta_info{in_mempool, delta, modified_fee, txid});733}734return result;735}737const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const738{739const auto it = mapNextTx.find(prevout);740return it == mapNextTx.end() ? nullptr : &(it->second->GetTx());741}743std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Txid& txid) const744{745AssertLockHeld(cs);746auto it = mapTx.find(txid);747return it != mapTx.end() ? std::make_optional(it) : std::nullopt;748}750std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Wtxid& wtxid) const