7#include <boost/multi_index/detail/hash_index_iterator.hpp>
8#include <boost/operators.hpp>
30 for (
const auto& outpoint : outpoints) {
31 if (!mempool.
exists(outpoint.hash)) {
55 for (
const auto& desc_txiter : descendants) {
66 const auto cluster = mempool.
GatherClusters({txids_needed.begin(), txids_needed.end()});
67 if (cluster.empty()) {
75 for (
const auto& txiter : cluster) {
81 int64_t(ancestor_size),
82 txiter->GetModifiedFee(),
90 for (
const auto& outpoint : outpoints_it->second) {
99 for (
const auto& txiter : cluster) {
100 const auto& txid = txiter->GetTx().GetHash();
103 std::vector<MockEntryMap::iterator> cached_descendants;
107 Assume(descendants.count(txiter) > 0);
108 for (
const auto& desc_txiter : descendants) {
109 const auto txid_desc = desc_txiter->GetTx().GetHash();
113 if (remove)
Assume(remove_desc);
115 if (!remove && !remove_desc) {
116 cached_descendants.push_back(desc_it);
120 Assume(cached_descendants.empty());
134 const std::map<
Txid, std::set<Txid>>& descendant_caches)
136 for (
const auto& entry : manual_entries) {
137 const auto& txid = entry.GetTx().GetHash();
139 if (!
Assume(descendant_caches.count(txid) > 0)) {
149 for (
const auto& [txid, desc_txids] : descendant_caches) {
151 if (!
Assume(!desc_txids.empty())) {
155 std::vector<MockEntryMap::iterator> descendants;
156 for (
const auto& desc_txid : desc_txids) {
163 descendants.emplace_back(desc_it);
185 FeeFrac self_feerate(e.GetModifiedFee(), e.GetTxSize());
186 FeeFrac ancestor_feerate(e.GetModFeesWithAncestors(), e.GetSizeWithAncestors());
187 return std::min(ancestor_feerate, self_feerate);
189 FeeFrac a_feerate{min_feerate(a->second)};
190 FeeFrac b_feerate{min_feerate(b->second)};
191 if (a_feerate != b_feerate) {
192 return a_feerate > b_feerate;
195 return a->first < b->first;
201 Assume(ancestors.size() >= 1);
203 for (
auto& anc : ancestors) {
211 for (
auto& descendant : it->second) {
213 Assume(descendant->second.GetModFeesWithAncestors() >= anc->second.GetModifiedFee());
214 Assume(descendant->second.GetSizeWithAncestors() >= anc->second.GetTxSize());
215 descendant->second.UpdateAncestorState(-anc->second.GetTxSize(), -anc->second.GetModifiedFee());
219 for (
const auto& anc : ancestors) {
223 Assume(anc->second.GetModFeesWithAncestors() == 0);
224 Assume(anc->second.GetSizeWithAncestors() == 0);
239 return entry->second.GetSizeWithAncestors() >= entry->second.GetTxSize() &&
240 entry->second.GetModFeesWithAncestors() >= entry->second.GetModifiedFee();}));
243 [&](
const auto& txid){return m_entries_by_txid.find(txid) == m_entries_by_txid.end();}));
249 uint32_t sequence_num{0};
257 const auto ancestor_package_size = (*best_iter)->second.GetSizeWithAncestors();
258 const auto ancestor_package_fee = (*best_iter)->second.GetModFeesWithAncestors();
260 if (target_feerate.has_value() &&
261 ancestor_package_fee < target_feerate->GetFee(ancestor_package_size)) {
267 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
269 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
270 to_process.insert(*best_iter);
271 while (!to_process.empty()) {
272 auto iter = to_process.begin();
273 Assume(iter != to_process.end());
274 ancestors.insert(*iter);
275 for (
const auto& input : (*iter)->second.GetTx().vin) {
277 if (ancestors.count(parent_it) == 0) {
278 to_process.insert(parent_it);
282 to_process.erase(iter);
286 for (
const auto& ancestor : ancestors) {
293 if (!target_feerate.has_value()) {
323 for (
const auto& outpoint : it->second) {
378 Assume(target_feerate.
GetFee(it->second.GetSizeWithAncestors()) > std::min(it->second.GetModifiedFee(), it->second.GetModFeesWithAncestors()));
379 CAmount bump_fee_with_ancestors = target_feerate.
GetFee(it->second.GetSizeWithAncestors()) - it->second.GetModFeesWithAncestors();
380 CAmount bump_fee_individual = target_feerate.
GetFee(it->second.GetTxSize()) - it->second.GetModifiedFee();
381 const CAmount bump_fee{std::max(bump_fee_with_ancestors, bump_fee_individual)};
383 for (
const auto& outpoint : outpoints) {
398 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
399 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
406 to_process.insert(iter);
407 ancestors.insert(iter);
410 std::set<Txid> has_been_processed;
411 while (!to_process.empty()) {
412 auto iter = to_process.begin();
414 for (
const auto& input : tx.
vin) {
416 if (!has_been_processed.count(input.prevout.hash)) {
417 to_process.insert(parent_it);
419 ancestors.insert(parent_it);
422 has_been_processed.insert(tx.
GetHash());
423 to_process.erase(iter);
425 const auto ancestor_package_size = std::accumulate(ancestors.cbegin(), ancestors.cend(), int64_t{0},
426 [](int64_t
sum,
const auto it) {return sum + it->second.GetTxSize();});
427 const auto ancestor_package_fee = std::accumulate(ancestors.cbegin(), ancestors.cend(),
CAmount{0},
428 [](
CAmount sum,
const auto it) {return sum + it->second.GetModifiedFee();});
429 return target_feerate.
GetFee(ancestor_package_size) - ancestor_package_fee;
int64_t CAmount
Amount in satoshis (Can be negative)
#define Assume(val)
Assume is the identity function.
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
CAmount GetFee(int32_t virtual_bytes) const
Return the fee in satoshis for the given vsize in vbytes.
The basic transaction that is broadcasted on the network and contained in blocks.
const Txid & GetHash() const LIFETIMEBOUND
const std::vector< CTxIn > vin
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
std::optional< txiter > GetIter(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
bool exists(const Txid &txid) const
std::set< txiter, CompareIteratorByHash > setEntries
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.
const CTransaction * GetConflictTx(const COutPoint &prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Get the transaction in the pool that spends the same prevout.
void CalculateDescendants(txiter it, setEntries &setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Populate setDescendants with all in-mempool descendants of given transaction.
std::tuple< size_t, size_t, CAmount > CalculateAncestorData(const CTxMemPoolEntry &entry) const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::set< Txid > m_in_block
std::map< Txid, uint32_t > Linearize()
Construct a new block template with all of the transactions and calculate the order in which they are...
std::map< COutPoint, CAmount > CalculateBumpFees(const CFeeRate &target_feerate)
Construct a new block template and, for each outpoint corresponding to a transaction that did not mak...
std::optional< CAmount > CalculateTotalBumpFees(const CFeeRate &target_feerate)
Construct a new block template and, calculate the cost of bumping all transactions that did not make ...
std::map< Txid, MiniMinerMempoolEntry > m_entries_by_txid
Main data structure holding the entries, can be indexed by txid.
std::map< Txid, uint32_t > m_inclusion_order
void DeleteAncestorPackage(const std::set< MockEntryMap::iterator, IteratorComparator > &ancestors)
Consider this ancestor package "mined" so remove all these entries from our data structures.
void SanityCheck() const
Perform some checks.
std::vector< MockEntryMap::iterator > m_entries
Vector of entries, can be sorted by ancestor feerate.
MiniMiner(const CTxMemPool &mempool, const std::vector< COutPoint > &outpoints)
Constructor that takes a list of outpoints that may or may not belong to transactions in the mempool.
std::map< COutPoint, CAmount > m_bump_fees
std::map< Txid, std::vector< MockEntryMap::iterator > > m_descendant_set_by_txid
Map of txid to its descendants.
bool m_ready_to_calculate
std::set< Txid > m_to_be_replaced
std::map< Txid, std::vector< COutPoint > > m_requested_outpoints_by_txid
void BuildMockTemplate(std::optional< CFeeRate > target_feerate)
Build a block template until the target feerate is hit.
Data structure storing a fee and size, ordered by increasing fee/size.
bool operator()(const I &a, const I &b) const