The reason that the fuzz tests fail before changing this to uint32_t
(e.g. this commit: https://github.com/davidgumberg/bitcoin/commit/01a4557b10b31e620716cff04c554e6f1a95653a) is because CFeeRate::GetFee
takes an unsigned int, but then passes it to EvaluateFeeUp()
which implicitly converts at_size
to a signed value, and large examples of uint32_t
values become negative integers, this results in EvaluateFee()
getting passed a negative number and asserting.
Wouldn’t it be better to change the FeeFrac::EvaluateFee*()
functions to take unsigned integers, e.g.:
0diff --git a/src/util/feefrac.h b/src/util/feefrac.h
1index 7577107e8c..9d034c6791 100644
2--- a/src/util/feefrac.h
3+++ b/src/util/feefrac.h
4@@ -199,10 +199,9 @@ struct FeeFrac
5 * is guaranteed to be the case when 0 <= at_size <= this->size.
6 */
7 template<bool RoundDown>
8- int64_t EvaluateFee(int32_t at_size) const noexcept
9+ int64_t EvaluateFee(uint32_t at_size) const noexcept
10 {
11 Assume(size > 0);
12- Assume(at_size >= 0);
13 if (fee >= 0 && fee < 0x200000000) [[likely]] {
14 // Common case where (this->fee * at_size) is guaranteed to fit in a uint64_t.
15 if constexpr (RoundDown) {
16@@ -218,9 +217,9 @@ struct FeeFrac
17
18 public:
19 /** Compute the fee for a given size `at_size` using this object's feerate, rounding down. */
20- int64_t EvaluateFeeDown(int32_t at_size) const noexcept { return EvaluateFee<true>(at_size); }
21+ int64_t EvaluateFeeDown(uint32_t at_size) const noexcept { return EvaluateFee<true>(at_size); }
22 /** Compute the fee for a given size `at_size` using this object's feerate, rounding up. */
23- int64_t EvaluateFeeUp(int32_t at_size) const noexcept { return EvaluateFee<false>(at_size); }
24+ int64_t EvaluateFeeUp(uint32_t at_size) const noexcept { return EvaluateFee<false>(at_size); }
25 };
26
27 /** Compare the feerate diagrams implied by the provided sorted chunks data.
Tested as follows:
0cmake --preset libfuzzer && cmake --build build_fuzz -j $(nproc)
1FUZZ=fee_rate_fuzz_target