You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CFeeRate's two-arg constructor and GetFee() perform internal arithmetic that overflows int64_t for fee amounts anywhere near Raptoreum's MAX_MONEY (21B * COIN = 2.1e18). The constructor in src/policy/feerate.cpp computes:
int64_t::max() / 1000 ≈ 9.2e15, which is ~228x smaller than MAX_MONEY. So any fee amount within roughly the upper 99.5% of the valid CAmount range overflows here, with undefined behaviour. Under signed-overflow sanitizers / -ftrapv builds, this aborts the process.
This was inherited from upstream Bitcoin, where MAX_MONEY = 21M * COIN ≈ 2.1e15, and MAX_MONEY * 1000 ≈ 2.1e18 fits comfortably in int64_t. The 1000x bump to Raptoreum's cap didn't get reflected in CFeeRate.
Real-world impact today is small (no caller passes single-tx fees that large), but:
Defensive arithmetic for consensus-adjacent code is cheap; UB lurking near MAX_MONEY is exactly the kind of thing that becomes a footgun later (e.g. when fuzz-testing or sanitizer CI lands).
Proposed fix
Promote internal arithmetic in CFeeRate::CFeeRate(CAmount, size_t) and CFeeRate::GetFee(size_t) to 128-bit. Two natural options:
__int128 — zero dependencies, supported by GCC/Clang on every platform Raptoreum already targets. Cheapest patch.
boost::multiprecision::int128_t / CAmount128 — already used in the codebase for asset balances (src/amount.h:15). More portable and consistent with existing conventions.
Either way, the public API stays int64_t (CAmount nSatoshisPerK), so only the intermediate multiplication moves to 128-bit. Saturation/clamping behaviour at the API edge can match how CAmount128 is handled elsewhere (AssetsRange etc.).
New boundary cases at MAX_MONEY, MAX_MONEY-1, OLD_MAX_MONEY, and a sanitizer-friendly assertion that the result matches the mathematically correct value (i.e. no silent truncation).
Out of scope for this issue
The matching question for CTxMemPool::GetMinFee() and other fee-arithmetic call sites — those should be audited as a follow-up once CFeeRate is hardened, but they're a separate ticket.
Summary
CFeeRate's two-arg constructor andGetFee()perform internal arithmetic that overflowsint64_tfor fee amounts anywhere near Raptoreum'sMAX_MONEY(21B * COIN = 2.1e18). The constructor insrc/policy/feerate.cppcomputes:int64_t::max() / 1000 ≈ 9.2e15, which is ~228x smaller thanMAX_MONEY. So any fee amount within roughly the upper 99.5% of the validCAmountrange overflows here, with undefined behaviour. Under signed-overflow sanitizers /-ftrapvbuilds, this aborts the process.This was inherited from upstream Bitcoin, where
MAX_MONEY = 21M * COIN ≈ 2.1e15, andMAX_MONEY * 1000 ≈ 2.1e18fits comfortably inint64_t. The 1000x bump to Raptoreum's cap didn't get reflected inCFeeRate.Real-world impact today is small (no caller passes single-tx fees that large), but:
OLD_MAX_MONEY. That's a minimal workaround, not a real fix toCFeeRateitself.MAX_MONEYis exactly the kind of thing that becomes a footgun later (e.g. when fuzz-testing or sanitizer CI lands).Proposed fix
Promote internal arithmetic in
CFeeRate::CFeeRate(CAmount, size_t)andCFeeRate::GetFee(size_t)to 128-bit. Two natural options:__int128— zero dependencies, supported by GCC/Clang on every platform Raptoreum already targets. Cheapest patch.boost::multiprecision::int128_t/CAmount128— already used in the codebase for asset balances (src/amount.h:15). More portable and consistent with existing conventions.Either way, the public API stays
int64_t(CAmount nSatoshisPerK), so only the intermediate multiplication moves to 128-bit. Saturation/clamping behaviour at the API edge can match howCAmount128is handled elsewhere (AssetsRangeetc.).Suggested test additions
amount_tests/GetFeeTest: revert the workaround from test(amount): fix GetFeeTest int64 overflow causing 318-failure cascade #444 and verifyCFeeRate(MAX_MONEY, ...)no longer aborts.MAX_MONEY,MAX_MONEY-1,OLD_MAX_MONEY, and a sanitizer-friendly assertion that the result matches the mathematically correct value (i.e. no silent truncation).Out of scope for this issue
CTxMemPool::GetMinFee()and other fee-arithmetic call sites — those should be audited as a follow-up onceCFeeRateis hardened, but they're a separate ticket.References
src/policy/feerate.cpp— the file that needs hardening.src/amount.h:15—CAmount128typedef used for asset balances; example of the same pattern.