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) {
80 txiter->GetSizeWithAncestors(),
81 txiter->GetModifiedFee(),
82 txiter->GetModFeesWithAncestors()});
89 for (
const auto& outpoint : outpoints_it->second) {
98 for (
const auto& txiter : cluster) {
99 const auto& txid = txiter->GetTx().GetHash();
102 std::vector<MockEntryMap::iterator> cached_descendants;
106 Assume(descendants.count(txiter) > 0);
107 for (
const auto& desc_txiter : descendants) {
108 const auto txid_desc = desc_txiter->GetTx().GetHash();
112 if (remove)
Assume(remove_desc);
114 if (!remove && !remove_desc) {
115 cached_descendants.push_back(desc_it);
119 Assume(cached_descendants.empty());
133 const std::map<
Txid, std::set<Txid>>& descendant_caches)
135 for (
const auto& entry : manual_entries) {
136 const auto& txid = entry.GetTx().GetHash();
138 if (!
Assume(descendant_caches.count(txid) > 0)) {
148 for (
const auto& [txid, desc_txids] : descendant_caches) {
150 if (!
Assume(!desc_txids.empty())) {
154 std::vector<MockEntryMap::iterator> descendants;
155 for (
const auto& desc_txid : desc_txids) {
162 descendants.emplace_back(desc_it);
184 FeeFrac self_feerate(e.GetModifiedFee(), e.GetTxSize());
185 FeeFrac ancestor_feerate(e.GetModFeesWithAncestors(), e.GetSizeWithAncestors());
186 return std::min(ancestor_feerate, self_feerate);
188 FeeFrac a_feerate{min_feerate(a->second)};
189 FeeFrac b_feerate{min_feerate(b->second)};
190 if (a_feerate != b_feerate) {
191 return a_feerate > b_feerate;
194 return a->first < b->first;
200 Assume(ancestors.size() >= 1);
202 for (
auto& anc : ancestors) {
210 for (
auto& descendant : it->second) {
212 Assume(descendant->second.GetModFeesWithAncestors() >= anc->second.GetModifiedFee());
213 Assume(descendant->second.GetSizeWithAncestors() >= anc->second.GetTxSize());
214 descendant->second.UpdateAncestorState(-anc->second.GetTxSize(), -anc->second.GetModifiedFee());
218 for (
const auto& anc : ancestors) {
222 Assume(anc->second.GetModFeesWithAncestors() == 0);
223 Assume(anc->second.GetSizeWithAncestors() == 0);
238 return entry->second.GetSizeWithAncestors() >= entry->second.GetTxSize() &&
239 entry->second.GetModFeesWithAncestors() >= entry->second.GetModifiedFee();}));
242 [&](
const auto& txid){return m_entries_by_txid.find(txid) == m_entries_by_txid.end();}));
248 uint32_t sequence_num{0};
256 const auto ancestor_package_size = (*best_iter)->second.GetSizeWithAncestors();
257 const auto ancestor_package_fee = (*best_iter)->second.GetModFeesWithAncestors();
259 if (target_feerate.has_value() &&
260 ancestor_package_fee < target_feerate->GetFee(ancestor_package_size)) {
266 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
268 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
269 to_process.insert(*best_iter);
270 while (!to_process.empty()) {
271 auto iter = to_process.begin();
272 Assume(iter != to_process.end());
273 ancestors.insert(*iter);
274 for (
const auto& input : (*iter)->second.GetTx().vin) {
276 if (ancestors.count(parent_it) == 0) {
277 to_process.insert(parent_it);
281 to_process.erase(iter);
285 for (
const auto& ancestor : ancestors) {
292 if (!target_feerate.has_value()) {
322 for (
const auto& outpoint : it->second) {
377 Assume(target_feerate.
GetFee(it->second.GetSizeWithAncestors()) > std::min(it->second.GetModifiedFee(), it->second.GetModFeesWithAncestors()));
378 CAmount bump_fee_with_ancestors = target_feerate.
GetFee(it->second.GetSizeWithAncestors()) - it->second.GetModFeesWithAncestors();
379 CAmount bump_fee_individual = target_feerate.
GetFee(it->second.GetTxSize()) - it->second.GetModifiedFee();
380 const CAmount bump_fee{std::max(bump_fee_with_ancestors, bump_fee_individual)};
382 for (
const auto& outpoint : outpoints) {
397 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
398 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
405 to_process.insert(iter);
406 ancestors.insert(iter);
409 std::set<Txid> has_been_processed;
410 while (!to_process.empty()) {
411 auto iter = to_process.begin();
413 for (
const auto& input : tx.
vin) {
415 if (!has_been_processed.count(input.prevout.hash)) {
416 to_process.insert(parent_it);
418 ancestors.insert(parent_it);
421 has_been_processed.insert(tx.
GetHash());
422 to_process.erase(iter);
424 const auto ancestor_package_size = std::accumulate(ancestors.cbegin(), ancestors.cend(), int64_t{0},
425 [](int64_t
sum,
const auto it) {return sum + it->second.GetTxSize();});
426 const auto ancestor_package_fee = std::accumulate(ancestors.cbegin(), ancestors.cend(),
CAmount{0},
427 [](
CAmount sum,
const auto it) {return sum + it->second.GetModifiedFee();});
428 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 hash.
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