Inline checked div functions back into unsigned module
A while back we move all the 'fee' stuff into a separate module because I thought it would help with clarity - I was wrong. Move the checked div functions back into the `unsigned` module on the main `Amount` impl block. Internal change only - code move.
This commit is contained in:
parent
aab9c2dfca
commit
e17c391a3c
|
@ -15,6 +15,7 @@ use super::{
|
||||||
parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle,
|
parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle,
|
||||||
OutOfRangeError, ParseAmountError, ParseError, SignedAmount,
|
OutOfRangeError, ParseAmountError, ParseError, SignedAmount,
|
||||||
};
|
};
|
||||||
|
use crate::{FeeRate, Weight};
|
||||||
|
|
||||||
mod encapsulate {
|
mod encapsulate {
|
||||||
use super::OutOfRangeError;
|
use super::OutOfRangeError;
|
||||||
|
@ -402,6 +403,106 @@ impl Amount {
|
||||||
SignedAmount::from_sat(self.to_sat() as i64) // Cast ok, signed amount and amount share positive range.
|
SignedAmount::from_sat(self.to_sat() as i64) // Cast ok, signed amount and amount share positive range.
|
||||||
.expect("range of Amount is within range of SignedAmount")
|
.expect("range of Amount is within range of SignedAmount")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checked weight floor division.
|
||||||
|
///
|
||||||
|
/// Be aware that integer division loses the remainder if no exact division
|
||||||
|
/// can be made. See also [`Self::checked_div_by_weight_ceil`].
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if overflow occurred.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option<FeeRate> {
|
||||||
|
let wu = weight.to_wu();
|
||||||
|
if wu == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mul by 1,000 because we use per/kwu.
|
||||||
|
match self.to_sat().checked_mul(1_000) {
|
||||||
|
Some(sats) => {
|
||||||
|
let fee_rate = sats / wu;
|
||||||
|
FeeRate::from_sat_per_kwu(fee_rate)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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. See also [`Self::checked_div_by_weight_floor`].
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if overflow occurred.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bitcoin_units::{amount, Amount, FeeRate, Weight};
|
||||||
|
/// let amount = Amount::from_sat(10)?;
|
||||||
|
/// let weight = Weight::from_wu(300);
|
||||||
|
/// let fee_rate = amount.checked_div_by_weight_ceil(weight);
|
||||||
|
/// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34));
|
||||||
|
/// # Ok::<_, amount::OutOfRangeError>(())
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option<FeeRate> {
|
||||||
|
let wu = weight.to_wu();
|
||||||
|
if wu == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mul by 1,000 because we use per/kwu.
|
||||||
|
if let Some(sats) = self.to_sat().checked_mul(1_000) {
|
||||||
|
// No need to used checked arithmetic because wu is non-zero.
|
||||||
|
if let Some(bump) = sats.checked_add(wu - 1) {
|
||||||
|
let fee_rate = bump / wu;
|
||||||
|
return FeeRate::from_sat_per_kwu(fee_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fee rate floor division.
|
||||||
|
///
|
||||||
|
/// Computes the maximum weight that would result in a fee less than or equal to this amount
|
||||||
|
/// at the given `fee_rate`. Uses floor division to ensure the resulting weight doesn't cause
|
||||||
|
/// the fee to exceed the amount.
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if overflow occurred or if `fee_rate` is zero.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option<Weight> {
|
||||||
|
if let Some(msats) = self.to_sat().checked_mul(1000) {
|
||||||
|
if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) {
|
||||||
|
return Some(Weight::from_wu(wu));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fee rate ceiling division.
|
||||||
|
///
|
||||||
|
/// Computes the minimum weight that would result in a fee greater than or equal to this amount
|
||||||
|
/// at the given `fee_rate`. Uses ceiling division to ensure the resulting weight is sufficient.
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if overflow occurred or if `fee_rate` is zero.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option<Weight> {
|
||||||
|
// Use ceil because result is used as the divisor.
|
||||||
|
let rate = fee_rate.to_sat_per_kwu_ceil();
|
||||||
|
if rate == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(msats) = self.to_sat().checked_mul(1000) {
|
||||||
|
// No need to used checked arithmetic because rate is non-zero.
|
||||||
|
if let Some(bump) = msats.checked_add(rate - 1) {
|
||||||
|
let wu = bump / rate;
|
||||||
|
return Some(Weight::from_wu(wu));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl default::Default for Amount {
|
impl default::Default for Amount {
|
||||||
|
|
102
units/src/fee.rs
102
units/src/fee.rs
|
@ -17,108 +17,6 @@ use NumOpResult as R;
|
||||||
|
|
||||||
use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight};
|
use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight};
|
||||||
|
|
||||||
impl Amount {
|
|
||||||
/// Checked weight floor division.
|
|
||||||
///
|
|
||||||
/// Be aware that integer division loses the remainder if no exact division
|
|
||||||
/// can be made. See also [`Self::checked_div_by_weight_ceil`].
|
|
||||||
///
|
|
||||||
/// Returns [`None`] if overflow occurred.
|
|
||||||
#[must_use]
|
|
||||||
pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option<FeeRate> {
|
|
||||||
let wu = weight.to_wu();
|
|
||||||
if wu == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mul by 1,000 because we use per/kwu.
|
|
||||||
match self.to_sat().checked_mul(1_000) {
|
|
||||||
Some(sats) => {
|
|
||||||
let fee_rate = sats / wu;
|
|
||||||
FeeRate::from_sat_per_kwu(fee_rate)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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. See also [`Self::checked_div_by_weight_floor`].
|
|
||||||
///
|
|
||||||
/// Returns [`None`] if overflow occurred.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitcoin_units::{amount, Amount, FeeRate, Weight};
|
|
||||||
/// let amount = Amount::from_sat(10)?;
|
|
||||||
/// let weight = Weight::from_wu(300);
|
|
||||||
/// let fee_rate = amount.checked_div_by_weight_ceil(weight);
|
|
||||||
/// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34));
|
|
||||||
/// # Ok::<_, amount::OutOfRangeError>(())
|
|
||||||
/// ```
|
|
||||||
#[must_use]
|
|
||||||
pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option<FeeRate> {
|
|
||||||
let wu = weight.to_wu();
|
|
||||||
if wu == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mul by 1,000 because we use per/kwu.
|
|
||||||
if let Some(sats) = self.to_sat().checked_mul(1_000) {
|
|
||||||
// No need to used checked arithmetic because wu is non-zero.
|
|
||||||
if let Some(bump) = sats.checked_add(wu - 1) {
|
|
||||||
let fee_rate = bump / wu;
|
|
||||||
return FeeRate::from_sat_per_kwu(fee_rate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked fee rate floor division.
|
|
||||||
///
|
|
||||||
/// Computes the maximum weight that would result in a fee less than or equal to this amount
|
|
||||||
/// at the given `fee_rate`. Uses floor division to ensure the resulting weight doesn't cause
|
|
||||||
/// the fee to exceed the amount.
|
|
||||||
///
|
|
||||||
/// Returns [`None`] if overflow occurred or if `fee_rate` is zero.
|
|
||||||
#[must_use]
|
|
||||||
pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option<Weight> {
|
|
||||||
if let Some(msats) = self.to_sat().checked_mul(1000) {
|
|
||||||
if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) {
|
|
||||||
return Some(Weight::from_wu(wu));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked fee rate ceiling division.
|
|
||||||
///
|
|
||||||
/// Computes the minimum weight that would result in a fee greater than or equal to this amount
|
|
||||||
/// at the given `fee_rate`. Uses ceiling division to ensure the resulting weight is sufficient.
|
|
||||||
///
|
|
||||||
/// Returns [`None`] if overflow occurred or if `fee_rate` is zero.
|
|
||||||
#[must_use]
|
|
||||||
pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option<Weight> {
|
|
||||||
// Use ceil because result is used as the divisor.
|
|
||||||
let rate = fee_rate.to_sat_per_kwu_ceil();
|
|
||||||
if rate == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(msats) = self.to_sat().checked_mul(1000) {
|
|
||||||
// No need to used checked arithmetic because rate is non-zero.
|
|
||||||
if let Some(bump) = msats.checked_add(rate - 1) {
|
|
||||||
let wu = bump / rate;
|
|
||||||
return Some(Weight::from_wu(wu));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FeeRate {
|
impl FeeRate {
|
||||||
/// Calculates the fee by multiplying this fee rate by weight.
|
/// Calculates the fee by multiplying this fee rate by weight.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue