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.contains(txiter));
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.contains(txid))) {
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.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();}));
241 [&](
const auto& txid){ return !m_entries_by_txid.contains(txid); }));
247 uint32_t sequence_num{0};
255 const auto ancestor_package_size = (*best_iter)->second.GetSizeWithAncestors();
256 const auto ancestor_package_fee = (*best_iter)->second.GetModFeesWithAncestors();
258 if (target_feerate.has_value() &&
259 ancestor_package_fee < target_feerate->GetFee(ancestor_package_size)) {
265 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
267 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
268 to_process.insert(*best_iter);
269 while (!to_process.empty()) {
270 auto iter = to_process.begin();
271 Assume(iter != to_process.end());
272 ancestors.insert(*iter);
273 for (
const auto& input : (*iter)->second.GetTx().vin) {
275 if (!ancestors.contains(parent_it)) {
276 to_process.insert(parent_it);
280 to_process.erase(iter);
284 for (
const auto& ancestor : ancestors) {
291 if (!target_feerate.has_value()) {
321 for (
const auto& outpoint : it->second) {
376 Assume(target_feerate.
GetFee(it->second.GetSizeWithAncestors()) > std::min(it->second.GetModifiedFee(), it->second.GetModFeesWithAncestors()));
377 CAmount bump_fee_with_ancestors = target_feerate.
GetFee(it->second.GetSizeWithAncestors()) - it->second.GetModFeesWithAncestors();
378 CAmount bump_fee_individual = target_feerate.
GetFee(it->second.GetTxSize()) - it->second.GetModifiedFee();
379 const CAmount bump_fee{std::max(bump_fee_with_ancestors, bump_fee_individual)};
381 for (
const auto& outpoint : outpoints) {
396 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
397 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
404 to_process.insert(iter);
405 ancestors.insert(iter);
408 std::set<Txid> has_been_processed;
409 while (!to_process.empty()) {
410 auto iter = to_process.begin();
412 for (
const auto& input : tx.
vin) {
414 if (!has_been_processed.contains(input.prevout.hash)) {
415 to_process.insert(parent_it);
417 ancestors.insert(parent_it);
420 has_been_processed.insert(tx.
GetHash());
421 to_process.erase(iter);
423 const auto ancestor_package_size = std::accumulate(ancestors.cbegin(), ancestors.cend(), int64_t{0},
424 [](int64_t
sum,
const auto it) {return sum + it->second.GetTxSize();});
425 const auto ancestor_package_fee = std::accumulate(ancestors.cbegin(), ancestors.cend(),
CAmount{0},
426 [](
CAmount sum,
const auto it) {return sum + it->second.GetModifiedFee();});
427 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.
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