-
Notifications
You must be signed in to change notification settings - Fork 0
fix: Prevent arithmetic overflow and underflow #486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
drafted to rebase on master and remove comment pointed out by Claude review. |
8422ef9 to
3a7afad
Compare
3a7afad to
af89b5e
Compare
af89b5e to
6867479
Compare
6867479 to
c50c402
Compare
Code Review - PR #486: Fix arithmetic overflow and underflowSummaryThis PR addresses a critical bug in unsigned integer arithmetic by introducing a ✅ Strengths1. Excellent Problem Identification 2. Clean Implementation
3. Comprehensive Test Coverage
4. Consistent Migration
🔍 Potential Issues & Suggestions1. Type Safety Concern - High Priority The // Current (requires double wrapping):
val result = afterPendingChannels.safe() - toSavingsAmount.safe()
// Better:
operator fun minus(other: USat): USat =
if (value >= other.value) USat(value - other.value) else USat(0uL)This would enable cleaner chaining: val result = a.safe() - b.safe() - c.safe() // No need to re-wrapImpact: The current implementation works but is less ergonomic and could lead to errors if developers forget to re-wrap intermediate results. 2. Incomplete Migration Check While the PR removes # Check for direct ULong arithmetic that might need safe()
grep -r "ULong.*-.*ULong" --include="*.kt" app/src/main/Some calculations (like fee estimates, percentage calculations) may benefit from saturating arithmetic too. 3. Missing Multiplication/Division The implementation only provides // In TransferViewModel.kt:384
val maxChannelSize2 = maxChannelSize1.safe() - channelsSize.safe()
val maxChannelSizeAvailableToIncrease = min(maxChannelSize1, maxChannelSize2)Consider adding: operator fun times(scalar: ULong): USat = /* saturating multiply */
operator fun div(divisor: ULong): USat = /* saturating divide */4. Edge Case: Addition Overflow Check The overflow check in // Current:
if (value <= ULong.MAX_VALUE - other.value) value + other.value else ULong.MAX_VALUE
// Consider:
val result = value + other.value
if (result < value) ULong.MAX_VALUE else result // Overflow if result wrapped aroundBoth are correct, but the second makes the overflow condition more explicit. 🔒 Security AnalysisNo security concerns identified. This PR actually improves security by:
This is particularly critical for Bitcoin wallet software where arithmetic errors could lead to:
⚡ Performance ConsiderationsExcellent performance characteristics:
📋 Test Coverage AssessmentTest coverage: Excellent (9/10) The test suite covers:
Missing coverage:
Consider adding: @Test
fun `balance calculation with large pending channels`() {
val totalLightning = 100_000uL
val pendingChannels = 150_000uL // More than total!
val result = totalLightning.safe() - pendingChannels.safe()
assertEquals(0uL, result) // Should not wrap around
}🎯 RecommendationsMust Fix:
Should Consider (for follow-up PR):
Nice to Have:
✅ Final VerdictAPPROVED - This is a high-quality fix for a real bug. The implementation is clean, well-tested, and addresses the root cause. The suggestions above are minor improvements that could be addressed in follow-up work. Risk Level: Low - The change is well-isolated and thoroughly tested. Merge Recommendation: ✅ Approve and merge after CI passes. Great work identifying and fixing this subtle bug! The saturating arithmetic approach is the right solution. |
This PR Fixes ULong arithmetic overflow issues when subtracting two values or underflow when summing up two values.
Description
USatvalue class with safe minus operator that returns 0 instead of overflowing(a - b).coerceAtLeast(0u)pattern which overflows before coercionUSatarithmetic behaviorPreview
N/A - No UI changes
QA Notes