Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2023-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <cstdint>7#include <vector>9#include <util/feefrac.h>10#include <policy/rbf.h>12#include <test/fuzz/fuzz.h>13#include <test/fuzz/util.h>15#include <cassert>17namespace {19/** Takes the pre-computed and topologically-valid chunks and generates a fee diagram which starts at FeeFrac of (0, 0) */20std::vector<FeeFrac> BuildDiagramFromChunks(const std::span<const FeeFrac> chunks)21{22std::vector<FeeFrac> diagram;23diagram.reserve(chunks.size() + 1);25diagram.emplace_back(0, 0);26for (auto& chunk : chunks) {27diagram.emplace_back(diagram.back() + chunk);28}29return diagram;30}33/** Evaluate a diagram at a specific size, returning the fee as a fraction.34*35* Fees in diagram cannot exceed 2^32, as the returned evaluation could overflow36* the FeeFrac::fee field in the result. */37FeeFrac EvaluateDiagram(int32_t size, std::span<const FeeFrac> diagram)38{39assert(diagram.size() > 0);40unsigned not_above = 0;41unsigned not_below = diagram.size() - 1;42// If outside the range of diagram, extend begin/end.43if (size < diagram[not_above].size) return {diagram[not_above].fee, 1};44if (size > diagram[not_below].size) return {diagram[not_below].fee, 1};45// Perform bisection search to locate the diagram segment that size is in.46while (not_below > not_above + 1) {47unsigned mid = (not_below + not_above) / 2;48if (diagram[mid].size <= size) not_above = mid;49if (diagram[mid].size >= size) not_below = mid;50}51// If the size matches a transition point between segments, return its fee.52if (not_below == not_above) return {diagram[not_below].fee, 1};53// Otherwise, interpolate.54auto dir_coef = diagram[not_below] - diagram[not_above];55assert(dir_coef.size > 0);56// Let A = diagram[not_above] and B = diagram[not_below]57const auto& point_a = diagram[not_above];58// We want to return:59// A.fee + (B.fee - A.fee) / (B.size - A.size) * (size - A.size)60// = A.fee + dir_coef.fee / dir_coef.size * (size - A.size)61// = (A.fee * dir_coef.size + dir_coef.fee * (size - A.size)) / dir_coef.size62assert(size >= point_a.size);63return {point_a.fee * dir_coef.size + dir_coef.fee * (size - point_a.size), dir_coef.size};64}66std::strong_ordering CompareFeeFracWithDiagram(const FeeFrac& ff, std::span<const FeeFrac> diagram)67{68return ByRatio{FeeFrac{ff.fee, 1}} <=> ByRatio{EvaluateDiagram(ff.size, diagram)};69}71std::partial_ordering CompareDiagrams(std::span<const FeeFrac> dia1, std::span<const FeeFrac> dia2)72{73bool all_ge = true;74bool all_le = true;75for (const auto p1 : dia1) {76auto cmp = CompareFeeFracWithDiagram(p1, dia2);77if (std::is_lt(cmp)) all_ge = false;78if (std::is_gt(cmp)) all_le = false;79}80for (const auto p2 : dia2) {81auto cmp = CompareFeeFracWithDiagram(p2, dia1);82if (std::is_lt(cmp)) all_le = false;83if (std::is_gt(cmp)) all_ge = false;84}85if (all_ge && all_le) return std::partial_ordering::equivalent;86if (all_ge && !all_le) return std::partial_ordering::greater;87if (!all_ge && all_le) return std::partial_ordering::less;88return std::partial_ordering::unordered;89}91void PopulateChunks(FuzzedDataProvider& fuzzed_data_provider, std::vector<FeeFrac>& chunks)92{93chunks.clear();95LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 50) {96chunks.emplace_back(fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(INT32_MIN>>1, INT32_MAX>>1), fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(1, 1000000));97}98return;99}101} // namespace103FUZZ_TARGET(build_and_compare_feerate_diagram)104{105// Generate a random set of chunks106FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());107std::vector<FeeFrac> chunks1, chunks2;108FeeFrac empty{0, 0};110PopulateChunks(fuzzed_data_provider, chunks1);111PopulateChunks(fuzzed_data_provider, chunks2);113std::vector<FeeFrac> diagram1{BuildDiagramFromChunks(chunks1)};114std::vector<FeeFrac> diagram2{BuildDiagramFromChunks(chunks2)};116assert(diagram1.front() == empty);117assert(diagram2.front() == empty);119auto real = CompareChunks(chunks1, chunks2);120auto sim = CompareDiagrams(diagram1, diagram2);121assert(real == sim);123// Do explicit evaluation at up to 1000 points, and verify consistency with the result.124LIMITED_WHILE (fuzzed_data_provider.remaining_bytes(), 1000) {125int32_t size = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(0, diagram2.back().size);126auto eval1 = EvaluateDiagram(size, diagram1);127auto eval2 = EvaluateDiagram(size, diagram2);128auto cmp = ByRatio{eval1} <=> ByRatio{eval2};129if (std::is_lt(cmp)) assert(!std::is_gt(real));130if (std::is_gt(cmp)) assert(!std::is_lt(real));131}132}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.