Repository: bitcoin/bitcoin
File: src/node/mini_miner.cpp (C++)

Code before:
            } else {
                descendants.emplace_back(desc_it);
            }
        }
        m_descendant_set_by_txid.emplace(txid, descendants);
    }
    Assume(m_to_be_replaced.empty());
    Assume(m_requested_outpoints_by_txid.empty());
    Assume(m_bump_fees.empty());
    Assume(m_inclusion_order.empty());
    SanityCheck();
}

// Compare by min(ancestor feerate, individual feerate), then iterator
//
// Under the ancestor-based mining approach, high-feerate children can pay for parents, but high-feerate
// parents do not incentive inclusion of their children. Therefore the mining algorithm only considers
// transactions for inclusion on basis of the minimum of their own feerate or their ancestor feerate.
struct AncestorFeerateComparator
{
    template<typename I>
    bool operator()(const I& a, const I& b) const {
        auto min_feerate = [](const MiniMinerMempoolEntry& e) -> CFeeRate {
            const CAmount ancestor_fee{e.GetModFeesWithAncestors()};
            const int64_t ancestor_size{e.GetSizeWithAncestors()};
            const CAmount tx_fee{e.GetModifiedFee()};
            const int64_t tx_size{e.GetTxSize()};
            // Comparing ancestor feerate with individual feerate:
            //     ancestor_fee / ancestor_size <= tx_fee / tx_size
            // Avoid division and possible loss of precision by
            // multiplying both sides by the sizes:
            return ancestor_fee * tx_size < tx_fee * ancestor_size ?
                       CFeeRate(ancestor_fee, ancestor_size) :
                       CFeeRate(tx_fee, tx_size);
        };
        CFeeRate a_feerate{min_feerate(a->second)};
        CFeeRate b_feerate{min_feerate(b->second)};
        if (a_feerate != b_feerate) {
            return a_feerate > b_feerate;
        }
        // Use txid as tiebreaker for stable sorting
        return a->first < b->first;
    }
};

void MiniMiner::DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors)
{
    Assume(ancestors.size() >= 1);
    // "Mine" all transactions in this ancestor set.
    for (auto& anc : ancestors) {
        Assume(m_in_block.count(anc->first) == 0);

Review comment (suggestion):
Nit: could be `return std::min(self_feerate, ancestor_feerate);`

Code after:
            } else {
                descendants.emplace_back(desc_it);
            }
        }
        m_descendant_set_by_txid.emplace(txid, descendants);
    }
    Assume(m_to_be_replaced.empty());
    Assume(m_requested_outpoints_by_txid.empty());
    Assume(m_bump_fees.empty());
    Assume(m_inclusion_order.empty());
    SanityCheck();
}

// Compare by min(ancestor feerate, individual feerate), then txid
//
// Under the ancestor-based mining approach, high-feerate children can pay for parents, but high-feerate
// parents do not incentive inclusion of their children. Therefore the mining algorithm only considers
// transactions for inclusion on basis of the minimum of their own feerate or their ancestor feerate.
struct AncestorFeerateComparator
{
    template<typename I>
    bool operator()(const I& a, const I& b) const {
        auto min_feerate = [](const MiniMinerMempoolEntry& e) -> FeeFrac {
            FeeFrac self_feerate(e.GetModifiedFee(), e.GetTxSize());
            FeeFrac ancestor_feerate(e.GetModFeesWithAncestors(), e.GetSizeWithAncestors());
            return std::min(ancestor_feerate, self_feerate);
        };
        FeeFrac a_feerate{min_feerate(a->second)};
        FeeFrac b_feerate{min_feerate(b->second)};
        if (a_feerate != b_feerate) {
            return a_feerate > b_feerate;
        }
        // Use txid as tiebreaker for stable sorting
        return a->first < b->first;
    }
};

void MiniMiner::DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors)
{
    Assume(ancestors.size() >= 1);
    // "Mine" all transactions in this ancestor set.
    for (auto& anc : ancestors) {
        Assume(m_in_block.count(anc->first) == 0);
        m_in_block.insert(anc->first);
        m_total_fees += anc->second.GetModifiedFee();
        m_total_vsize += anc->second.GetTxSize();
        auto it = m_descendant_set_by_txid.find(anc->first);
        // Each entry’s descendant set includes itself
        Assume(it != m_descendant_set_by_txid.end());
        for (auto& descendant : it->second) {
            // If these fail, we must be double-deducting.