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