Skip to main content

bitcoin_units/
weight.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Implements `Weight` and associated features.
4
5use core::num::NonZeroU64;
6use core::{fmt, ops};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::{Arbitrary, Unstructured};
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12
13use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
14use crate::{Amount, FeeRate, NumOpResult};
15
16/// The factor that non-witness serialization data is multiplied by during weight calculation.
17pub const WITNESS_SCALE_FACTOR: usize = 4;
18
19mod encapsulate {
20    /// The weight of a transaction or block.
21    ///
22    /// This is an integer newtype representing weight in weight units. It provides protection
23    /// against mixing up the types, conversion functions, and basic formatting.
24    #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
25    pub struct Weight(u64);
26
27    impl Weight {
28        /// Constructs a new [`Weight`] from weight units.
29        #[inline]
30        pub const fn from_wu(wu: u64) -> Self { Self(wu) }
31
32        /// Returns raw weight units.
33        ///
34        /// Can be used instead of `into()` to avoid inference issues.
35        #[inline]
36        pub const fn to_wu(self) -> u64 { self.0 }
37    }
38}
39#[doc(inline)]
40pub use encapsulate::Weight;
41
42impl Weight {
43    /// Zero weight units (wu).
44    ///
45    /// Equivalent to [`MIN`](Self::MIN), may better express intent in some contexts.
46    pub const ZERO: Self = Self::from_wu(0);
47
48    /// Minimum possible value (0 wu).
49    ///
50    /// Equivalent to [`ZERO`](Self::ZERO), may better express intent in some contexts.
51    pub const MIN: Self = Self::from_wu(u64::MIN);
52
53    /// Maximum possible value.
54    pub const MAX: Self = Self::from_wu(u64::MAX);
55
56    /// The factor that non-witness serialization data is multiplied by during weight calculation.
57    pub const WITNESS_SCALE_FACTOR: u64 = WITNESS_SCALE_FACTOR as u64; // this value is 4
58
59    /// The maximum allowed weight for a block, see BIP-0141 (network rule).
60    pub const MAX_BLOCK: Self = Self::from_wu(4_000_000);
61
62    /// The minimum transaction weight for a valid serialized transaction.
63    pub const MIN_TRANSACTION: Self = Self::from_wu(Self::WITNESS_SCALE_FACTOR * 60);
64
65    /// Constructs a new [`Weight`] from kilo weight units returning [`None`] if an overflow occurred.
66    #[inline]
67    pub const fn from_kwu(wu: u64) -> Option<Self> {
68        // No `map()` in const context.
69        match wu.checked_mul(1000) {
70            Some(wu) => Some(Self::from_wu(wu)),
71            None => None,
72        }
73    }
74
75    /// Constructs a new [`Weight`] from virtual bytes, returning [`None`] if an overflow occurred.
76    #[inline]
77    pub const fn from_vb(vb: u64) -> Option<Self> {
78        // No `map()` in const context.
79        match vb.checked_mul(Self::WITNESS_SCALE_FACTOR) {
80            Some(wu) => Some(Self::from_wu(wu)),
81            None => None,
82        }
83    }
84
85    /// Constructs a new [`Weight`] from virtual bytes without an overflow check.
86    #[inline]
87    pub const fn from_vb_unchecked(vb: u64) -> Self {
88        Self::from_wu(vb * Self::WITNESS_SCALE_FACTOR)
89    }
90
91    /// Constructs a new `Weight` from a prefixed hex string.
92    ///
93    /// The hex string once parsed is assumed to represent weight units.
94    ///
95    /// # Errors
96    ///
97    /// If the input string is not a valid hex representation of a weight in weight units or it
98    /// does not include the `0x` prefix.
99    #[inline]
100    pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
101        let weight = parse_int::hex_u64_prefixed(s)?;
102        Ok(Self::from_wu(weight))
103    }
104
105    /// Constructs a new `Weight` from an unprefixed hex string.
106    ///
107    /// The hex string once parsed is assumed to represent weight units.
108    ///
109    /// # Errors
110    ///
111    /// If the input string is not a valid hex representation of a weight in weight units or if
112    /// it includes the `0x` prefix.
113    #[inline]
114    pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
115        let weight = parse_int::hex_u64_unprefixed(s)?;
116        Ok(Self::from_wu(weight))
117    }
118
119    /// Converts to kilo weight units rounding down.
120    #[inline]
121    pub const fn to_kwu_floor(self) -> u64 { self.to_wu() / 1000 }
122
123    /// Converts to kilo weight units rounding up.
124    #[inline]
125    pub const fn to_kwu_ceil(self) -> u64 { self.to_wu().div_ceil(1_000) }
126
127    /// Converts to vB rounding down.
128    #[inline]
129    pub const fn to_vbytes_floor(self) -> u64 { self.to_wu() / Self::WITNESS_SCALE_FACTOR }
130
131    /// Converts to vB rounding up.
132    #[inline]
133    pub const fn to_vbytes_ceil(self) -> u64 { self.to_wu().div_ceil(Self::WITNESS_SCALE_FACTOR) }
134
135    /// Checked addition.
136    ///
137    /// Computes `self + rhs` returning [`None`] if an overflow occurred.
138    #[inline]
139    #[must_use]
140    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
141        // No `map()` in const context.
142        match self.to_wu().checked_add(rhs.to_wu()) {
143            Some(wu) => Some(Self::from_wu(wu)),
144            None => None,
145        }
146    }
147
148    /// Checked subtraction.
149    ///
150    /// Computes `self - rhs` returning [`None`] if an overflow occurred.
151    #[inline]
152    #[must_use]
153    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
154        // No `map()` in const context.
155        match self.to_wu().checked_sub(rhs.to_wu()) {
156            Some(wu) => Some(Self::from_wu(wu)),
157            None => None,
158        }
159    }
160
161    /// Checked multiplication.
162    ///
163    /// Computes `self * rhs` returning [`None`] if an overflow occurred.
164    #[inline]
165    #[must_use]
166    pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
167        // No `map()` in const context.
168        match self.to_wu().checked_mul(rhs) {
169            Some(wu) => Some(Self::from_wu(wu)),
170            None => None,
171        }
172    }
173
174    /// Checked division.
175    ///
176    /// Computes `self / rhs` returning [`None`] if `rhs == 0`.
177    #[inline]
178    #[must_use]
179    pub const fn checked_div(self, rhs: u64) -> Option<Self> {
180        // No `map()` in const context.
181        match self.to_wu().checked_div(rhs) {
182            Some(wu) => Some(Self::from_wu(wu)),
183            None => None,
184        }
185    }
186
187    /// Checked fee rate multiplication.
188    ///
189    /// Computes the absolute fee amount for a given [`FeeRate`] at this weight. When the resulting
190    /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is
191    /// enough instead of falling short if rounded down.
192    #[inline]
193    pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult<Amount> {
194        fee_rate.mul_by_weight(self)
195    }
196}
197
198crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(Weight, to_wu);
199
200/// Alternative will display the unit.
201impl fmt::Display for Weight {
202    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203        if f.alternate() {
204            write!(f, "{} wu", self.to_wu())
205        } else {
206            fmt::Display::fmt(&self.to_wu(), f)
207        }
208    }
209}
210
211impl From<Weight> for u64 {
212    #[inline]
213    fn from(value: Weight) -> Self { value.to_wu() }
214}
215
216crate::internal_macros::impl_op_for_references! {
217    impl ops::Add<Weight> for Weight {
218        type Output = Weight;
219
220        fn add(self, rhs: Weight) -> Self::Output { Weight::from_wu(self.to_wu() + rhs.to_wu()) }
221    }
222    impl ops::Sub<Weight> for Weight {
223        type Output = Weight;
224
225        fn sub(self, rhs: Weight) -> Self::Output { Weight::from_wu(self.to_wu() - rhs.to_wu()) }
226    }
227
228    impl ops::Mul<u64> for Weight {
229        type Output = Weight;
230
231        fn mul(self, rhs: u64) -> Self::Output { Weight::from_wu(self.to_wu() * rhs) }
232    }
233    impl ops::Mul<Weight> for u64 {
234        type Output = Weight;
235
236        fn mul(self, rhs: Weight) -> Self::Output { Weight::from_wu(self * rhs.to_wu()) }
237    }
238    impl ops::Div<u64> for Weight {
239        type Output = Weight;
240
241        fn div(self, rhs: u64) -> Self::Output { Weight::from_wu(self.to_wu() / rhs) }
242    }
243    impl ops::Div<Weight> for Weight {
244        type Output = u64;
245
246        fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
247    }
248    impl ops::Rem<u64> for Weight {
249        type Output = Weight;
250
251        fn rem(self, rhs: u64) -> Self::Output { Weight::from_wu(self.to_wu() % rhs) }
252    }
253    impl ops::Rem<Weight> for Weight {
254        type Output = u64;
255
256        fn rem(self, rhs: Weight) -> Self::Output { self.to_wu() % rhs.to_wu() }
257    }
258    impl ops::Div<NonZeroU64> for Weight {
259        type Output = Weight;
260
261        fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_wu(self.to_wu() / rhs.get()) }
262    }
263}
264crate::internal_macros::impl_add_assign!(Weight);
265crate::internal_macros::impl_sub_assign!(Weight);
266
267impl ops::MulAssign<u64> for Weight {
268    #[inline]
269    fn mul_assign(&mut self, rhs: u64) { *self = Self::from_wu(self.to_wu() * rhs); }
270}
271
272impl ops::DivAssign<u64> for Weight {
273    #[inline]
274    fn div_assign(&mut self, rhs: u64) { *self = Self::from_wu(self.to_wu() / rhs); }
275}
276
277impl ops::RemAssign<u64> for Weight {
278    #[inline]
279    fn rem_assign(&mut self, rhs: u64) { *self = Self::from_wu(self.to_wu() % rhs); }
280}
281
282impl core::iter::Sum for Weight {
283    #[inline]
284    fn sum<I>(iter: I) -> Self
285    where
286        I: Iterator<Item = Self>,
287    {
288        Self::from_wu(iter.map(Self::to_wu).sum())
289    }
290}
291
292impl<'a> core::iter::Sum<&'a Self> for Weight {
293    #[inline]
294    fn sum<I>(iter: I) -> Self
295    where
296        I: Iterator<Item = &'a Self>,
297    {
298        iter.copied().sum()
299    }
300}
301
302parse_int::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);
303
304#[cfg(feature = "serde")]
305impl Serialize for Weight {
306    #[inline]
307    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
308    where
309        S: Serializer,
310    {
311        u64::serialize(&self.to_wu(), s)
312    }
313}
314
315#[cfg(feature = "serde")]
316impl<'de> Deserialize<'de> for Weight {
317    #[inline]
318    fn deserialize<D>(d: D) -> Result<Self, D::Error>
319    where
320        D: Deserializer<'de>,
321    {
322        Ok(Self::from_wu(u64::deserialize(d)?))
323    }
324}
325
326#[cfg(feature = "arbitrary")]
327impl<'a> Arbitrary<'a> for Weight {
328    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
329        let w = u64::arbitrary(u)?;
330        Ok(Self::from_wu(w))
331    }
332}
333
334#[cfg(test)]
335mod tests {
336    use core::num::NonZeroU64;
337
338    use super::*;
339
340    const ONE: Weight = Weight::from_wu(1);
341    const TWO: Weight = Weight::from_wu(2);
342    const FOUR: Weight = Weight::from_wu(4);
343
344    #[test]
345    fn sanity_check() {
346        assert_eq!(Weight::MIN_TRANSACTION, Weight::from_wu(240));
347    }
348
349    #[test]
350    #[allow(clippy::op_ref)]
351    fn weight_div_nonzero() {
352        let w = Weight::from_wu(100);
353        let divisor = NonZeroU64::new(4).unwrap();
354        assert_eq!(w / divisor, Weight::from_wu(25));
355        // for borrowed variants
356        assert_eq!(&w / &divisor, Weight::from_wu(25));
357        assert_eq!(w / &divisor, Weight::from_wu(25));
358    }
359
360    #[test]
361    fn from_kwu() {
362        let got = Weight::from_kwu(1).unwrap();
363        let want = Weight::from_wu(1_000);
364        assert_eq!(got, want);
365    }
366
367    #[test]
368    fn from_kwu_overflows() { assert!(Weight::from_kwu(u64::MAX).is_none()) }
369
370    #[test]
371    fn from_vb() {
372        let got = Weight::from_vb(1).unwrap();
373        let want = Weight::from_wu(4);
374        assert_eq!(got, want);
375    }
376
377    #[test]
378    fn from_vb_overflows() {
379        assert!(Weight::from_vb(u64::MAX).is_none());
380    }
381
382    #[test]
383    fn from_vb_unchecked() {
384        let got = Weight::from_vb_unchecked(1);
385        let want = Weight::from_wu(4);
386        assert_eq!(got, want);
387    }
388
389    #[test]
390    #[cfg(debug_assertions)]
391    #[should_panic = "attempt to multiply with overflow"]
392    fn from_vb_unchecked_panic() { Weight::from_vb_unchecked(u64::MAX); }
393
394    #[test]
395    #[cfg(feature = "alloc")]
396    fn try_from_string() {
397        let weight_value: alloc::string::String = "10".into();
398        let got = Weight::try_from(weight_value).unwrap();
399        let want = Weight::from_wu(10);
400        assert_eq!(got, want);
401
402        // Only base-10 integers should parse
403        let weight_value: alloc::string::String = "0xab".into();
404        assert!(Weight::try_from(weight_value).is_err());
405        let weight_value: alloc::string::String = "10.123".into();
406        assert!(Weight::try_from(weight_value).is_err());
407    }
408
409    #[test]
410    #[cfg(feature = "alloc")]
411    fn try_from_box() {
412        let weight_value: alloc::boxed::Box<str> = "10".into();
413        let got = Weight::try_from(weight_value).unwrap();
414        let want = Weight::from_wu(10);
415        assert_eq!(got, want);
416
417        // Only base-10 integers should parse
418        let weight_value: alloc::boxed::Box<str> = "0xab".into();
419        assert!(Weight::try_from(weight_value).is_err());
420        let weight_value: alloc::boxed::Box<str> = "10.123".into();
421        assert!(Weight::try_from(weight_value).is_err());
422    }
423
424    #[test]
425    fn to_kwu_floor() {
426        assert_eq!(Weight::from_wu(5_000).to_kwu_floor(), 5);
427        assert_eq!(Weight::from_wu(5_999).to_kwu_floor(), 5);
428    }
429
430    #[test]
431    fn to_kwu_ceil() {
432        assert_eq!(Weight::from_wu(1_000).to_kwu_ceil(), 1);
433        assert_eq!(Weight::from_wu(1_001).to_kwu_ceil(), 2);
434        assert_eq!(Weight::MAX.to_kwu_ceil(), u64::MAX / 1_000 + 1);
435    }
436
437    #[test]
438    fn to_vb_floor() {
439        assert_eq!(Weight::from_wu(8).to_vbytes_floor(), 2);
440        assert_eq!(Weight::from_wu(9).to_vbytes_floor(), 2);
441    }
442
443    #[test]
444    fn to_vb_ceil() {
445        assert_eq!(Weight::from_wu(4).to_vbytes_ceil(), 1);
446        assert_eq!(Weight::from_wu(5).to_vbytes_ceil(), 2);
447        assert_eq!(Weight::MAX.to_vbytes_ceil(), u64::MAX / Weight::WITNESS_SCALE_FACTOR + 1);
448    }
449
450    #[test]
451    fn checked_add() {
452        assert_eq!(ONE.checked_add(ONE).unwrap(), TWO);
453    }
454
455    #[test]
456    fn checked_add_overflows() { assert!(Weight::MAX.checked_add(ONE).is_none()) }
457
458    #[test]
459    fn checked_sub() {
460        assert_eq!(TWO.checked_sub(ONE).unwrap(), ONE);
461    }
462
463    #[test]
464    fn checked_sub_overflows() { assert!(Weight::ZERO.checked_sub(ONE).is_none()) }
465
466    #[test]
467    fn checked_mul() {
468        assert_eq!(TWO.checked_mul(1).unwrap(), TWO);
469        assert_eq!(TWO.checked_mul(2).unwrap(), FOUR);
470    }
471
472    #[test]
473    fn checked_mul_overflows() { assert!(Weight::MAX.checked_mul(2).is_none()) }
474
475    #[test]
476    fn checked_div() {
477        assert_eq!(FOUR.checked_div(2).unwrap(), TWO);
478        assert_eq!(TWO.checked_div(1).unwrap(), TWO);
479    }
480
481    #[test]
482    fn checked_div_overflows() { assert!(TWO.checked_div(0).is_none()) }
483
484    #[test]
485    #[allow(clippy::op_ref)]
486    fn addition() {
487        let one = Weight::from_wu(1);
488        let two = Weight::from_wu(2);
489        let three = Weight::from_wu(3);
490
491        assert!(one + two == three);
492        assert!(&one + two == three);
493        assert!(one + &two == three);
494        assert!(&one + &two == three);
495    }
496
497    #[test]
498    #[allow(clippy::op_ref)]
499    fn subtract() {
500        let ten = Weight::from_wu(10);
501        let seven = Weight::from_wu(7);
502        let three = Weight::from_wu(3);
503
504        assert_eq!(ten - seven, three);
505        assert_eq!(&ten - seven, three);
506        assert_eq!(ten - &seven, three);
507        assert_eq!(&ten - &seven, three);
508    }
509
510    #[test]
511    #[allow(clippy::op_ref)]
512    fn multiply() {
513        let two = Weight::from_wu(2);
514        let six = Weight::from_wu(6);
515
516        assert_eq!(3_u64 * two, six);
517        assert_eq!(two * 3_u64, six);
518    }
519
520    #[test]
521    fn divide() {
522        let eight = Weight::from_wu(8);
523        let four = Weight::from_wu(4);
524
525        assert_eq!(eight / four, 2_u64);
526        assert_eq!(eight / 4_u64, Weight::from_wu(2));
527    }
528
529    #[test]
530    fn add_assign() {
531        let mut f = Weight::from_wu(1);
532        f += Weight::from_wu(2);
533        assert_eq!(f, Weight::from_wu(3));
534
535        let mut f = Weight::from_wu(1);
536        f += &Weight::from_wu(2);
537        assert_eq!(f, Weight::from_wu(3));
538    }
539
540    #[test]
541    fn sub_assign() {
542        let mut f = Weight::from_wu(3);
543        f -= Weight::from_wu(2);
544        assert_eq!(f, Weight::from_wu(1));
545
546        let mut f = Weight::from_wu(3);
547        f -= &Weight::from_wu(2);
548        assert_eq!(f, Weight::from_wu(1));
549    }
550
551    #[test]
552    fn mul_assign() {
553        let mut w = Weight::from_wu(3);
554        w *= 2_u64;
555        assert_eq!(w, Weight::from_wu(6));
556    }
557
558    #[test]
559    fn div_assign() {
560        let mut w = Weight::from_wu(8);
561        w /= Weight::from_wu(4).into();
562        assert_eq!(w, Weight::from_wu(2));
563    }
564
565    #[test]
566    fn remainder() {
567        let weight10 = Weight::from_wu(10);
568        let weight3 = Weight::from_wu(3);
569
570        let remainder = weight10 % weight3;
571        assert_eq!(remainder, 1);
572
573        let remainder = weight10 % 3;
574        assert_eq!(remainder, Weight::from_wu(1));
575    }
576
577    #[test]
578    fn remainder_assign() {
579        let mut weight = Weight::from_wu(10);
580        weight %= 3;
581        assert_eq!(weight, Weight::from_wu(1));
582    }
583
584    #[test]
585    fn iter_sum() {
586        let values = [
587            Weight::from_wu(10),
588            Weight::from_wu(50),
589            Weight::from_wu(30),
590            Weight::from_wu(5),
591            Weight::from_wu(5),
592        ];
593        let got: Weight = values.into_iter().sum();
594        let want = Weight::from_wu(100);
595        assert_eq!(got, want);
596    }
597
598    #[test]
599    fn iter_sum_ref() {
600        let values = [
601            Weight::from_wu(10),
602            Weight::from_wu(50),
603            Weight::from_wu(30),
604            Weight::from_wu(5),
605            Weight::from_wu(5),
606        ];
607        let got: Weight = values.iter().sum();
608        let want = Weight::from_wu(100);
609        assert_eq!(got, want);
610    }
611
612    #[test]
613    fn iter_sum_empty() {
614        let values: [Weight; 0] = [];
615        let got: Weight = values.into_iter().sum();
616        let want = Weight::from_wu(0);
617        assert_eq!(got, want);
618    }
619}