mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-18 18:04:44 +02:00
Merge bitcoin/bitcoin#34669: feefrac: drop comparison and operator{<<,>>} for sorted wrappers
1aa78cdab6clusterlin: adopt STL ranges algorithms (refactor) (Pieter Wuille)747da25360feefrac: drop comparison and operator{<<,>>} for sorted wrappers (Pieter Wuille) Pull request description: Instead of having an unintuitive but strong implicit sort order on `FeeFrac` (first increasing feerate, then decreasing size), and separate overloaded `operator<<` and `operator>>` that implement a weak ordering that only looks at feerate, replace these with explicit wrapper classes which make the behavior more explicit (`ByRatio` and `ByRatioNegSize`). This allows for things like `ByRatio{a} <= ByRatio{b}`, instead of the earlier `!(a >> b)`. It also supports usage inside `std::min`/`std::max`/`std::less`, and `std::greater`, so one can use: * `std::max<ByRatioNegSize<FeeFrac>>(a, b)` to get the highest-feerate `FeeFrac`, tie-breaking by smallest size. * `std::ranges::sort(v, std::greater<ByRatioNegSize<FeeFrac>>{});` to sort a vector that way. Suggested in https://github.com/bitcoin/bitcoin/pull/34257#discussion_r2780475893. ACKs for top commit: achow101: ACK1aa78cdab6sedited: ACK1aa78cdab6ajtowns: ACK1aa78cdab6Tree-SHA512: d76657b15f6d745e5ca01c67fd5b101fdc418e6301646d14e575b6564bfa2fe0eb40a95a7ff95a4420624ef6b67224d35e4713aa5bbc0d293e08fe44c0cc6db0
This commit is contained in:
@@ -295,7 +295,7 @@ void BlockAssembler::addChunks()
|
||||
|
||||
while (selected_transactions.size() > 0) {
|
||||
// Check to see if min fee rate is still respected.
|
||||
if (chunk_feerate_vsize << m_options.blockMinFeeRate.GetFeePerVSize()) {
|
||||
if (ByRatio{chunk_feerate_vsize} < ByRatio{m_options.blockMinFeeRate.GetFeePerVSize()}) {
|
||||
// Everything else we might consider has a lower feerate
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,12 +184,12 @@ struct AncestorFeerateComparator
|
||||
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);
|
||||
return std::min<ByRatioNegSize<FeeFrac>>(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;
|
||||
return ByRatioNegSize{a_feerate} > ByRatioNegSize{b_feerate};
|
||||
}
|
||||
// Use txid as tiebreaker for stable sorting
|
||||
return a->first < b->first;
|
||||
|
||||
@@ -165,7 +165,7 @@ class TxOrphanageImpl final : public TxOrphanage {
|
||||
assert(max_peer_memory > 0);
|
||||
const FeeFrac latency_score(m_total_latency_score, max_peer_latency_score);
|
||||
const FeeFrac mem_score(m_total_usage, max_peer_memory);
|
||||
return std::max<FeeFrac>(latency_score, mem_score);
|
||||
return std::max<ByRatioNegSize<FeeFrac>>(latency_score, mem_score);
|
||||
}
|
||||
};
|
||||
/** Store per-peer statistics. Used to determine each peer's DoS score. The size of this map is used to determine the
|
||||
@@ -458,12 +458,18 @@ void TxOrphanageImpl::LimitOrphans()
|
||||
for (const auto& [nodeid, entry] : m_peer_orphanage_info) {
|
||||
// Performance optimization: only consider peers with a DoS score > 1.
|
||||
const auto dos_score = entry.GetDosScore(max_lat, max_mem);
|
||||
if (dos_score >> FeeFrac{1, 1}) {
|
||||
if (ByRatio{dos_score} > ByRatio{FeeFrac{1, 1}}) {
|
||||
heap_peer_dos.emplace_back(nodeid, dos_score);
|
||||
}
|
||||
}
|
||||
static constexpr auto compare_score = [](const auto& left, const auto& right) {
|
||||
if (left.second != right.second) return left.second < right.second;
|
||||
if (left.second != right.second) {
|
||||
// Note: if ratios are the same, this tiebreaks by denominator. In practice, since the
|
||||
// latency denominator (number of announcements and inputs) is always lower, this means
|
||||
// that a peer with only high latency scores will be targeted before a peer using a lot
|
||||
// of memory, even if they have the same ratios.
|
||||
return ByRatioNegSize{left.second} < ByRatioNegSize{right.second};
|
||||
}
|
||||
// Tiebreak by considering the more recent peer (higher NodeId) to be worse.
|
||||
return left.first < right.first;
|
||||
};
|
||||
@@ -473,9 +479,6 @@ void TxOrphanageImpl::LimitOrphans()
|
||||
// This outer loop finds the peer with the highest DoS score, which is a fraction of memory and latency scores
|
||||
// over the respective allowances. We continue until the orphanage is within global limits. That means some peers
|
||||
// might still have a DoS score > 1 at the end.
|
||||
// Note: if ratios are the same, FeeFrac tiebreaks by denominator. In practice, since the latency denominator (number of
|
||||
// announcements and inputs) is always lower, this means that a peer with only high latency scores will be targeted
|
||||
// before a peer using a lot of memory, even if they have the same ratios.
|
||||
do {
|
||||
Assume(!heap_peer_dos.empty());
|
||||
// This is a max-heap, so the worst peer is at the front. pop_heap()
|
||||
@@ -485,7 +488,7 @@ void TxOrphanageImpl::LimitOrphans()
|
||||
heap_peer_dos.pop_back();
|
||||
|
||||
// If needs trim, then at least one peer has a DoS score higher than 1.
|
||||
Assume(dos_score >> (FeeFrac{1, 1}));
|
||||
Assume(ByRatio{dos_score} > ByRatio{FeeFrac(1, 1)});
|
||||
|
||||
auto it_worst_peer = m_peer_orphanage_info.find(worst_peer);
|
||||
|
||||
@@ -507,7 +510,8 @@ void TxOrphanageImpl::LimitOrphans()
|
||||
|
||||
// If we erased the last orphan from this peer, it_worst_peer will be invalidated.
|
||||
it_worst_peer = m_peer_orphanage_info.find(worst_peer);
|
||||
if (it_worst_peer == m_peer_orphanage_info.end() || it_worst_peer->second.GetDosScore(max_lat, max_mem) <= dos_threshold) break;
|
||||
if (it_worst_peer == m_peer_orphanage_info.end() ||
|
||||
ByRatioNegSize{it_worst_peer->second.GetDosScore(max_lat, max_mem)} <= ByRatioNegSize{dos_threshold}) break;
|
||||
}
|
||||
LogDebug(BCLog::TXPACKAGES, "peer=%d orphanage overflow, removed %u of %u announcements\n", worst_peer, num_erased_this_round, starting_num_ann);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user