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 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! { crate::internal_macros::impl_op_for_references! {
impl ops::Mul<FeeRate> for Weight { impl ops::Mul<FeeRate> for Weight {
type Output = NumOpResult<Amount>; type Output = NumOpResult<Amount>;
fn mul(self, rhs: FeeRate) -> Self::Output { fn mul(self, rhs: FeeRate) -> Self::Output { rhs.mul_by_weight(self) }
match rhs.mul_by_weight(self) {
Some(amount) => R::Valid(amount),
None => R::Error(E::while_doing(MathOp::Mul)),
}
}
} }
impl ops::Mul<FeeRate> for NumOpResult<Weight> { impl ops::Mul<FeeRate> for NumOpResult<Weight> {
type Output = NumOpResult<Amount>; type Output = NumOpResult<Amount>;
@ -72,12 +67,7 @@ crate::internal_macros::impl_op_for_references! {
impl ops::Mul<Weight> for FeeRate { impl ops::Mul<Weight> for FeeRate {
type Output = NumOpResult<Amount>; type Output = NumOpResult<Amount>;
fn mul(self, rhs: Weight) -> Self::Output { fn mul(self, rhs: Weight) -> Self::Output { self.mul_by_weight(rhs) }
match self.mul_by_weight(rhs) {
Some(amount) => R::Valid(amount),
None => R::Error(E::while_doing(MathOp::Mul)),
}
}
} }
impl ops::Mul<Weight> for NumOpResult<FeeRate> { impl ops::Mul<Weight> for NumOpResult<FeeRate> {
type Output = NumOpResult<Amount>; type Output = NumOpResult<Amount>;
@ -218,7 +208,7 @@ mod tests {
assert_eq!(Amount::from_sat_u32(100), fee); assert_eq!(Amount::from_sat_u32(100), fee);
let fee = FeeRate::from_sat_per_kwu(10).unwrap().mul_by_weight(Weight::MAX); 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 weight = Weight::from_vb(3).unwrap();
let fee_rate = FeeRate::from_sat_per_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 { pub const fn to_fee(self, weight: Weight) -> Amount {
// No `unwrap_or()` in const context. // No `unwrap_or()` in const context.
match self.mul_by_weight(weight) { match self.mul_by_weight(weight) {
Some(fee) => fee, NumOpResult::Valid(fee) => fee,
None => Amount::MAX, NumOpResult::Error(_) => Amount::MAX,
} }
} }
@ -207,7 +207,7 @@ impl FeeRate {
/// This is equivalent to `Self::checked_mul_by_weight()`. /// This is equivalent to `Self::checked_mul_by_weight()`.
#[must_use] #[must_use]
#[deprecated(since = "TBD", note = "use `to_fee()` instead")] #[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`] /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`]
/// if an overflow occurred. /// 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 /// 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 /// 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. /// enough instead of falling short if rounded down.
/// pub const fn mul_by_weight(self, weight: Weight) -> NumOpResult<Amount> {
/// Returns [`None`] if overflow occurred.
#[must_use]
pub const fn mul_by_weight(self, weight: Weight) -> Option<Amount> {
let wu = weight.to_wu(); let wu = weight.to_wu();
if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) {
// Bump by 999 to do ceil division using kwu. // Bump by 999 to do ceil division using kwu.
if let Some(bump) = fee_kwu.checked_add(999) { if let Some(bump) = fee_kwu.checked_add(999) {
let fee = bump / 1_000; let fee = bump / 1_000;
if let Ok(fee_amount) = Amount::from_sat(fee) { 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")] #[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; 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. /// The factor that non-witness serialization data is multiplied by during weight calculation.
pub const WITNESS_SCALE_FACTOR: usize = 4; 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 /// 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 /// 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. /// enough instead of falling short if rounded down.
/// pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult<Amount> {
/// Returns [`None`] if overflow occurred.
#[must_use]
pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> Option<Amount> {
fee_rate.mul_by_weight(self) fee_rate.mul_by_weight(self)
} }
} }