7#include <boost/multi_index/detail/hash_index_iterator.hpp>
8#include <boost/operators.hpp>
29 for (
const auto& outpoint : outpoints) {
54 for (
const auto& desc_txiter : descendants) {
64 std::vector<uint256> txids_needed;
67 txids_needed.push_back(txid);
70 if (cluster.empty()) {
78 for (
const auto& txiter : cluster) {
83 txiter->GetSizeWithAncestors(),
84 txiter->GetModifiedFee(),
85 txiter->GetModFeesWithAncestors()});
92 for (
const auto& outpoint : outpoints_it->second) {
101 for (
const auto& txiter : cluster) {
102 const auto& txid = txiter->GetTx().GetHash();
105 std::vector<MockEntryMap::iterator> cached_descendants;
109 Assume(descendants.count(txiter) > 0);
110 for (
const auto& desc_txiter : descendants) {
111 const auto txid_desc = desc_txiter->GetTx().GetHash();
115 if (remove)
Assume(remove_desc);
117 if (!remove && !remove_desc) {
118 cached_descendants.push_back(desc_it);
122 Assume(cached_descendants.empty());
136 const std::map<
Txid, std::set<Txid>>& descendant_caches)
138 for (
const auto& entry : manual_entries) {
139 const auto& txid = entry.GetTx().GetHash();
141 if (!
Assume(descendant_caches.count(txid) > 0)) {
151 for (
const auto& [txid, desc_txids] : descendant_caches) {
153 if (!
Assume(!desc_txids.empty())) {
157 std::vector<MockEntryMap::iterator> descendants;
158 for (
const auto& desc_txid : desc_txids) {
165 descendants.emplace_back(desc_it);
187 FeeFrac self_feerate(e.GetModifiedFee(), e.GetTxSize());
188 FeeFrac ancestor_feerate(e.GetModFeesWithAncestors(), e.GetSizeWithAncestors());
189 return std::min(ancestor_feerate, self_feerate);
191 FeeFrac a_feerate{min_feerate(a->second)};
192 FeeFrac b_feerate{min_feerate(b->second)};
193 if (a_feerate != b_feerate) {
194 return a_feerate > b_feerate;
197 return a->first < b->first;
203 Assume(ancestors.size() >= 1);
205 for (
auto& anc : ancestors) {
213 for (
auto& descendant : it->second) {
215 Assume(descendant->second.GetModFeesWithAncestors() >= anc->second.GetModifiedFee());
216 Assume(descendant->second.GetSizeWithAncestors() >= anc->second.GetTxSize());
217 descendant->second.UpdateAncestorState(-anc->second.GetTxSize(), -anc->second.GetModifiedFee());
221 for (
const auto& anc : ancestors) {
225 Assume(anc->second.GetModFeesWithAncestors() == 0);
226 Assume(anc->second.GetSizeWithAncestors() == 0);
241 return entry->second.GetSizeWithAncestors() >= entry->second.GetTxSize() &&
242 entry->second.GetModFeesWithAncestors() >= entry->second.GetModifiedFee();}));
245 [&](
const auto& txid){return m_entries_by_txid.find(txid) == m_entries_by_txid.end();}));
251 uint32_t sequence_num{0};
259 const auto ancestor_package_size = (*best_iter)->second.GetSizeWithAncestors();
260 const auto ancestor_package_fee = (*best_iter)->second.GetModFeesWithAncestors();
262 if (target_feerate.has_value() &&
263 ancestor_package_fee < target_feerate->GetFee(ancestor_package_size)) {
269 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
271 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
272 to_process.insert(*best_iter);
273 while (!to_process.empty()) {
274 auto iter = to_process.begin();
275 Assume(iter != to_process.end());
276 ancestors.insert(*iter);
277 for (
const auto& input : (*iter)->second.GetTx().vin) {
279 if (ancestors.count(parent_it) == 0) {
280 to_process.insert(parent_it);
284 to_process.erase(iter);
288 for (
const auto& ancestor : ancestors) {
295 if (!target_feerate.has_value()) {
325 for (
const auto& outpoint : it->second) {
380 Assume(target_feerate.
GetFee(it->second.GetSizeWithAncestors()) > std::min(it->second.GetModifiedFee(), it->second.GetModFeesWithAncestors()));
381 CAmount bump_fee_with_ancestors = target_feerate.
GetFee(it->second.GetSizeWithAncestors()) - it->second.GetModFeesWithAncestors();
382 CAmount bump_fee_individual = target_feerate.
GetFee(it->second.GetTxSize()) - it->second.GetModifiedFee();
383 const CAmount bump_fee{std::max(bump_fee_with_ancestors, bump_fee_individual)};
385 for (
const auto& outpoint : outpoints) {
400 std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
401 std::set<MockEntryMap::iterator, IteratorComparator> to_process;
408 to_process.insert(iter);
409 ancestors.insert(iter);
412 std::set<uint256> has_been_processed;
413 while (!to_process.empty()) {
414 auto iter = to_process.begin();
416 for (
const auto& input : tx.
vin) {
418 if (!has_been_processed.count(input.prevout.hash)) {
419 to_process.insert(parent_it);
421 ancestors.insert(parent_it);
424 has_been_processed.insert(tx.
GetHash());
425 to_process.erase(iter);
427 const auto ancestor_package_size = std::accumulate(ancestors.cbegin(), ancestors.cend(), int64_t{0},
428 [](int64_t
sum,
const auto it) {return sum + it->second.GetTxSize();});
429 const auto ancestor_package_fee = std::accumulate(ancestors.cbegin(), ancestors.cend(),
CAmount{0},
430 [](
CAmount sum,
const auto it) {return sum + it->second.GetModifiedFee();});
431 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 kilovirtualbyte: CAmount / kvB.
CAmount GetFee(uint32_t num_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 ...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
std::optional< txiter > GetIter(const uint256 &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
std::vector< txiter > GatherClusters(const std::vector< uint256 > &txids) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Collect the entire cluster of connected transactions for each transaction in txids.
std::set< txiter, CompareIteratorByHash > setEntries
bool exists(const GenTxid >xid) const
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.
static GenTxid Txid(const uint256 &hash)
std::map< uint256, std::vector< MockEntryMap::iterator > > m_descendant_set_by_txid
Map of txid to its descendants.
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::map< uint256, std::vector< COutPoint > > m_requested_outpoints_by_txid
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::set< uint256 > m_in_block
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.
std::map< uint256, MiniMinerMempoolEntry > m_entries_by_txid
Main data structure holding the entries, can be indexed by txid.
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::set< uint256 > m_to_be_replaced
std::map< COutPoint, CAmount > m_bump_fees
bool m_ready_to_calculate
void BuildMockTemplate(std::optional< CFeeRate > target_feerate)
Build a block template until the target feerate is hit.
static transaction_identifier FromUint256(const uint256 &id)
Data structure storing a fee and size, ordered by increasing fee/size.
bool operator()(const I &a, const I &b) const
bilingual_str _(ConstevalStringLiteral str)
Translation function.