Split checked_div_by_weight into floor and ceiling version

This commit is contained in:
yancy 2024-11-06 11:08:41 -06:00
parent 4797a75586
commit 8b928a1515
2 changed files with 42 additions and 9 deletions

View File

@ -140,22 +140,43 @@ fn checked_arithmetic() {
#[cfg(feature = "alloc")]
#[test]
fn amount_checked_div_by_weight() {
fn amount_checked_div_by_weight_ceil() {
let weight = Weight::from_kwu(1).unwrap();
let fee_rate = Amount::from_sat(1).checked_div_by_weight(weight).unwrap();
let fee_rate = Amount::from_sat(1).checked_div_by_weight_ceil(weight).unwrap();
// 1 sats / 1,000 wu = 1 sats/kwu
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1));
let weight = Weight::from_wu(381);
let fee_rate = Amount::from_sat(329).checked_div_by_weight(weight).unwrap();
let fee_rate = Amount::from_sat(329).checked_div_by_weight_ceil(weight).unwrap();
// 329 sats / 381 wu = 863.5 sats/kwu
// round up to 864
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864));
let fee_rate = Amount::MAX.checked_div_by_weight(weight);
let fee_rate = Amount::MAX.checked_div_by_weight_ceil(weight);
assert!(fee_rate.is_none());
let fee_rate = Amount::ONE_SAT.checked_div_by_weight(Weight::ZERO);
let fee_rate = Amount::ONE_SAT.checked_div_by_weight_ceil(Weight::ZERO);
assert!(fee_rate.is_none());
}
#[cfg(feature = "alloc")]
#[test]
fn amount_checked_div_by_weight_floor() {
let weight = Weight::from_kwu(1).unwrap();
let fee_rate = Amount::from_sat(1).checked_div_by_weight_floor(weight).unwrap();
// 1 sats / 1,000 wu = 1 sats/kwu
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1));
let weight = Weight::from_wu(381);
let fee_rate = Amount::from_sat(329).checked_div_by_weight_floor(weight).unwrap();
// 329 sats / 381 wu = 863.5 sats/kwu
// round down to 863
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863));
let fee_rate = Amount::MAX.checked_div_by_weight_floor(weight);
assert!(fee_rate.is_none());
let fee_rate = Amount::ONE_SAT.checked_div_by_weight_floor(Weight::ZERO);
assert!(fee_rate.is_none());
}

View File

@ -231,22 +231,34 @@ impl Amount {
/// Returns [`None`] if overflow occurred.
pub fn checked_div(self, rhs: u64) -> Option<Amount> { self.0.checked_div(rhs).map(Amount) }
/// Checked weight division.
/// Checked weight ceiling division.
///
/// Be aware that integer division loses the remainder if no exact division
/// can be made. This method rounds up ensuring the transaction fee-rate is
/// sufficient. If you wish to round down use `amount / weight`.
/// sufficient. See also [`Amount::checked_div_by_weight_floor`].
///
/// Returns [`None`] if overflow occurred.
#[cfg(feature = "alloc")]
pub fn checked_div_by_weight(self, rhs: Weight) -> Option<FeeRate> {
let sats = self.0.checked_mul(1000)?;
pub fn checked_div_by_weight_ceil(self, rhs: Weight) -> Option<FeeRate> {
let sats = self.0.checked_mul(1_000)?;
let wu = rhs.to_wu();
let fee_rate = sats.checked_add(wu.checked_sub(1)?)?.checked_div(wu)?;
Some(FeeRate::from_sat_per_kwu(fee_rate))
}
/// Checked weight floor division.
///
/// Be aware that integer division loses the remainder if no exact division
/// can be made. See also [`Amount::checked_div_by_weight_ceil`].
///
/// Returns [`None`] if overflow occurred.
#[cfg(feature = "alloc")]
pub fn checked_div_by_weight_floor(self, rhs: Weight) -> Option<FeeRate> {
let fee_rate = self.0.checked_mul(1_000)?.checked_div(rhs.to_wu())?;
Some(FeeRate::from_sat_per_kwu(fee_rate))
}
/// Checked remainder.
///
/// Returns [`None`] if overflow occurred.