/Users/eugenesiegel/btc/bitcoin/src/util/feefrac.h
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 4 |  |  | 
| 5 |  | #ifndef BITCOIN_UTIL_FEEFRAC_H | 
| 6 |  | #define BITCOIN_UTIL_FEEFRAC_H | 
| 7 |  |  | 
| 8 |  | #include <span.h> | 
| 9 |  | #include <util/check.h> | 
| 10 |  |  | 
| 11 |  | #include <compare> | 
| 12 |  | #include <cstdint> | 
| 13 |  | #include <vector> | 
| 14 |  |  | 
| 15 |  | /** Data structure storing a fee and size, ordered by increasing fee/size. | 
| 16 |  |  * | 
| 17 |  |  * The size of a FeeFrac cannot be zero unless the fee is also zero. | 
| 18 |  |  * | 
| 19 |  |  * FeeFracs have a total ordering, first by increasing feerate (ratio of fee over size), and then | 
| 20 |  |  * by decreasing size. The empty FeeFrac (fee and size both 0) sorts last. So for example, the | 
| 21 |  |  * following FeeFracs are in sorted order: | 
| 22 |  |  * | 
| 23 |  |  * - fee=0 size=1 (feerate 0) | 
| 24 |  |  * - fee=1 size=2 (feerate 0.5) | 
| 25 |  |  * - fee=2 size=3 (feerate 0.667...) | 
| 26 |  |  * - fee=2 size=2 (feerate 1) | 
| 27 |  |  * - fee=1 size=1 (feerate 1) | 
| 28 |  |  * - fee=3 size=2 (feerate 1.5) | 
| 29 |  |  * - fee=2 size=1 (feerate 2) | 
| 30 |  |  * - fee=0 size=0 (undefined feerate) | 
| 31 |  |  * | 
| 32 |  |  * A FeeFrac is considered "better" if it sorts after another, by this ordering. All standard | 
| 33 |  |  * comparison operators (<=>, ==, !=, >, <, >=, <=) respect this ordering. | 
| 34 |  |  * | 
| 35 |  |  * The FeeRateCompare, and >> and << operators only compare feerate and treat equal feerate but | 
| 36 |  |  * different size as equivalent. The empty FeeFrac is neither lower or higher in feerate than any | 
| 37 |  |  * other. | 
| 38 |  |  */ | 
| 39 |  | struct FeeFrac | 
| 40 |  | { | 
| 41 |  |     /** Helper function for 32*64 signed multiplication, returning an unspecified but totally | 
| 42 |  |      *  ordered type. This is a fallback version, separate so it can be tested on platforms where | 
| 43 |  |      *  it isn't actually needed. */ | 
| 44 |  |     static inline std::pair<int64_t, uint32_t> MulFallback(int64_t a, int32_t b) noexcept | 
| 45 | 0 |     { | 
| 46 | 0 |         int64_t low = int64_t{static_cast<uint32_t>(a)} * b; | 
| 47 | 0 |         int64_t high = (a >> 32) * b; | 
| 48 | 0 |         return {high + (low >> 32), static_cast<uint32_t>(low)}; | 
| 49 | 0 |     } | 
| 50 |  |  | 
| 51 |  |     /** Helper function for 96/32 signed division, rounding towards negative infinity (if | 
| 52 |  |      *  round_down) or positive infinity (if !round_down). This is a fallback version, separate so | 
| 53 |  |      *  that it can be tested on platforms where it isn't actually needed. | 
| 54 |  |      * | 
| 55 |  |      * The exact behavior with negative n does not really matter, but this implementation chooses | 
| 56 |  |      * to be consistent for testability reasons. | 
| 57 |  |      * | 
| 58 |  |      * The result must fit in an int64_t, and d must be strictly positive. */ | 
| 59 |  |     static inline int64_t DivFallback(std::pair<int64_t, uint32_t> n, int32_t d, bool round_down) noexcept | 
| 60 | 0 |     { | 
| 61 | 0 |         Assume(d > 0); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 62 |  |         // Compute quot_high = n.first / d, so the result becomes | 
| 63 |  |         // (n.second + (n.first - quot_high * d) * 2**32) / d + (quot_high * 2**32), or | 
| 64 |  |         // (n.second + (n.first % d) * 2**32) / d + (quot_high * 2**32). | 
| 65 | 0 |         int64_t quot_high = n.first / d; | 
| 66 |  |         // Evaluate the parenthesized expression above, so the result becomes | 
| 67 |  |         // n_low / d + (quot_high * 2**32) | 
| 68 | 0 |         int64_t n_low = ((n.first % d) << 32) + n.second; | 
| 69 |  |         // Evaluate the division so the result becomes quot_low + quot_high * 2**32. It is possible | 
| 70 |  |         // that the / operator here rounds in the wrong direction (if n_low is not a multiple of | 
| 71 |  |         // size, and is (if round_down) negative, or (if !round_down) positive). If so, make a | 
| 72 |  |         // correction. | 
| 73 | 0 |         int64_t quot_low = n_low / d; | 
| 74 | 0 |         int32_t mod_low = n_low % d; | 
| 75 | 0 |         quot_low += (mod_low > 0) - (mod_low && round_down); | 
| 76 |  |         // Combine and return the result | 
| 77 | 0 |         return (quot_high << 32) + quot_low; | 
| 78 | 0 |     } | 
| 79 |  |  | 
| 80 |  | #ifdef __SIZEOF_INT128__ | 
| 81 |  |     /** Helper function for 32*64 signed multiplication, returning an unspecified but totally | 
| 82 |  |      *  ordered type. This is a version relying on __int128. */ | 
| 83 |  |     static inline __int128 Mul(int64_t a, int32_t b) noexcept | 
| 84 | 178M |     { | 
| 85 | 178M |         return __int128{a} * b; | 
| 86 | 178M |     } | 
| 87 |  |  | 
| 88 |  |     /** Helper function for 96/32 signed division, rounding towards negative infinity (if | 
| 89 |  |      *  round_down), or towards positive infinity (if !round_down). This is a | 
| 90 |  |      *  version relying on __int128. | 
| 91 |  |      * | 
| 92 |  |      * The result must fit in an int64_t, and d must be strictly positive. */ | 
| 93 |  |     static inline int64_t Div(__int128 n, int32_t d, bool round_down) noexcept | 
| 94 | 0 |     { | 
| 95 | 0 |         Assume(d > 0); | Line | Count | Source |  | 118 | 0 | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 96 |  |         // Compute the division. | 
| 97 | 0 |         int64_t quot = n / d; | 
| 98 | 0 |         int32_t mod = n % d; | 
| 99 |  |         // Correct result if the / operator above rounded in the wrong direction. | 
| 100 | 0 |         return quot + ((mod > 0) - (mod && round_down)); | 
| 101 | 0 |     } | 
| 102 |  | #else | 
| 103 |  |     static constexpr auto Mul = MulFallback; | 
| 104 |  |     static constexpr auto Div = DivFallback; | 
| 105 |  | #endif | 
| 106 |  |  | 
| 107 |  |     int64_t fee; | 
| 108 |  |     int32_t size; | 
| 109 |  |  | 
| 110 |  |     /** Construct an IsEmpty() FeeFrac. */ | 
| 111 | 931k |     constexpr inline FeeFrac() noexcept : fee{0}, size{0} {} | 
| 112 |  |  | 
| 113 |  |     /** Construct a FeeFrac with specified fee and size. */ | 
| 114 | 154M |     constexpr inline FeeFrac(int64_t f, int32_t s) noexcept : fee{f}, size{s} {} | 
| 115 |  |  | 
| 116 |  |     constexpr inline FeeFrac(const FeeFrac&) noexcept = default; | 
| 117 |  |     constexpr inline FeeFrac& operator=(const FeeFrac&) noexcept = default; | 
| 118 |  |  | 
| 119 |  |     /** Check if this is empty (size and fee are 0). */ | 
| 120 | 3.74M |     bool inline IsEmpty() const noexcept { | 
| 121 | 3.74M |         return size == 0; | 
| 122 | 3.74M |     } | 
| 123 |  |  | 
| 124 |  |     /** Add fee and size of another FeeFrac to this one. */ | 
| 125 |  |     void inline operator+=(const FeeFrac& other) noexcept | 
| 126 | 0 |     { | 
| 127 | 0 |         fee += other.fee; | 
| 128 | 0 |         size += other.size; | 
| 129 | 0 |     } | 
| 130 |  |  | 
| 131 |  |     /** Subtract fee and size of another FeeFrac from this one. */ | 
| 132 |  |     void inline operator-=(const FeeFrac& other) noexcept | 
| 133 | 0 |     { | 
| 134 | 0 |         fee -= other.fee; | 
| 135 | 0 |         size -= other.size; | 
| 136 | 0 |     } | 
| 137 |  |  | 
| 138 |  |     /** Sum fee and size. */ | 
| 139 |  |     friend inline FeeFrac operator+(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 140 | 0 |     { | 
| 141 | 0 |         return {a.fee + b.fee, a.size + b.size}; | 
| 142 | 0 |     } | 
| 143 |  |  | 
| 144 |  |     /** Subtract both fee and size. */ | 
| 145 |  |     friend inline FeeFrac operator-(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 146 | 0 |     { | 
| 147 | 0 |         return {a.fee - b.fee, a.size - b.size}; | 
| 148 | 0 |     } | 
| 149 |  |  | 
| 150 |  |     /** Check if two FeeFrac objects are equal (both same fee and same size). */ | 
| 151 |  |     friend inline bool operator==(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 152 | 0 |     { | 
| 153 | 0 |         return a.fee == b.fee && a.size == b.size; | 
| 154 | 0 |     } | 
| 155 |  |  | 
| 156 |  |     /** Compare two FeeFracs just by feerate. */ | 
| 157 |  |     friend inline std::weak_ordering FeeRateCompare(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 158 | 57.0M |     { | 
| 159 | 57.0M |         auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size); | 
| 160 | 57.0M |         return cross_a <=> cross_b; | 
| 161 | 57.0M |     } | 
| 162 |  |  | 
| 163 |  |     /** Check if a FeeFrac object has strictly lower feerate than another. */ | 
| 164 |  |     friend inline bool operator<<(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 165 | 0 |     { | 
| 166 | 0 |         auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size); | 
| 167 | 0 |         return cross_a < cross_b; | 
| 168 | 0 |     } | 
| 169 |  |  | 
| 170 |  |     /** Check if a FeeFrac object has strictly higher feerate than another. */ | 
| 171 |  |     friend inline bool operator>>(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 172 | 0 |     { | 
| 173 | 0 |         auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size); | 
| 174 | 0 |         return cross_a > cross_b; | 
| 175 | 0 |     } | 
| 176 |  |  | 
| 177 |  |     /** Compare two FeeFracs. <, >, <=, and >= are auto-generated from this. */ | 
| 178 |  |     friend inline std::strong_ordering operator<=>(const FeeFrac& a, const FeeFrac& b) noexcept | 
| 179 | 32.3M |     { | 
| 180 | 32.3M |         auto cross_a = Mul(a.fee, b.size), cross_b = Mul(b.fee, a.size); | 
| 181 | 32.3M |         if (cross_a == cross_b) return b.size <=> a.size; | 
| 182 | 0 |         return cross_a <=> cross_b; | 
| 183 | 32.3M |     } | 
| 184 |  |  | 
| 185 |  |     /** Swap two FeeFracs. */ | 
| 186 |  |     friend inline void swap(FeeFrac& a, FeeFrac& b) noexcept | 
| 187 | 0 |     { | 
| 188 | 0 |         std::swap(a.fee, b.fee); | 
| 189 | 0 |         std::swap(a.size, b.size); | 
| 190 | 0 |     } | 
| 191 |  |  | 
| 192 |  |     /** Compute the fee for a given size `at_size` using this object's feerate. | 
| 193 |  |      * | 
| 194 |  |      * This effectively corresponds to evaluating (this->fee * at_size) / this->size, with the | 
| 195 |  |      * result rounded towards negative infinity (if RoundDown) or towards positive infinity | 
| 196 |  |      * (if !RoundDown). | 
| 197 |  |      * | 
| 198 |  |      * Requires this->size > 0, at_size >= 0, and that the correct result fits in a int64_t. This | 
| 199 |  |      * is guaranteed to be the case when 0 <= at_size <= this->size. | 
| 200 |  |      */ | 
| 201 |  |     template<bool RoundDown> | 
| 202 |  |     int64_t EvaluateFee(int32_t at_size) const noexcept | 
| 203 | 9.60M |     { | 
| 204 | 9.60M |         Assume(size > 0); | Line | Count | Source |  | 118 | 5.85M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 |         Assume(size > 0); | Line | Count | Source |  | 118 | 3.74M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 205 | 9.60M |         Assume(at_size >= 0); | Line | Count | Source |  | 118 | 5.85M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 |         Assume(at_size >= 0); | Line | Count | Source |  | 118 | 3.74M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 206 | 9.60M |         if (fee >= 0 && fee < 0x200000000) [[likely]] { | 
| 207 |  |             // Common case where (this->fee * at_size) is guaranteed to fit in a uint64_t. | 
| 208 | 9.60M |             if constexpr (RoundDown) { | 
| 209 | 5.85M |                 return (uint64_t(fee) * at_size) / uint32_t(size); | 
| 210 | 5.85M |             } else { | 
| 211 | 3.74M |                 return (uint64_t(fee) * at_size + size - 1U) / uint32_t(size); | 
| 212 | 3.74M |             } | 
| 213 | 9.60M |         } else { | 
| 214 |  |             // Otherwise, use Mul and Div. | 
| 215 | 0 |             return Div(Mul(fee, at_size), size, RoundDown); | 
| 216 | 0 |         } | 
| 217 | 9.60M |     } _ZNK7FeeFrac11EvaluateFeeILb1EEExi| Line | Count | Source |  | 203 | 5.85M |     { |  | 204 | 5.85M |         Assume(size > 0); | Line | Count | Source |  | 118 | 5.85M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 |  | 205 | 5.85M |         Assume(at_size >= 0); | Line | Count | Source |  | 118 | 5.85M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 |  | 206 | 5.85M |         if (fee >= 0 && fee < 0x200000000) [[likely]] { |  | 207 |  |             // Common case where (this->fee * at_size) is guaranteed to fit in a uint64_t. |  | 208 | 5.85M |             if constexpr (RoundDown) { |  | 209 | 5.85M |                 return (uint64_t(fee) * at_size) / uint32_t(size); |  | 210 |  |             } else { |  | 211 |  |                 return (uint64_t(fee) * at_size + size - 1U) / uint32_t(size); |  | 212 |  |             } |  | 213 | 5.85M |         } else { |  | 214 |  |             // Otherwise, use Mul and Div. |  | 215 | 0 |             return Div(Mul(fee, at_size), size, RoundDown); |  | 216 | 0 |         } |  | 217 | 5.85M |     } | 
_ZNK7FeeFrac11EvaluateFeeILb0EEExi| Line | Count | Source |  | 203 | 3.74M |     { |  | 204 | 3.74M |         Assume(size > 0); | Line | Count | Source |  | 118 | 3.74M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 |  | 205 | 3.74M |         Assume(at_size >= 0); | Line | Count | Source |  | 118 | 3.74M | #define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val) | 
 |  | 206 | 3.74M |         if (fee >= 0 && fee < 0x200000000) [[likely]] { |  | 207 |  |             // Common case where (this->fee * at_size) is guaranteed to fit in a uint64_t. |  | 208 |  |             if constexpr (RoundDown) { |  | 209 |  |                 return (uint64_t(fee) * at_size) / uint32_t(size); |  | 210 | 3.74M |             } else { |  | 211 | 3.74M |                 return (uint64_t(fee) * at_size + size - 1U) / uint32_t(size); |  | 212 | 3.74M |             } |  | 213 | 3.74M |         } else { |  | 214 |  |             // Otherwise, use Mul and Div. |  | 215 | 0 |             return Div(Mul(fee, at_size), size, RoundDown); |  | 216 | 0 |         } |  | 217 | 3.74M |     } | 
 | 
| 218 |  |  | 
| 219 |  | public: | 
| 220 |  |     /** Compute the fee for a given size `at_size` using this object's feerate, rounding down. */ | 
| 221 | 5.85M |     int64_t EvaluateFeeDown(int32_t at_size) const noexcept { return EvaluateFee<true>(at_size); } | 
| 222 |  |     /** Compute the fee for a given size `at_size` using this object's feerate, rounding up. */ | 
| 223 | 3.74M |     int64_t EvaluateFeeUp(int32_t at_size) const noexcept { return EvaluateFee<false>(at_size); } | 
| 224 |  | }; | 
| 225 |  |  | 
| 226 |  | /** Compare the feerate diagrams implied by the provided sorted chunks data. | 
| 227 |  |  * | 
| 228 |  |  * The implied diagram for each starts at (0, 0), then contains for each chunk the cumulative fee | 
| 229 |  |  * and size up to that chunk, and then extends infinitely to the right with a horizontal line. | 
| 230 |  |  * | 
| 231 |  |  * The caller must guarantee that the sum of the FeeFracs in either of the chunks' data set do not | 
| 232 |  |  * overflow (so sum fees < 2^63, and sum sizes < 2^31). | 
| 233 |  |  */ | 
| 234 |  | std::partial_ordering CompareChunks(std::span<const FeeFrac> chunks0, std::span<const FeeFrac> chunks1); | 
| 235 |  |  | 
| 236 |  | /** Tagged wrapper around FeeFrac to avoid unit confusion. */ | 
| 237 |  | template<typename Tag> | 
| 238 |  | struct FeePerUnit : public FeeFrac | 
| 239 |  | { | 
| 240 |  |     // Inherit FeeFrac constructors. | 
| 241 |  |     using FeeFrac::FeeFrac; | 
| 242 |  |  | 
| 243 |  |     /** Convert a FeeFrac to a FeePerUnit. */ | 
| 244 |  |     static FeePerUnit FromFeeFrac(const FeeFrac& feefrac) noexcept | 
| 245 | 0 |     { | 
| 246 | 0 |         return {feefrac.fee, feefrac.size}; | 
| 247 | 0 |     } | 
| 248 |  | }; | 
| 249 |  |  | 
| 250 |  | // FeePerUnit instance for satoshi / vbyte. | 
| 251 |  | struct VSizeTag {}; | 
| 252 |  | using FeePerVSize = FeePerUnit<VSizeTag>; | 
| 253 |  |  | 
| 254 |  | // FeePerUnit instance for satoshi / WU. | 
| 255 |  | struct WeightTag {}; | 
| 256 |  | using FeePerWeight = FeePerUnit<WeightTag>; | 
| 257 |  |  | 
| 258 |  | #endif // BITCOIN_UTIL_FEEFRAC_H |