Return NumOpResult for FeeRate and Weight

As we did for `Amount` change the fee functions on `FeeRate` and
`Weight` to return `NumOpResult`.

This change does not add that much value but it does not make things
worse and it makes the API more uniform. Also reduces lines of code.
This commit is contained in:
Tobin C. Harding 2025-06-14 07:44:52 +10:00
parent 15065b78c7
commit 3b0286bd56
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
3 changed files with 12 additions and 28 deletions

View File

@ -27,17 +27,12 @@ use core::ops;
use NumOpResult as R;
use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, Weight};
use crate::{Amount, FeeRate, NumOpResult, Weight};
crate::internal_macros::impl_op_for_references! {
impl ops::Mul<FeeRate> for Weight {
type Output = NumOpResult<Amount>;
fn mul(self, rhs: FeeRate) -> Self::Output {
match rhs.mul_by_weight(self) {
Some(amount) => R::Valid(amount),
None => R::Error(E::while_doing(MathOp::Mul)),
}
}
fn mul(self, rhs: FeeRate) -> Self::Output { rhs.mul_by_weight(self) }
}
impl ops::Mul<FeeRate> for NumOpResult<Weight> {
type Output = NumOpResult<Amount>;
@ -72,12 +67,7 @@ crate::internal_macros::impl_op_for_references! {
impl ops::Mul<Weight> for FeeRate {
type Output = NumOpResult<Amount>;
fn mul(self, rhs: Weight) -> Self::Output {
match self.mul_by_weight(rhs) {
Some(amount) => R::Valid(amount),
None => R::Error(E::while_doing(MathOp::Mul)),
}
}
fn mul(self, rhs: Weight) -> Self::Output { self.mul_by_weight(rhs) }
}
impl ops::Mul<Weight> for NumOpResult<FeeRate> {
type Output = NumOpResult<Amount>;
@ -218,7 +208,7 @@ mod tests {
assert_eq!(Amount::from_sat_u32(100), fee);
let fee = FeeRate::from_sat_per_kwu(10).unwrap().mul_by_weight(Weight::MAX);
assert!(fee.is_none());
assert!(fee.is_error());
let weight = Weight::from_vb(3).unwrap();
let fee_rate = FeeRate::from_sat_per_vb(3).unwrap();

View File

@ -196,8 +196,8 @@ impl FeeRate {
pub const fn to_fee(self, weight: Weight) -> Amount {
// No `unwrap_or()` in const context.
match self.mul_by_weight(weight) {
Some(fee) => fee,
None => Amount::MAX,
NumOpResult::Valid(fee) => fee,
NumOpResult::Error(_) => Amount::MAX,
}
}
@ -207,7 +207,7 @@ impl FeeRate {
/// This is equivalent to `Self::checked_mul_by_weight()`.
#[must_use]
#[deprecated(since = "TBD", note = "use `to_fee()` instead")]
pub fn fee_wu(self, weight: Weight) -> Option<Amount> { self.mul_by_weight(weight) }
pub fn fee_wu(self, weight: Weight) -> Option<Amount> { self.mul_by_weight(weight).ok() }
/// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`]
/// if an overflow occurred.
@ -223,21 +223,18 @@ impl FeeRate {
/// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting
/// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is
/// enough instead of falling short if rounded down.
///
/// Returns [`None`] if overflow occurred.
#[must_use]
pub const fn mul_by_weight(self, weight: Weight) -> Option<Amount> {
pub const fn mul_by_weight(self, weight: Weight) -> NumOpResult<Amount> {
let wu = weight.to_wu();
if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) {
// Bump by 999 to do ceil division using kwu.
if let Some(bump) = fee_kwu.checked_add(999) {
let fee = bump / 1_000;
if let Ok(fee_amount) = Amount::from_sat(fee) {
return Some(fee_amount);
return NumOpResult::Valid(fee_amount);
}
}
}
None
NumOpResult::Error(E::while_doing(MathOp::Mul))
}
}

View File

@ -10,7 +10,7 @@ use arbitrary::{Arbitrary, Unstructured};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{Amount, CheckedSum, FeeRate};
use crate::{Amount, CheckedSum, FeeRate, NumOpResult};
/// The factor that non-witness serialization data is multiplied by during weight calculation.
pub const WITNESS_SCALE_FACTOR: usize = 4;
@ -168,10 +168,7 @@ impl Weight {
/// Computes the absolute fee amount for a given [`FeeRate`] at this weight. When the resulting
/// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is
/// enough instead of falling short if rounded down.
///
/// Returns [`None`] if overflow occurred.
#[must_use]
pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> Option<Amount> {
pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult<Amount> {
fee_rate.mul_by_weight(self)
}
}