Skip to content

refactor: CFeeRate encapsulates FeeFrac internally - #32750

Merged
achow101 merged 1 commit into
bitcoin:masterfrom
polespinasa:FeeFracWrapper
Aug 9, 2025
Merged

refactor: CFeeRate encapsulates FeeFrac internally#32750
achow101 merged 1 commit into
bitcoin:masterfrom
polespinasa:FeeFracWrapper

Conversation

@polespinasa

@polespinasa polespinasa commented Jun 15, 2025

Copy link
Copy Markdown
Member

The FeeFrac type represents a fraction, intended to be used for sats/vbyte or sats/WU. It was added to improve accuracy when evaluating fee rates in cluster mempool. [1]
But it can also be used to fix the precision issues that the current CFeeRate class has now.

At the moment, CFeeRate handles the fee rate as satoshis per kilovirtualbyte: CAmount / kvB using an integer.
This PR fix CFeeRate precision issues by encapsulating FeeFrac internally keeping backwards compatibility.

This PR can also be used as a based to use multiple units on RPC calls as detailed in this issue [2].

Some previous discussions:
[1] #30535
[2] #32093

@DrahtBot

DrahtBot commented Jun 15, 2025

Copy link
Copy Markdown
Contributor

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32750.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK murchandamus, ismaelsadeeq, theStack, achow101
Concept ACK Eunovo

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

No conflicts as of last run.

LLM Linter (✨ experimental)

Possible typos and grammar issues:

  • param@[in] -> @PARAM[in] [correct Doxygen tag syntax]
  • param@[in] -> @PARAM[in] [correct Doxygen tag syntax]

drahtbot_id_4_m

@polespinasa polespinasa changed the title Refactor CFeeRate to use FeeFrac internally refactor: CFeeRate encapsulates FeeFrac internally Jun 15, 2025
@DrahtBot

Copy link
Copy Markdown
Contributor

🚧 At least one of the CI tasks failed.
Task fuzzer,address,undefined,integer, no depends: https://github.com/bitcoin/bitcoin/runs/44121425336
LLM reason (✨ experimental): The CI failure is caused by an implicit integer conversion that triggered an UndefinedBehaviorSanitizer error during fuzzing.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@ismaelsadeeq ismaelsadeeq left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK I've taken a look into this previously in #30535 (review)

@ismaelsadeeq ismaelsadeeq left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can fix the fuzz crash with

diff --git a/src/test/fuzz/fee_rate.cpp b/src/test/fuzz/fee_rate.cpp
index 92616b62bea..f69cb59ab7b 100644
--- a/src/test/fuzz/fee_rate.cpp
+++ b/src/test/fuzz/fee_rate.cpp
@@ -20,7 +20,7 @@ FUZZ_TARGET(fee_rate)
     const CFeeRate fee_rate{satoshis_per_k};
 
     (void)fee_rate.GetFeePerK();
-    const auto bytes = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+    const auto bytes = fuzzed_data_provider.ConsumeIntegral<int32_t>();
     if (!MultiplicationOverflow(int64_t{bytes}, satoshis_per_k)) {
         (void)fee_rate.GetFee(bytes);
     }

Also the // Compare approximately with CFeeRate test in src/test/fuzz/fee_frac.cpp is now not required.

@polespinasa
polespinasa force-pushed the FeeFracWrapper branch 2 times, most recently from fdc3d20 to 417bd07 Compare June 16, 2025 19:42
Comment thread src/policy/feerate.h Outdated
Comment thread src/policy/feerate.cpp Outdated
Comment thread src/policy/feerate.cpp Outdated
Comment thread src/policy/feerate.cpp Outdated
Comment thread src/policy/feerate.h Outdated
Comment thread src/policy/feerate.cpp Outdated

@Eunovo Eunovo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

Left some comments

Comment thread src/policy/feerate.h Outdated
Comment thread src/policy/feerate.h Outdated
Comment thread src/policy/feerate.cpp Outdated
Comment thread src/policy/feerate.cpp Outdated
@polespinasa

Copy link
Copy Markdown
Member Author

13efb13bbe0e904babd6f7646dda1885e80b8226 Rebased on top of Master (c584966)

@theStack

Copy link
Copy Markdown
Contributor

Concept ACK

Comment thread src/policy/feerate.cpp Outdated
Comment thread src/policy/feerate.h Outdated
Comment thread src/policy/feerate.cpp Outdated
@polespinasa

Copy link
Copy Markdown
Member Author

db63d5bf81895d78d39fe8cf94ded6f63d81d614 removes an unused include and some nit on arg names.
990010f49ca97479f9fe46e288ed0f0fbb0fde94 modifies the code to use uint instead of ints see #32750 (comment) for context

Comment thread src/policy/feerate.cpp Outdated
Comment thread src/util/feefrac.h Outdated
@polespinasa
polespinasa force-pushed the FeeFracWrapper branch 2 times, most recently from cc894b5 to bf63317 Compare June 26, 2025 15:37
@polespinasa

Copy link
Copy Markdown
Member Author

I think I'll drop bf63317ae7395b0509f86e2c188b1c6cacf995de and revert to only db63d5bf81 (unless someone sees a blocking reason and the need to use uint32 instead of int32).

Changing to uint32 needs many changes in FeeFrac (which I would like to avoid touching). In FeeFrac size is defined as an int32_t so using uint32 doesn't give us any "advantage".

Friendly ping @davidgumberg @Eunovo @sipa to know your opinion :)

@ismaelsadeeq ismaelsadeeq left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK d3b8a54 📦

@theStack theStack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code-review ACK d3b8a54

Comment thread src/policy/feerate.h
Comment on lines -75 to +83
SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.m_feerate.fee, obj.m_feerate.size); }

@theStack theStack Aug 8, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

losely related nit: seems like CFeeRate serialization hasn't been used for more than a decade [1] (other than in the fuzz test) and we could as well just remove it; was shortly looking into that as I was worried that this line could change some file format

[1] AFAICT, the last use was removed in #5159

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#22962 ;)

@achow101

achow101 commented Aug 9, 2025

Copy link
Copy Markdown
Member

ACK d3b8a54

@achow101
achow101 merged commit daca51b into bitcoin:master Aug 9, 2025
alexanderwiederin added a commit to alexanderwiederin/rust-bitcoinkernel that referenced this pull request Aug 11, 2025
…c2c5afd75

39c2c5afd75 kernel: Fix bitcoin-chainstate for windows
b4c1e8b7b6c kernel: Add Purpose section to header documentation
1209f44eba2 kernel: Allowing reducing exports
bd46b323c51 kernel: Add pure kernel bitcoin-chainstate
61653d71a4c kernel: Add functions to get the block hash from a block
681dba7385d kernel: Add block index utility functions to C header
d3099c8896a kernel: Add function to read block undo data from disk to C header
67ab40ed6b3 kernel: Add functions to read block from disk to C header
f4fa216380c kernel: Add function for copying block data to C header
4d6e283e3d3 kernel: Add functions for the block validation state to C header
77429db87f4 kernel: Add validation interface to C header
b0ffc6d3b77 kernel: Add interrupt function to C header
9f889a77270 kernel: Add import blocks function to C header
762bae19dac kernel: Add chainstate load options for in-memory dbs in C header
d087bd8c463 kernel: Add options for reindexing in C header
323189720f3 kernel: Add block validation to C header
6d994d1d78f kernel: Add chainstate loading when instantiating a ChainstateManager
4390e0a3f84 kernel: Add chainstate manager option for setting worker threads
f28e13fab3b kernel: Add chainstate manager object to C header
a75a4234551 kernel: Add notifications context option to C header
5ca40d94ec5 kernel: Add chain params context option to C header
ad870979956 kernel: Add kernel library context object
3490457e805 kernel: Add logging to kernel library C header
040469a30f3 kernel: Introduce initial kernel C header API
daca51bf80e Merge bitcoin/bitcoin#32750: refactor: CFeeRate encapsulates FeeFrac internally
f679bad6052 Merge bitcoin/bitcoin#33105: validation: detect witness stripping without re-running Script checks
63d604af05f Merge bitcoin/bitcoin#33152: Release: Prepare "Open Transifex translations for v30.0" step
27aefac4250 validation: detect witness stripping without re-running Script checks
2907b58834a policy: introduce a helper to detect whether a transaction spends Segwit outputs
26e9db2df07 Merge bitcoin/bitcoin#31886: cli: return local services in -netinfo
2bb06bcaf28 Merge bitcoin/bitcoin#31679: cmake: Install internal binaries to <prefix>/libexec/
6a2bb0fd835 Merge bitcoin/bitcoin#33151: subtree: update crc32c subtree
656e16aa5e6 qt: Update the `src/qt/locale/bitcoin_en.xlf` translation source file
a0eaa449254 Fix typos
b43b8be782b Merge bitcoin/bitcoin#33125: ci: Use mlc `v1` and fix typos
8d4aaaec49c Update Transifex slug for 30.x
8ef8dd6871d Update crc32c subtree to latest upstream master
9a5d29711af Squashed 'src/crc32c/' changes from b60d2b7334..efb8ea04e4
f28a94b40ee ci: update shellcheck to v0.11.0
e46af304416 ci: update mlc to v1
7d60c0eb69b fix typo
49f2f3c89fa doc: fix typos
d818340e7e2 test: Rename shuffled_indeces to shuffled_indices
96f8673b879 doc: fix typos
d767503b6a2 Merge bitcoin/bitcoin#33039: refactor,test: follow-ups to multi-byte block obfuscation
721a051320f test: add coverage for -netinfo header and local services
f7d2db28e90 netinfo: return shortened services, if peers list requested
4489ab526ad netinfo: return local services in the default report
eb073209db9 qa: test witness stripping in p2p_segwit
86e3a0a8cbd refactor: standardize obfuscation memory alignment
13f00345c06 refactor: write `Obfuscation` object when new key is generated in dbwrapper
e5b1b7c5577 refactor: rename `OBFUSCATION_KEY_KEY`
298bf951057 refactor: simplify `Obfuscation::HexKey`
2dea0454254 test: make `obfuscation_serialize` more thorough
a17d8202c36 test: merge xor_roundtrip_random_chunks and xor_bytes_reference
d3b8a54a812 Refactor CFeeRate to use FeeFrac internally
f49840dd902 doc: Fix typo in files.md
f5cf0b1ccc8 bitcoin wrapper: improve help output
c810b168b89 doc: Add description of installed files to files.md
94ffd01a029 doc: Add release notes describing libexec/ binaries
cd97905ebc5 cmake: Move internal binaries from bin/ to libexec/
REVERT: ce8003578e7 kernel: Fix bitcoin-chainstate for windows
REVERT: 9ebe4a83a93 kernel: Add Purpose section to header documentation
REVERT: 10d2432218e kernel: Allowing reducing exports
REVERT: e04b1e1f528 kernel: Add pure kernel bitcoin-chainstate
REVERT: e0f98a533cd kernel: Add functions to get the block hash from a block
REVERT: af1c5e34955 kernel: Add block index utility functions to C header
REVERT: fd60e50badc kernel: Add function to read block undo data from disk to C header
REVERT: f507d230bba kernel: Add functions to read block from disk to C header
REVERT: 1480dd9f41f kernel: Add function for copying block data to C header
REVERT: 26f484b94e6 kernel: Add functions for the block validation state to C header
REVERT: 8c286be14af kernel: Add validation interface to C header
REVERT: 6d733019bba kernel: Add interrupt function to C header
REVERT: c917663b0b5 kernel: Add import blocks function to C header
REVERT: 9c2496406f7 kernel: Add chainstate load options for in-memory dbs in C header
REVERT: 393329899d9 kernel: Add options for reindexing in C header
REVERT: 107156b9362 kernel: Add block validation to C header
REVERT: b83c0d3ba49 kernel: Add chainstate loading when instantiating a ChainstateManager
REVERT: c3279239c75 kernel: Add chainstate manager option for setting worker threads
REVERT: f7a2c3c600e kernel: Add chainstate manager object to C header
REVERT: 5e8b57622c3 kernel: Add notifications context option to C header
REVERT: 56298e76271 kernel: Add chain params context option to C header
REVERT: 9bade37d97d kernel: Add kernel library context object
REVERT: 9859726fbd6 kernel: Add logging to kernel library C header
REVERT: 6dd7a4fcab0 kernel: Introduce initial kernel C header API

git-subtree-dir: libbitcoinkernel-sys/bitcoin
git-subtree-split: 39c2c5afd75e5d455ac2699dcc1c65728e1a5bc5
@hebasto hebasto mentioned this pull request Aug 12, 2025
@fanquake

ghost commented Aug 13, 2025

Copy link
Copy Markdown
Member

As pointed out in #33177, this broke the Guix build. Was fixed in #33178.


const auto tx_bytes{fuzzed_data_provider.ConsumeIntegral<unsigned int>()};

const auto tx_bytes{fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits<int32_t>::max())};

ghost Aug 22, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: any reason to exclude negative values? They are documented to behave as-if 0 was passed, so it seems fine to keep the fuzz coverage for it? (https://maflcko.github.io/b-c-cov/fuzz.coverage/src/policy/feerate.cpp.gcov.html)

(There is a unit test covering it, so just a nit)

ghost Aug 22, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Negatives values would make the code crash because of the Assume introduced in GetFee

Assume(virtual_bytes >= 0);

$ FUZZ=wallet_fees build_fuzz/bin/fuzz
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2952456953
INFO: Loaded 1 modules   (614477 inline 8-bit counters): 614477 [0x5832503883e0, 0x58325041e42d), 
INFO: Loaded 1 PC tables (614477 PCs): 614477 [0x58325041e430,0x583250d7e900), 
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
policy/feerate.cpp:22 GetFee: Assertion `virtual_bytes >= 0' failed.
==89225== ERROR: libFuzzer: deadly signal

The addition of that Assertion was recommended here #32750 (comment) and further discussed here #32750 (comment) and here #32750 (review)

Comment thread src/policy/feerate.cpp

Assume(virtual_bytes >= 0);
if (m_feerate.IsEmpty()) { return CAmount(0);}
CAmount nFee = CAmount(m_feerate.EvaluateFeeUp(virtual_bytes));

ghost Aug 22, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nano nit: The c-style cast isn't needed and the narrowing check can be enabled:

    CAmount nFee{m_feerate.EvaluateFeeUp(virtual_bytes)};

@bitcoin bitcoin locked and limited conversation to collaborators Aug 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.