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) 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#ifndef BITCOIN_UTIL_FEEFRAC_H6#define BITCOIN_UTIL_FEEFRAC_H8#include <util/check.h>9#include <util/overflow.h>11#include <concepts>12#include <cstdint>13#include <span>14#include <utility>16/** Data structure storing a fee and size.17*18* The size of a FeeFrac cannot be zero unless the fee is also zero.19*/20struct FeeFrac21{22/** Helper function for 32*64 signed multiplication, returning an unspecified but totally23* ordered type. This is a fallback version, separate so it can be tested on platforms where24* it isn't actually needed. */25static inline std::pair<int64_t, uint32_t> MulFallback(int64_t a, int32_t b) noexcept26{27int64_t low = int64_t{static_cast<uint32_t>(a)} * b;28int64_t high = (a >> 32) * b;29return {high + (low >> 32), static_cast<uint32_t>(low)};30}32/** Helper function for 96/32 signed division, rounding towards negative infinity (if33* round_down) or positive infinity (if !round_down). This is a fallback version, separate so34* that it can be tested on platforms where it isn't actually needed.35*36* The exact behavior with negative n does not really matter, but this implementation chooses37* to be consistent for testability reasons.38*39* The result must fit in an int64_t, and d must be strictly positive. */40static inline int64_t DivFallback(std::pair<int64_t, uint32_t> n, int32_t d, bool round_down) noexcept41{42Assume(d > 0);43// Compute quot_high = n.first / d, so the result becomes44// (n.second + (n.first - quot_high * d) * 2**32) / d + (quot_high * 2**32), or45// (n.second + (n.first % d) * 2**32) / d + (quot_high * 2**32).46int64_t quot_high = n.first / d;47// Evaluate the parenthesized expression above, so the result becomes48// n_low / d + (quot_high * 2**32)49int64_t n_low = ((n.first % d) << 32) + n.second;50// Evaluate the division so the result becomes quot_low + quot_high * 2**32. It is possible51// that the / operator here rounds in the wrong direction (if n_low is not a multiple of52// size, and is (if round_down) negative, or (if !round_down) positive). If so, make a53// correction.54int64_t quot_low = n_low / d;55int32_t mod_low = n_low % d;56quot_low += (mod_low > 0) - (mod_low && round_down);57// Combine and return the result58return (quot_high << 32) + quot_low;59}61#ifdef __SIZEOF_INT128__62/** Helper function for 32*64 signed multiplication, returning an unspecified but totally63* ordered type. This is a version relying on __int128. */64static inline __int128 Mul(int64_t a, int32_t b) noexcept65{66return __int128{a} * b;67}69/** Helper function for 96/32 signed division, rounding towards negative infinity (if70* round_down), or towards positive infinity (if !round_down). This is a71* version relying on __int128.72*73* The result must fit in an int64_t, and d must be strictly positive. */74static inline int64_t Div(__int128 n, int32_t d, bool round_down) noexcept75{76Assume(d > 0);77// Compute the division.78int64_t quot = n / d;79int32_t mod = n % d;80// Correct result if the / operator above rounded in the wrong direction.81return quot + ((mod > 0) - (mod && round_down));82}83#else84static constexpr auto Mul = MulFallback;85static constexpr auto Div = DivFallback;86#endif88int64_t fee;89int32_t size;91/** Construct an IsEmpty() FeeFrac. */92constexpr inline FeeFrac() noexcept : fee{0}, size{0} {}94/** Construct a FeeFrac with specified fee and size. */95constexpr inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {}97constexpr inline FeeFrac(const FeeFrac&) noexcept = default;98constexpr inline FeeFrac& operator=(const FeeFrac&) noexcept = default;100/** Check if this is empty (size and fee are 0). */101bool inline IsEmpty() const noexcept {102return size == 0;103}105/** Add fee and size of another FeeFrac to this one. */106void inline operator+=(const FeeFrac& other) noexcept107{108fee += other.fee;109size += other.size;110}112/** Subtract fee and size of another FeeFrac from this one. */113void inline operator-=(const FeeFrac& other) noexcept114{115fee -= other.fee;116size -= other.size;117}119/** Sum fee and size. */120friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept121{122return {a.fee + b.fee, a.size + b.size};123}125/** Subtract both fee and size. */126friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept127{128return {a.fee - b.fee, a.size - b.size};129}131/** Check if two FeeFrac objects are equal (both same fee and same size). */132friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept133{134return a.fee == b.fee && a.size == b.size;135}137/** Swap two FeeFracs. */138friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept139{140std::swap(a.fee, b.fee);141std::swap(a.size, b.size);142}144/** Compute the fee for a given size `at_size` using this object's feerate.145*146* This effectively corresponds to evaluating (this->fee * at_size) / this->size, with the147* result rounded towards negative infinity (if RoundDown) or towards positive infinity148* (if !RoundDown).149*150* Requires this->size > 0, at_size >= 0, and that the correct result fits in a int64_t. This151* is guaranteed to be the case when 0 <= at_size <= this->size.152*/153template<bool RoundDown>154int64_t EvaluateFee(int32_t at_size) const noexcept155{156Assume(size > 0);157Assume(at_size >= 0);158if (fee >= 0 && fee < 0x200000000) [[likely]] {159// Common case where (this->fee * at_size) is guaranteed to fit in a uint64_t.160if constexpr (RoundDown) {161return (uint64_t(fee) * at_size) / uint32_t(size);162} else {163return CeilDiv(uint64_t(fee) * at_size, uint32_t(size));164}165} else {166// Otherwise, use Mul and Div.167return Div(Mul(fee, at_size), size, RoundDown);168}169}171public:172/** Compute the fee for a given size `at_size` using this object's feerate, rounding down. */173int64_t EvaluateFeeDown(int32_t at_size) const noexcept { return EvaluateFee<true>(at_size); }174/** Compute the fee for a given size `at_size` using this object's feerate, rounding up. */175int64_t EvaluateFeeUp(int32_t at_size) const noexcept { return EvaluateFee<false>(at_size); }176};178/** Compare the feerate diagrams implied by the provided sorted chunks data.179*180* The implied diagram for each starts at (0, 0), then contains for each chunk the cumulative fee181* and size up to that chunk, and then extends infinitely to the right with a horizontal line.182*183* The caller must guarantee that the sum of the FeeFracs in either of the chunks' data set do not184* overflow (so sum fees < 2^63, and sum sizes < 2^31).185*/186std::partial_ordering CompareChunks(std::span<const FeeFrac> chunks0, std::span<const FeeFrac> chunks1);188/** Tagged wrapper around FeeFrac to avoid unit confusion. */189template<typename Tag>190struct FeePerUnit : public FeeFrac191{192// Inherit FeeFrac constructors.193using FeeFrac::FeeFrac;195/** Convert a FeeFrac to a FeePerUnit. */196static FeePerUnit FromFeeFrac(const FeeFrac& feefrac) noexcept197{198return {feefrac.fee, feefrac.size};199}200};202// FeePerUnit instance for satoshi / vbyte.203struct VSizeTag {};204using FeePerVSize = FeePerUnit<VSizeTag>;206// FeePerUnit instance for satoshi / WU.207struct WeightTag {};208using FeePerWeight = FeePerUnit<WeightTag>;210/** Wrapper around FeeFrac & derived types, which adds a feerate-based ordering which treats211* equal-feerate but distinct-size FeeFracs as equals.212*213* This is not included inside FeeFrac itself, because it is not a total ordering (as would be214* expected for built-in comparison operators).215*/216template<std::derived_from<FeeFrac> T>217class ByRatio218{219const T& m_feefrac;221public:222constexpr ByRatio(const T& feefrac) noexcept : m_feefrac{feefrac} {}224friend bool operator==(const ByRatio& a, const ByRatio& b) noexcept225{226auto cross_a = T::Mul(a.m_feefrac.fee, b.m_feefrac.size);227auto cross_b = T::Mul(b.m_feefrac.fee, a.m_feefrac.size);228return cross_a == cross_b;229}231// Note that we can use std::strong_ordering here, because even though FeeFrac{1,2} and232// FeeFrac{2,4} are distinct as FeeFracs, they are indistinguishable from ByRatio's perspective233// (operator== also treats them as equal).234friend std::strong_ordering operator<=>(const ByRatio& a, const ByRatio& b) noexcept235{236auto cross_a = T::Mul(a.m_feefrac.fee, b.m_feefrac.size);237auto cross_b = T::Mul(b.m_feefrac.fee, a.m_feefrac.size);238return cross_a <=> cross_b;239}241// Specialized versions for efficiency. GCC 15+ and Clang 11+ produce operator<=>-derived242// versions that are equally efficient as this at -O2, but earlier versions do not.243friend bool operator<(const ByRatio& a, const ByRatio& b) noexcept244{245auto cross_a = T::Mul(a.m_feefrac.fee, b.m_feefrac.size);246auto cross_b = T::Mul(b.m_feefrac.fee, a.m_feefrac.size);247return cross_a < cross_b;248}249friend bool operator>(const ByRatio& a, const ByRatio& b) noexcept250{
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.