mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
feefrac: drop comparison and operator{<<,>>} for sorted wrappers
Instead of having an unintuitive but total implicit sort order on
FeeFrac (first increasing feerate, then decreasing size), and separate
overloaded operator<< and operator>> for a weak ordering that only looks
at feerate, replace these with explicit wrapper classes which make the
behavior more explicit.
This allows for things like ByRatio{a} <= ByRatio{b}, instead of the
earlier !(a >> b). It also supports usage inside std::max and
std::greater, so one can use:
* std::max<ByRatioNegSize<FeeFrac>>(a, b)
* std::sort(v.begin(), v.end(), std::greater<ByRatioNegSize<FeeFrac>>{})
This commit is contained in:
committed by
Pieter Wuille
parent
3a8b4e89f6
commit
747da25360
@@ -126,7 +126,7 @@ public:
|
||||
// Add a queue entry with split excluded.
|
||||
queue.emplace_back(inc, und - m_depgraph.Descendants(split));
|
||||
// Update statistics to account for the candidate new_inc.
|
||||
if (new_inc.feerate > best.feerate) best = new_inc;
|
||||
if (ByRatioNegSize{new_inc.feerate} > ByRatioNegSize{best.feerate}) best = new_inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
x_shifted >>= 1;
|
||||
}
|
||||
SetInfo cur(m_depgraph, txn & m_todo);
|
||||
if (cur.feerate > best.feerate) best = cur;
|
||||
if (ByRatioNegSize{cur.feerate} > ByRatioNegSize{best.feerate}) best = cur;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
@@ -737,7 +737,7 @@ FUZZ_TARGET(clusterlin_chunking)
|
||||
|
||||
// Verify that chunk feerates are monotonically non-increasing.
|
||||
for (size_t i = 1; i < chunking.size(); ++i) {
|
||||
assert(!(chunking[i] >> chunking[i - 1]));
|
||||
assert(ByRatio{chunking[i]} <= ByRatio{chunking[i - 1]});
|
||||
}
|
||||
|
||||
// Naively recompute the chunks (each is the highest-feerate prefix of what remains).
|
||||
@@ -748,7 +748,7 @@ FUZZ_TARGET(clusterlin_chunking)
|
||||
for (DepGraphIndex idx : linearization) {
|
||||
if (todo[idx]) {
|
||||
accumulator.Set(depgraph, idx);
|
||||
if (best.feerate.IsEmpty() || accumulator.feerate >> best.feerate) {
|
||||
if (best.feerate.IsEmpty() || ByRatio{accumulator.feerate} > ByRatio{best.feerate}) {
|
||||
best = accumulator;
|
||||
}
|
||||
}
|
||||
@@ -825,7 +825,7 @@ FUZZ_TARGET(clusterlin_simple_finder)
|
||||
// Compare with a non-empty topological set read from the fuzz input (comparing with an
|
||||
// empty set is not interesting).
|
||||
auto read_topo = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||
assert(found.feerate >= depgraph.FeeRate(read_topo));
|
||||
assert(ByRatioNegSize{found.feerate} >= ByRatioNegSize{depgraph.FeeRate(read_topo)});
|
||||
}
|
||||
|
||||
// Find a non-empty topologically valid subset of transactions to remove from the graph.
|
||||
@@ -1110,9 +1110,9 @@ FUZZ_TARGET(clusterlin_linearize)
|
||||
// Check whether tx2 only depends on transactions that precede tx1.
|
||||
if ((depgraph.Ancestors(tx2) - done).Count() == 1) {
|
||||
// tx2 could take position pos1.
|
||||
// Verify that individual transaction feerate is decreasing (note that >=
|
||||
// tie-breaks by size).
|
||||
assert(depgraph.FeeRate(tx1) >= depgraph.FeeRate(tx2));
|
||||
// Verify that individual transaction feerate is decreasing (tie-breaking by
|
||||
// size).
|
||||
assert(ByRatioNegSize{depgraph.FeeRate(tx1)} >= ByRatioNegSize{depgraph.FeeRate(tx2)});
|
||||
// If feerate and size are equal, compare by DepGraphIndex.
|
||||
if (depgraph.FeeRate(tx1) == depgraph.FeeRate(tx2)) {
|
||||
assert(tx1 < tx2);
|
||||
@@ -1139,8 +1139,8 @@ FUZZ_TARGET(clusterlin_linearize)
|
||||
// Check whether chunk2 only depends on transactions that precede chunk1.
|
||||
if ((chunk2_ancestors - done).IsSubsetOf(chunk2.transactions)) {
|
||||
// chunk2 could take position chunk_num1.
|
||||
// Verify that chunk feerate is decreasing (note that >= tie-breaks by size).
|
||||
assert(chunk1.feerate >= chunk2.feerate);
|
||||
// Verify that chunk feerate is decreasing (tie-breaking by size).
|
||||
assert(ByRatioNegSize{chunk1.feerate} >= ByRatioNegSize{chunk2.feerate});
|
||||
// If feerate and size are equal, compare by maximum DepGraphIndex element.
|
||||
if (chunk1.feerate == chunk2.feerate) {
|
||||
assert(chunk1.transactions.Last() < chunk2.transactions.Last());
|
||||
|
||||
@@ -84,9 +84,9 @@ FUZZ_TARGET(feefrac)
|
||||
|
||||
// Feerate comparisons
|
||||
auto cmp_feerate = MulCompare(f1, s2, f2, s1);
|
||||
assert(FeeRateCompare(fr1, fr2) == cmp_feerate);
|
||||
assert((fr1 << fr2) == std::is_lt(cmp_feerate));
|
||||
assert((fr1 >> fr2) == std::is_gt(cmp_feerate));
|
||||
assert((ByRatio{fr1} <=> ByRatio{fr2}) == cmp_feerate);
|
||||
assert((ByRatio{fr1} < ByRatio{fr2}) == std::is_lt(cmp_feerate));
|
||||
assert((ByRatio{fr1} > ByRatio{fr2}) == std::is_gt(cmp_feerate));
|
||||
|
||||
// Compare with manual invocation of FeeFrac::Mul.
|
||||
auto cmp_mul = FeeFrac::Mul(f1, s2) <=> FeeFrac::Mul(f2, s1);
|
||||
@@ -98,13 +98,13 @@ FUZZ_TARGET(feefrac)
|
||||
|
||||
// Total order comparisons
|
||||
auto cmp_total = std::is_eq(cmp_feerate) ? (s2 <=> s1) : cmp_feerate;
|
||||
assert((fr1 <=> fr2) == cmp_total);
|
||||
assert((fr1 < fr2) == std::is_lt(cmp_total));
|
||||
assert((fr1 > fr2) == std::is_gt(cmp_total));
|
||||
assert((fr1 <= fr2) == std::is_lteq(cmp_total));
|
||||
assert((fr1 >= fr2) == std::is_gteq(cmp_total));
|
||||
assert((fr1 == fr2) == std::is_eq(cmp_total));
|
||||
assert((fr1 != fr2) == std::is_neq(cmp_total));
|
||||
assert((ByRatioNegSize{fr1} <=> ByRatioNegSize{fr2}) == cmp_total);
|
||||
assert((ByRatioNegSize{fr1} < ByRatioNegSize{fr2}) == std::is_lt(cmp_total));
|
||||
assert((ByRatioNegSize{fr1} > ByRatioNegSize{fr2}) == std::is_gt(cmp_total));
|
||||
assert((ByRatioNegSize{fr1} <= ByRatioNegSize{fr2}) == std::is_lteq(cmp_total));
|
||||
assert((ByRatioNegSize{fr1} >= ByRatioNegSize{fr2}) == std::is_gteq(cmp_total));
|
||||
assert((ByRatioNegSize{fr1} == ByRatioNegSize{fr2}) == std::is_eq(cmp_total));
|
||||
assert((ByRatioNegSize{fr1} != ByRatioNegSize{fr2}) == std::is_neq(cmp_total));
|
||||
}
|
||||
|
||||
FUZZ_TARGET(feefrac_div_fallback)
|
||||
|
||||
@@ -63,9 +63,9 @@ FeeFrac EvaluateDiagram(int32_t size, std::span<const FeeFrac> diagram)
|
||||
return {point_a.fee * dir_coef.size + dir_coef.fee * (size - point_a.size), dir_coef.size};
|
||||
}
|
||||
|
||||
std::weak_ordering CompareFeeFracWithDiagram(const FeeFrac& ff, std::span<const FeeFrac> diagram)
|
||||
std::strong_ordering CompareFeeFracWithDiagram(const FeeFrac& ff, std::span<const FeeFrac> diagram)
|
||||
{
|
||||
return FeeRateCompare(FeeFrac{ff.fee, 1}, EvaluateDiagram(ff.size, diagram));
|
||||
return ByRatio{FeeFrac{ff.fee, 1}} <=> ByRatio{EvaluateDiagram(ff.size, diagram)};
|
||||
}
|
||||
|
||||
std::partial_ordering CompareDiagrams(std::span<const FeeFrac> dia1, std::span<const FeeFrac> dia2)
|
||||
@@ -126,7 +126,7 @@ FUZZ_TARGET(build_and_compare_feerate_diagram)
|
||||
int32_t size = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(0, diagram2.back().size);
|
||||
auto eval1 = EvaluateDiagram(size, diagram1);
|
||||
auto eval2 = EvaluateDiagram(size, diagram2);
|
||||
auto cmp = FeeRateCompare(eval1, eval2);
|
||||
auto cmp = ByRatio{eval1} <=> ByRatio{eval2};
|
||||
if (std::is_lt(cmp)) assert(!std::is_gt(real));
|
||||
if (std::is_gt(cmp)) assert(!std::is_lt(real));
|
||||
}
|
||||
|
||||
@@ -210,12 +210,12 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
|
||||
FeeFrac first_sum;
|
||||
for (size_t i = 0; i < calc_results->first.size(); ++i) {
|
||||
first_sum += calc_results->first[i];
|
||||
if (i) assert(!(calc_results->first[i - 1] << calc_results->first[i]));
|
||||
if (i) assert(ByRatio{calc_results->first[i - 1]} >= ByRatio{calc_results->first[i]});
|
||||
}
|
||||
FeeFrac second_sum;
|
||||
for (size_t i = 0; i < calc_results->second.size(); ++i) {
|
||||
second_sum += calc_results->second[i];
|
||||
if (i) assert(!(calc_results->second[i - 1] << calc_results->second[i]));
|
||||
if (i) assert(ByRatio{calc_results->second[i - 1]} >= ByRatio{calc_results->second[i]});
|
||||
}
|
||||
|
||||
FeeFrac replaced;
|
||||
|
||||
@@ -433,7 +433,7 @@ FUZZ_TARGET(txgraph)
|
||||
assert(num_tx == sim.GetTransactionCount());
|
||||
// Sort by feerate only, since violating topological constraints within same-feerate
|
||||
// chunks won't affect diagram comparisons.
|
||||
std::sort(chunk_feerates.begin(), chunk_feerates.end(), std::greater{});
|
||||
std::sort(chunk_feerates.begin(), chunk_feerates.end(), std::greater<ByRatioNegSize<FeeFrac>>{});
|
||||
return chunk_feerates;
|
||||
};
|
||||
|
||||
@@ -806,10 +806,10 @@ FUZZ_TARGET(txgraph)
|
||||
assert(sim_gain == real_gain);
|
||||
// Check that the feerates in each diagram are monotonically decreasing.
|
||||
for (size_t i = 1; i < real_main_diagram.size(); ++i) {
|
||||
assert(FeeRateCompare(real_main_diagram[i], real_main_diagram[i - 1]) <= 0);
|
||||
assert(ByRatio{real_main_diagram[i]} <= ByRatio{real_main_diagram[i - 1]});
|
||||
}
|
||||
for (size_t i = 1; i < real_staged_diagram.size(); ++i) {
|
||||
assert(FeeRateCompare(real_staged_diagram[i], real_staged_diagram[i - 1]) <= 0);
|
||||
assert(ByRatio{real_staged_diagram[i]} <= ByRatio{real_staged_diagram[i - 1]});
|
||||
}
|
||||
break;
|
||||
} else if (block_builders.size() < 4 && !main_sim.IsOversized() && command-- == 0) {
|
||||
@@ -829,7 +829,7 @@ FUZZ_TARGET(txgraph)
|
||||
if (chunk) {
|
||||
// Chunk feerates must be monotonously decreasing.
|
||||
if (!builder_data.last_feerate.IsEmpty()) {
|
||||
assert(!(chunk->second >> builder_data.last_feerate));
|
||||
assert(ByRatio{chunk->second} <= ByRatio{builder_data.last_feerate});
|
||||
}
|
||||
builder_data.last_feerate = chunk->second;
|
||||
// Verify the contents of GetCurrentChunk.
|
||||
@@ -1118,7 +1118,7 @@ FUZZ_TARGET(txgraph)
|
||||
std::pair<int32_t, uint64_t> max_chunk_tiebreak{0, 0};
|
||||
for (const auto& chunk : real_chunking) {
|
||||
// If this is the first chunk with a strictly lower feerate, reset.
|
||||
if (chunk.feerate << last_chunk_feerate) {
|
||||
if (ByRatio{chunk.feerate} < ByRatio{last_chunk_feerate}) {
|
||||
comp_prefix_sizes.clear();
|
||||
max_chunk_tiebreak = {0, 0};
|
||||
}
|
||||
@@ -1212,12 +1212,12 @@ FUZZ_TARGET(txgraph)
|
||||
if (pos > 0) {
|
||||
size_t before = rng.randrange<size_t>(pos);
|
||||
auto before_feerate = real->GetMainChunkFeerate(*sims[0].GetRef(vec1[before]));
|
||||
assert(FeeRateCompare(before_feerate, pos_feerate) >= 0);
|
||||
assert(ByRatio{before_feerate} >= ByRatio{pos_feerate});
|
||||
}
|
||||
if (pos + 1 < vec1.size()) {
|
||||
size_t after = pos + 1 + rng.randrange<size_t>(vec1.size() - 1 - pos);
|
||||
auto after_feerate = real->GetMainChunkFeerate(*sims[0].GetRef(vec1[after]));
|
||||
assert(FeeRateCompare(after_feerate, pos_feerate) <= 0);
|
||||
assert(ByRatio{after_feerate} <= ByRatio{pos_feerate});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,17 +1265,17 @@ FUZZ_TARGET(txgraph)
|
||||
auto [main_cmp_diagram, stage_cmp_diagram] = real->GetMainStagingDiagrams();
|
||||
// Check that the feerates in each diagram are monotonically decreasing.
|
||||
for (size_t i = 1; i < main_cmp_diagram.size(); ++i) {
|
||||
assert(FeeRateCompare(main_cmp_diagram[i], main_cmp_diagram[i - 1]) <= 0);
|
||||
assert(ByRatio{main_cmp_diagram[i]} <= ByRatio{main_cmp_diagram[i - 1]});
|
||||
}
|
||||
for (size_t i = 1; i < stage_cmp_diagram.size(); ++i) {
|
||||
assert(FeeRateCompare(stage_cmp_diagram[i], stage_cmp_diagram[i - 1]) <= 0);
|
||||
assert(ByRatio{stage_cmp_diagram[i]} <= ByRatio{stage_cmp_diagram[i - 1]});
|
||||
}
|
||||
// Treat the diagrams as sets of chunk feerates, and sort them in the same way so that
|
||||
// std::set_difference can be used on them below. The exact ordering does not matter
|
||||
// here, but it has to be consistent with the one used in main_real_diagram and
|
||||
// stage_real_diagram).
|
||||
std::sort(main_cmp_diagram.begin(), main_cmp_diagram.end(), std::greater{});
|
||||
std::sort(stage_cmp_diagram.begin(), stage_cmp_diagram.end(), std::greater{});
|
||||
std::sort(main_cmp_diagram.begin(), main_cmp_diagram.end(), std::greater<ByRatioNegSize<FeeFrac>>{});
|
||||
std::sort(stage_cmp_diagram.begin(), stage_cmp_diagram.end(), std::greater<ByRatioNegSize<FeeFrac>>{});
|
||||
// Find the chunks that appear in main_diagram but are missing from main_cmp_diagram.
|
||||
// This is allowed, because GetMainStagingDiagrams omits clusters in main unaffected
|
||||
// by staging.
|
||||
@@ -1283,7 +1283,7 @@ FUZZ_TARGET(txgraph)
|
||||
std::set_difference(main_real_diagram.begin(), main_real_diagram.end(),
|
||||
main_cmp_diagram.begin(), main_cmp_diagram.end(),
|
||||
std::inserter(missing_main_cmp, missing_main_cmp.end()),
|
||||
std::greater{});
|
||||
std::greater<ByRatioNegSize<FeeFrac>>{});
|
||||
assert(main_cmp_diagram.size() + missing_main_cmp.size() == main_real_diagram.size());
|
||||
// Do the same for chunks in stage_diagram missing from stage_cmp_diagram.
|
||||
auto stage_real_diagram = get_diagram_fn(TxGraph::Level::TOP);
|
||||
@@ -1291,7 +1291,7 @@ FUZZ_TARGET(txgraph)
|
||||
std::set_difference(stage_real_diagram.begin(), stage_real_diagram.end(),
|
||||
stage_cmp_diagram.begin(), stage_cmp_diagram.end(),
|
||||
std::inserter(missing_stage_cmp, missing_stage_cmp.end()),
|
||||
std::greater{});
|
||||
std::greater<ByRatioNegSize<FeeFrac>>{});
|
||||
assert(stage_cmp_diagram.size() + missing_stage_cmp.size() == stage_real_diagram.size());
|
||||
// The missing chunks must be equal across main & staging (otherwise they couldn't have
|
||||
// been omitted).
|
||||
|
||||
@@ -554,7 +554,7 @@ FUZZ_TARGET(txorphanage_sim)
|
||||
count += 1 + (txn[ann.tx]->vin.size() / 10);
|
||||
usage += GetTransactionWeight(*txn[ann.tx]);
|
||||
}
|
||||
return std::max(FeeFrac{count, max_count}, FeeFrac{usage, max_usage});
|
||||
return std::max<ByRatioNegSize<FeeFrac>>(FeeFrac{count, max_count}, FeeFrac{usage, max_usage});
|
||||
};
|
||||
|
||||
//
|
||||
@@ -706,13 +706,13 @@ FUZZ_TARGET(txorphanage_sim)
|
||||
auto dos_score = dos_score_fn(peer, max_ann, max_mem);
|
||||
// Use >= so that the more recent peer (higher NodeId) wins in case of
|
||||
// ties.
|
||||
if (dos_score >= worst_dos_score) {
|
||||
if (ByRatioNegSize{dos_score} >= ByRatioNegSize{worst_dos_score}) {
|
||||
worst_dos_score = dos_score;
|
||||
worst_peer = peer;
|
||||
}
|
||||
}
|
||||
assert(worst_peer != unsigned(-1));
|
||||
assert(worst_dos_score >> FeeFrac(1, 1));
|
||||
assert(ByRatio{worst_dos_score} > ByRatio{FeeFrac(1, 1)});
|
||||
// Find oldest announcement from worst_peer, preferring non-reconsiderable ones.
|
||||
bool done{false};
|
||||
for (int reconsider = 0; reconsider < 2; ++reconsider) {
|
||||
|
||||
Reference in New Issue
Block a user