Merge rust-bitcoin/rust-bitcoin#4235: Use impl_op_for_references macro in fee module

93c6c8cef5 Use impl_op_for_references macro in fee module (Erick Cestari)

Pull request description:

  This pr replaces the individual operator implementations in the fee module with the impl_op_for_references macro to handle reference operations. This removes the need to manually implement reference combinations for operands, simplifying the code and improving consistency.

  ### Changes:
  - Replaces direct implementations of operators with macro usage
  - Adds tests to verify that reference operations work correctly
  - Maintains the same semantics as the original implementation

  Closes #4173

ACKs for top commit:
  tcharding:
    ACK 93c6c8cef5
  apoelstra:
    ACK 93c6c8cef59ceed56932d62daeb212c2b40fc4a1; successfully ran local tests; yeah, I think the docs loss is fine -- the docs are hard to find and say exactly what users expect of the / operator

Tree-SHA512: 51d7643c2cecd16a0cb16afcd195fd87bc9eca9116e16518d888ba61a8edb5684162af987ea52611c9463f5299810f92a057dedc3fa8e89cdef21ef40528bca1
This commit is contained in:
merge-script 2025-03-13 19:37:59 +00:00
commit 2f711b0c07
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 41 additions and 33 deletions

View File

@ -159,26 +159,24 @@ impl FeeRate {
} }
} }
/// Computes the ceiling so that the fee computation is conservative. 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.checked_mul_by_weight(self).valid_or_error() } rhs.checked_mul_by_weight(self).valid_or_error()
}
} }
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.checked_mul_by_weight(rhs).valid_or_error() } self.checked_mul_by_weight(rhs).valid_or_error()
}
} }
impl ops::Div<Weight> for Amount { impl ops::Div<Weight> for Amount {
type Output = FeeRate; type Output = FeeRate;
/// Truncating integer division.
///
/// This is likely the wrong thing for a user dividing an amount by a weight. Consider using
/// `checked_div_by_weight` instead.
fn div(self, rhs: Weight) -> Self::Output { fn div(self, rhs: Weight) -> Self::Output {
FeeRate::from_sat_per_kwu(self.to_sat() * 1000 / rhs.to_wu()) FeeRate::from_sat_per_kwu(self.to_sat() * 1000 / rhs.to_wu())
} }
@ -187,14 +185,10 @@ impl ops::Div<Weight> for Amount {
impl ops::Div<FeeRate> for Amount { impl ops::Div<FeeRate> for Amount {
type Output = Weight; type Output = Weight;
/// Truncating integer division. fn div(self, rhs: FeeRate) -> Self::Output {
/// self.checked_div_by_fee_rate_floor(rhs).unwrap()
/// # Panics }
/// }
/// This operation will panic if `fee_rate` is zero or the division results in overflow.
///
/// Note: This uses floor division. For ceiling division use [`Amount::checked_div_by_fee_rate_ceil`].
fn div(self, rhs: FeeRate) -> Self::Output { self.checked_div_by_fee_rate_floor(rhs).unwrap() }
} }
impl Weight { impl Weight {
@ -265,9 +259,15 @@ mod tests {
let six = Amount::from_sat_unchecked(6); let six = Amount::from_sat_unchecked(6);
assert_eq!(two * three, six.into()); assert_eq!(two * three, six.into());
// Test reference operators
assert_eq!(&two * three, six.into());
assert_eq!(two * &three, six.into());
assert_eq!(&two * &three, six.into());
} }
#[test] #[test]
#[allow(clippy::op_ref)]
fn amount_div_by_fee_rate() { fn amount_div_by_fee_rate() {
// Test exact division // Test exact division
let amount = Amount::from_sat_unchecked(1000); let amount = Amount::from_sat_unchecked(1000);
@ -275,6 +275,14 @@ mod tests {
let weight = amount / fee_rate; let weight = amount / fee_rate;
assert_eq!(weight, Weight::from_wu(500_000)); assert_eq!(weight, Weight::from_wu(500_000));
// Test reference division
let weight_ref = &amount / fee_rate;
assert_eq!(weight_ref, Weight::from_wu(500_000));
let weight_ref2 = amount / &fee_rate;
assert_eq!(weight_ref2, Weight::from_wu(500_000));
let weight_ref3 = &amount / &fee_rate;
assert_eq!(weight_ref3, Weight::from_wu(500_000));
// Test truncation behavior // Test truncation behavior
let amount = Amount::from_sat_unchecked(1000); let amount = Amount::from_sat_unchecked(1000);
let fee_rate = FeeRate::from_sat_per_kwu(3); let fee_rate = FeeRate::from_sat_per_kwu(3);