bitcoin_units/fee_rate/
mod.rs1#[cfg(feature = "serde")]
6pub mod serde;
7
8use core::num::NonZeroU64;
9use core::ops;
10
11#[cfg(feature = "arbitrary")]
12use arbitrary::{Arbitrary, Unstructured};
13use NumOpResult as R;
14
15use crate::result::{MathOp, NumOpError as E, NumOpResult};
16use crate::{Amount, Weight};
17
18mod encapsulate {
19 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
28 pub struct FeeRate(u64);
29
30 impl FeeRate {
31 #[inline]
33 pub(crate) const fn from_sat_per_mvb(sat_mvb: u64) -> Self { Self(sat_mvb) }
34
35 #[inline]
37 pub(crate) const fn to_sat_per_mvb(self) -> u64 { self.0 }
38 }
39}
40#[doc(inline)]
41pub use encapsulate::FeeRate;
42use internals::const_casts;
43
44impl FeeRate {
45 pub const ZERO: Self = Self::from_sat_per_mvb(0);
49
50 pub const MIN: Self = Self::ZERO;
54
55 pub const MAX: Self = Self::from_sat_per_mvb(u64::MAX);
57
58 pub const BROADCAST_MIN: Self = Self::from_sat_per_vb(1);
62
63 pub const DUST: Self = Self::from_sat_per_vb(3);
65
66 #[inline]
68 pub const fn from_sat_per_kwu(sat_kwu: u32) -> Self {
69 let fee_rate = (const_casts::u32_to_u64(sat_kwu)) * 4_000;
70 Self::from_sat_per_mvb(fee_rate)
71 }
72
73 #[inline]
75 pub const fn from_per_kwu(rate: Amount) -> NumOpResult<Self> {
76 match rate.checked_mul(4_000) {
78 Some(per_mvb) => R::Valid(Self::from_sat_per_mvb(per_mvb.to_sat())),
79 None => R::Error(E::while_doing(MathOp::Mul)),
80 }
81 }
82
83 #[inline]
85 pub const fn from_sat_per_vb(sat_vb: u32) -> Self {
86 let fee_rate = (const_casts::u32_to_u64(sat_vb)) * 1_000_000;
87 Self::from_sat_per_mvb(fee_rate)
88 }
89
90 #[inline]
92 pub const fn from_per_vb(rate: Amount) -> NumOpResult<Self> {
93 match rate.checked_mul(1_000_000) {
95 Some(per_mvb) => R::Valid(Self::from_sat_per_mvb(per_mvb.to_sat())),
96 None => R::Error(E::while_doing(MathOp::Mul)),
97 }
98 }
99
100 #[inline]
102 pub const fn from_sat_per_kvb(sat_kvb: u32) -> Self {
103 let fee_rate = (const_casts::u32_to_u64(sat_kvb)) * 1_000;
104 Self::from_sat_per_mvb(fee_rate)
105 }
106
107 #[inline]
109 pub const fn from_per_kvb(rate: Amount) -> NumOpResult<Self> {
110 match rate.checked_mul(1_000) {
112 Some(per_mvb) => R::Valid(Self::from_sat_per_mvb(per_mvb.to_sat())),
113 None => R::Error(E::while_doing(MathOp::Mul)),
114 }
115 }
116
117 #[inline]
119 pub const fn to_sat_per_kwu_floor(self) -> u64 { self.to_sat_per_mvb() / 4_000 }
120
121 #[inline]
123 pub const fn to_sat_per_kwu_ceil(self) -> u64 { self.to_sat_per_mvb().div_ceil(4_000) }
124
125 #[inline]
127 pub const fn to_sat_per_vb_floor(self) -> u64 { self.to_sat_per_mvb() / 1_000_000 }
128
129 #[inline]
131 pub const fn to_sat_per_vb_ceil(self) -> u64 { self.to_sat_per_mvb().div_ceil(1_000_000) }
132
133 #[inline]
135 pub const fn to_sat_per_kvb_floor(self) -> u64 { self.to_sat_per_mvb() / 1_000 }
136
137 #[inline]
139 pub const fn to_sat_per_kvb_ceil(self) -> u64 { self.to_sat_per_mvb().div_ceil(1_000) }
140
141 #[inline]
145 #[must_use]
146 pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
147 match self.to_sat_per_mvb().checked_mul(rhs) {
149 Some(res) => Some(Self::from_sat_per_mvb(res)),
150 None => None,
151 }
152 }
153
154 #[inline]
158 #[must_use]
159 pub const fn checked_div(self, rhs: u64) -> Option<Self> {
160 match self.to_sat_per_mvb().checked_div(rhs) {
162 Some(res) => Some(Self::from_sat_per_mvb(res)),
163 None => None,
164 }
165 }
166
167 #[inline]
171 #[must_use]
172 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
173 match self.to_sat_per_mvb().checked_add(rhs.to_sat_per_mvb()) {
175 Some(res) => Some(Self::from_sat_per_mvb(res)),
176 None => None,
177 }
178 }
179
180 #[inline]
184 #[must_use]
185 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
186 match self.to_sat_per_mvb().checked_sub(rhs.to_sat_per_mvb()) {
188 Some(res) => Some(Self::from_sat_per_mvb(res)),
189 None => None,
190 }
191 }
192
193 #[inline]
203 pub const fn to_fee(self, weight: Weight) -> Amount {
204 match self.mul_by_weight(weight) {
206 NumOpResult::Valid(fee) => fee,
207 NumOpResult::Error(_) => Amount::MAX,
208 }
209 }
210
211 #[must_use]
216 #[deprecated(since = "1.0.0-rc.0", note = "use `to_fee()` instead")]
217 pub fn fee_wu(self, weight: Weight) -> Option<Amount> { self.mul_by_weight(weight).ok() }
218
219 #[must_use]
225 #[deprecated(since = "1.0.0-rc.0", note = "use Weight::from_vb and then `to_fee()` instead")]
226 pub fn fee_vb(self, vb: u64) -> Option<Amount> { Weight::from_vb(vb).map(|w| self.to_fee(w)) }
227
228 pub const fn mul_by_weight(self, weight: Weight) -> NumOpResult<Amount> {
234 let wu = weight.to_wu();
235 if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) {
236 let fee = fee_kwu.div_ceil(1_000);
237 if let Ok(fee_amount) = Amount::from_sat(fee) {
238 return NumOpResult::Valid(fee_amount);
239 }
240 }
241 NumOpResult::Error(E::while_doing(MathOp::Mul))
242 }
243}
244
245crate::internal_macros::impl_op_for_references! {
246 impl ops::Add<FeeRate> for FeeRate {
247 type Output = FeeRate;
248
249 fn add(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_mvb(self.to_sat_per_mvb() + rhs.to_sat_per_mvb()) }
250 }
251
252 impl ops::Sub<FeeRate> for FeeRate {
253 type Output = FeeRate;
254
255 fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_mvb(self.to_sat_per_mvb() - rhs.to_sat_per_mvb()) }
256 }
257
258 impl ops::Div<NonZeroU64> for FeeRate {
259 type Output = FeeRate;
260
261 fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_mvb(self.to_sat_per_mvb() / rhs.get()) }
262 }
263}
264crate::internal_macros::impl_add_assign!(FeeRate);
265crate::internal_macros::impl_sub_assign!(FeeRate);
266
267impl core::iter::Sum for FeeRate {
268 #[inline]
269 fn sum<I>(iter: I) -> Self
270 where
271 I: Iterator<Item = Self>,
272 {
273 Self::from_sat_per_mvb(iter.map(Self::to_sat_per_mvb).sum())
274 }
275}
276
277impl<'a> core::iter::Sum<&'a Self> for FeeRate {
278 #[inline]
279 fn sum<I>(iter: I) -> Self
280 where
281 I: Iterator<Item = &'a Self>,
282 {
283 Self::from_sat_per_mvb(iter.map(|f| Self::to_sat_per_mvb(*f)).sum())
284 }
285}
286
287#[cfg(feature = "arbitrary")]
288impl<'a> Arbitrary<'a> for FeeRate {
289 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
290 let choice = u.int_in_range(0..=4)?;
291 match choice {
292 0 => Ok(Self::MIN),
293 1 => Ok(Self::BROADCAST_MIN),
294 2 => Ok(Self::DUST),
295 3 => Ok(Self::MAX),
296 _ => Ok(Self::from_sat_per_mvb(u64::arbitrary(u)?)),
297 }
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use core::num::NonZeroU64;
304
305 use super::*;
306
307 #[test]
308 #[allow(clippy::op_ref)]
309 fn feerate_div_nonzero() {
310 let rate = FeeRate::from_sat_per_kwu(200);
311 let divisor = NonZeroU64::new(2).unwrap();
312 assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100));
313 assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100));
314 }
315
316 #[test]
317 #[allow(clippy::op_ref)]
318 fn addition() {
319 let one = FeeRate::from_sat_per_kwu(1);
320 let two = FeeRate::from_sat_per_kwu(2);
321 let three = FeeRate::from_sat_per_kwu(3);
322
323 assert!(one + two == three);
324 assert!(&one + two == three);
325 assert!(one + &two == three);
326 assert!(&one + &two == three);
327 }
328
329 #[test]
330 #[allow(clippy::op_ref)]
331 fn subtract() {
332 let three = FeeRate::from_sat_per_kwu(3);
333 let seven = FeeRate::from_sat_per_kwu(7);
334 let ten = FeeRate::from_sat_per_kwu(10);
335
336 assert_eq!(ten - seven, three);
337 assert_eq!(&ten - seven, three);
338 assert_eq!(ten - &seven, three);
339 assert_eq!(&ten - &seven, three);
340 }
341
342 #[test]
343 fn add_assign() {
344 let mut f = FeeRate::from_sat_per_kwu(1);
345 f += FeeRate::from_sat_per_kwu(2);
346 assert_eq!(f, FeeRate::from_sat_per_kwu(3));
347
348 let mut f = FeeRate::from_sat_per_kwu(1);
349 f += &FeeRate::from_sat_per_kwu(2);
350 assert_eq!(f, FeeRate::from_sat_per_kwu(3));
351
352 let mut f = NumOpResult::Valid(FeeRate::from_sat_per_kwu(1));
353 f += FeeRate::from_sat_per_kwu(2);
354 assert_eq!(f, NumOpResult::Valid(FeeRate::from_sat_per_kwu(3)));
355
356 let mut f = NumOpResult::Valid(FeeRate::from_sat_per_kwu(1));
357 f += NumOpResult::Valid(FeeRate::from_sat_per_kwu(2));
358 assert_eq!(f, NumOpResult::Valid(FeeRate::from_sat_per_kwu(3)));
359 }
360
361 #[test]
362 fn sub_assign() {
363 let mut f = FeeRate::from_sat_per_kwu(3);
364 f -= FeeRate::from_sat_per_kwu(2);
365 assert_eq!(f, FeeRate::from_sat_per_kwu(1));
366
367 let mut f = FeeRate::from_sat_per_kwu(3);
368 f -= &FeeRate::from_sat_per_kwu(2);
369 assert_eq!(f, FeeRate::from_sat_per_kwu(1));
370
371 let mut f = NumOpResult::Valid(FeeRate::from_sat_per_kwu(3));
372 f -= FeeRate::from_sat_per_kwu(2);
373 assert_eq!(f, NumOpResult::Valid(FeeRate::from_sat_per_kwu(1)));
374
375 let mut f = NumOpResult::Valid(FeeRate::from_sat_per_kwu(3));
376 f -= NumOpResult::Valid(FeeRate::from_sat_per_kwu(2));
377 assert_eq!(f, NumOpResult::Valid(FeeRate::from_sat_per_kwu(1)));
378 }
379
380 #[test]
381 fn checked_add() {
382 let one = FeeRate::from_sat_per_kwu(1);
383 let two = FeeRate::from_sat_per_kwu(2);
384 let three = FeeRate::from_sat_per_kwu(3);
385
386 assert_eq!(one.checked_add(two).unwrap(), three);
387
388 let _ = FeeRate::from_sat_per_kvb(u32::MAX).checked_add(one).unwrap();
390 let fee_rate = FeeRate::from_sat_per_mvb(u64::MAX).checked_add(one);
391 assert!(fee_rate.is_none());
392 }
393
394 #[test]
395 fn checked_sub() {
396 let one = FeeRate::from_sat_per_kwu(1);
397 let two = FeeRate::from_sat_per_kwu(2);
398 let three = FeeRate::from_sat_per_kwu(3);
399 assert_eq!(three.checked_sub(two).unwrap(), one);
400
401 let fee_rate = FeeRate::ZERO.checked_sub(one);
402 assert!(fee_rate.is_none());
403 }
404
405 #[test]
406 fn fee_rate_const() {
407 assert_eq!(FeeRate::ZERO.to_sat_per_kwu_floor(), 0);
408 assert_eq!(FeeRate::MIN.to_sat_per_kwu_floor(), u64::MIN);
409 assert_eq!(FeeRate::MAX.to_sat_per_kwu_floor(), u64::MAX / 4_000);
410 assert_eq!(FeeRate::BROADCAST_MIN.to_sat_per_kwu_floor(), 250);
411 assert_eq!(FeeRate::DUST.to_sat_per_kwu_floor(), 750);
412 }
413
414 #[test]
415 fn fee_rate_from_sat_per_vb() {
416 let fee_rate = FeeRate::from_sat_per_vb(10);
417 assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500));
418 }
419
420 #[test]
421 fn fee_rate_from_sat_per_kvb() {
422 let fee_rate = FeeRate::from_sat_per_kvb(11);
423 assert_eq!(fee_rate, FeeRate::from_sat_per_mvb(11_000));
424 }
425
426 #[test]
427 fn fee_rate_to_sat_per_x() {
428 let fee_rate = FeeRate::from_sat_per_mvb(2_000_400);
429
430 assert_eq!(fee_rate.to_sat_per_kwu_floor(), 500);
432 assert_eq!(fee_rate.to_sat_per_kwu_ceil(), 501);
433
434 assert_eq!(fee_rate.to_sat_per_vb_floor(), 2);
436 assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3);
437
438 assert_eq!(fee_rate.to_sat_per_kvb_floor(), 2_000);
440 assert_eq!(fee_rate.to_sat_per_kvb_ceil(), 2_001);
441
442 let max = FeeRate::MAX;
443 assert_eq!(max.to_sat_per_kwu_ceil(), u64::MAX / 4_000 + 1);
444 assert_eq!(max.to_sat_per_vb_ceil(), u64::MAX / 1_000_000 + 1);
445 assert_eq!(max.to_sat_per_kvb_ceil(), u64::MAX / 1_000 + 1);
446 }
447
448 #[test]
449 fn checked_mul() {
450 let fee_rate =
451 FeeRate::from_sat_per_kwu(10).checked_mul(10).expect("expected feerate in sat/kwu");
452 assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100));
453
454 let fee_rate = FeeRate::from_sat_per_kwu(10).checked_mul(u64::MAX);
455 assert!(fee_rate.is_none());
456 }
457
458 #[test]
459 fn checked_div() {
460 let fee_rate =
461 FeeRate::from_sat_per_kwu(10).checked_div(10).expect("expected feerate in sat/kwu");
462 assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1));
463
464 let fee_rate = FeeRate::from_sat_per_kwu(10).checked_div(0);
465 assert!(fee_rate.is_none());
466 }
467
468 #[test]
469 fn mvb() {
470 let fee_rate = FeeRate::from_sat_per_mvb(1_234_567);
471 let got = fee_rate.to_sat_per_mvb();
472 assert_eq!(got, 1_234_567);
473 }
474}