bitcoin_units/
weight.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Implements `Weight` and associated features.
4
5use core::fmt;
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
7
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11/// The factor that non-witness serialization data is multiplied by during weight calculation.
12pub const WITNESS_SCALE_FACTOR: usize = 4;
13
14/// Represents block weight - the weight of a transaction or block.
15///
16/// This is an integer newtype representing weigth in `wu`. It provides protection against mixing
17/// up the types as well as basic formatting features.
18#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "serde", serde(transparent))]
21pub struct Weight(u64);
22
23impl Weight {
24    /// 0 wu.
25    ///
26    /// Equivalent to [`MIN`](Self::MIN), may better express intent in some contexts.
27    pub const ZERO: Weight = Weight(0);
28
29    /// Minimum possible value (0 wu).
30    ///
31    /// Equivalent to [`ZERO`](Self::ZERO), may better express intent in some contexts.
32    pub const MIN: Weight = Weight(u64::MIN);
33
34    /// Maximum possible value.
35    pub const MAX: Weight = Weight(u64::MAX);
36
37    /// The factor that non-witness serialization data is multiplied by during weight calculation.
38    pub const WITNESS_SCALE_FACTOR: u64 = WITNESS_SCALE_FACTOR as u64;
39
40    /// The maximum allowed weight for a block, see BIP 141 (network rule).
41    pub const MAX_BLOCK: Weight = Weight(4_000_000);
42
43    /// The minimum transaction weight for a valid serialized transaction.
44    pub const MIN_TRANSACTION: Weight = Weight(Self::WITNESS_SCALE_FACTOR * 60);
45
46    /// Directly constructs `Weight` from weight units.
47    pub const fn from_wu(wu: u64) -> Self { Weight(wu) }
48
49    /// Directly constructs `Weight` from usize weight units.
50    pub const fn from_wu_usize(wu: usize) -> Self { Weight(wu as u64) }
51
52    /// Constructs `Weight` from kilo weight units returning `None` if an overflow occurred.
53    pub fn from_kwu(wu: u64) -> Option<Self> { wu.checked_mul(1000).map(Weight) }
54
55    /// Constructs `Weight` from virtual bytes, returning `None` on overflow.
56    pub fn from_vb(vb: u64) -> Option<Self> {
57        vb.checked_mul(Self::WITNESS_SCALE_FACTOR).map(Weight::from_wu)
58    }
59
60    /// Constructs `Weight` from virtual bytes panicking on overflow.
61    ///
62    /// # Panics
63    ///
64    /// If the conversion from virtual bytes overflows.
65    pub const fn from_vb_unwrap(vb: u64) -> Weight {
66        match vb.checked_mul(Self::WITNESS_SCALE_FACTOR) {
67            Some(weight) => Weight(weight),
68            None => {
69                // When MSRV is 1.57+ we can use `panic!()`.
70                #[allow(unconditional_panic)]
71                #[allow(clippy::let_unit_value)]
72                #[allow(clippy::out_of_bounds_indexing)]
73                let _int_overflow_scaling_weight = [(); 0][1];
74                Weight(0)
75            }
76        }
77    }
78
79    /// Constructs `Weight` from virtual bytes without an overflow check.
80    pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
81
82    /// Constructs `Weight` from witness size.
83    pub const fn from_witness_data_size(witness_size: u64) -> Self { Weight(witness_size) }
84
85    /// Constructs `Weight` from non-witness size.
86    pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
87        Weight(non_witness_size * Self::WITNESS_SCALE_FACTOR)
88    }
89
90    /// Returns raw weight units.
91    ///
92    /// Can be used instead of `into()` to avoid inference issues.
93    pub const fn to_wu(self) -> u64 { self.0 }
94
95    /// Converts to kilo weight units rounding down.
96    pub const fn to_kwu_floor(self) -> u64 { self.0 / 1000 }
97
98    /// Converts to vB rounding down.
99    pub const fn to_vbytes_floor(self) -> u64 { self.0 / Self::WITNESS_SCALE_FACTOR }
100
101    /// Converts to vB rounding up.
102    pub const fn to_vbytes_ceil(self) -> u64 {
103        (self.0 + Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
104    }
105
106    /// Checked addition.
107    ///
108    /// Computes `self + rhs` returning `None` if an overflow occurred.
109    pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
110
111    /// Checked subtraction.
112    ///
113    /// Computes `self - rhs` returning `None` if an overflow occurred.
114    pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
115
116    /// Checked multiplication.
117    ///
118    /// Computes `self * rhs` returning `None` if an overflow occurred.
119    pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
120
121    /// Checked division.
122    ///
123    /// Computes `self / rhs` returning `None` if `rhs == 0`.
124    pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
125
126    /// Scale by witness factor.
127    ///
128    /// Computes `self * WITNESS_SCALE_FACTOR` returning `None` if an overflow occurred.
129    pub fn scale_by_witness_factor(self) -> Option<Self> {
130        Self::checked_mul(self, Self::WITNESS_SCALE_FACTOR)
131    }
132}
133
134/// Alternative will display the unit.
135impl fmt::Display for Weight {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        if f.alternate() {
138            write!(f, "{} wu", self.0)
139        } else {
140            fmt::Display::fmt(&self.0, f)
141        }
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn weight_constructor() {
151        assert_eq!(Weight::ZERO, Weight::from_wu(0));
152        assert_eq!(Weight::ZERO, Weight::from_wu_usize(0_usize));
153    }
154
155    #[test]
156    fn kilo_weight_constructor() {
157        assert_eq!(Weight(1_000), Weight::from_kwu(1).expect("expected weight unit"));
158    }
159
160    #[test]
161    #[should_panic]
162    fn kilo_weight_constructor_panic() {
163        Weight::from_kwu(u64::MAX).expect("expected weight unit");
164    }
165
166    #[test]
167    fn from_vb() {
168        let vb = Weight::from_vb(1).expect("expected weight unit");
169        assert_eq!(Weight(4), vb);
170
171        let vb = Weight::from_vb(u64::MAX);
172        assert_eq!(None, vb);
173    }
174
175    #[test]
176    fn from_vb_const() {
177        const WU: Weight = Weight::from_vb_unwrap(1);
178        assert_eq!(Weight(4), WU);
179    }
180
181    #[test]
182    fn from_vb_unchecked() {
183        let vb = Weight::from_vb_unchecked(1);
184        assert_eq!(Weight(4), vb);
185    }
186
187    #[test]
188    #[cfg(debug_assertions)]
189    #[should_panic]
190    fn from_vb_unchecked_panic() { Weight::from_vb_unchecked(u64::MAX); }
191
192    #[test]
193    fn from_witness_data_size() {
194        let witness_data_size = 1;
195        assert_eq!(Weight(witness_data_size), Weight::from_witness_data_size(witness_data_size));
196    }
197
198    #[test]
199    fn from_non_witness_data_size() {
200        assert_eq!(Weight(4), Weight::from_non_witness_data_size(1));
201    }
202
203    #[test]
204    fn to_kwu_floor() {
205        assert_eq!(1, Weight(1_000).to_kwu_floor());
206    }
207
208    #[test]
209    fn to_vb_floor() {
210        assert_eq!(1, Weight(4).to_vbytes_floor());
211        assert_eq!(1, Weight(5).to_vbytes_floor());
212    }
213
214    #[test]
215    fn to_vb_ceil() {
216        assert_eq!(1, Weight(4).to_vbytes_ceil());
217        assert_eq!(2, Weight(5).to_vbytes_ceil());
218    }
219
220    #[test]
221    fn checked_add() {
222        let result = Weight(1).checked_add(Weight(1)).expect("expected weight unit");
223        assert_eq!(Weight(2), result);
224
225        let result = Weight::MAX.checked_add(Weight(1));
226        assert_eq!(None, result);
227    }
228
229    #[test]
230    fn checked_sub() {
231        let result = Weight(1).checked_sub(Weight(1)).expect("expected weight unit");
232        assert_eq!(Weight::ZERO, result);
233
234        let result = Weight::MIN.checked_sub(Weight(1));
235        assert_eq!(None, result);
236    }
237
238    #[test]
239    fn checked_mul() {
240        let result = Weight(2).checked_mul(2).expect("expected weight unit");
241        assert_eq!(Weight(4), result);
242
243        let result = Weight::MAX.checked_mul(2);
244        assert_eq!(None, result);
245    }
246
247    #[test]
248    fn checked_div() {
249        let result = Weight(2).checked_div(2).expect("expected weight unit");
250        assert_eq!(Weight(1), result);
251
252        let result = Weight(2).checked_div(0);
253        assert_eq!(None, result);
254    }
255
256    #[test]
257    fn scale_by_witness_factor() {
258        let result = Weight(1).scale_by_witness_factor().expect("expected weight unit");
259        assert_eq!(Weight(4), result);
260
261        let result = Weight::MAX.scale_by_witness_factor();
262        assert_eq!(None, result);
263    }
264}
265
266impl From<Weight> for u64 {
267    fn from(value: Weight) -> Self { value.to_wu() }
268}
269
270impl Add for Weight {
271    type Output = Weight;
272
273    fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
274}
275
276impl AddAssign for Weight {
277    fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
278}
279
280impl Sub for Weight {
281    type Output = Weight;
282
283    fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
284}
285
286impl SubAssign for Weight {
287    fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
288}
289
290impl Mul<u64> for Weight {
291    type Output = Weight;
292
293    fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
294}
295
296impl Mul<Weight> for u64 {
297    type Output = Weight;
298
299    fn mul(self, rhs: Weight) -> Self::Output { Weight(self * rhs.0) }
300}
301
302impl MulAssign<u64> for Weight {
303    fn mul_assign(&mut self, rhs: u64) { self.0 *= rhs }
304}
305
306impl Div<u64> for Weight {
307    type Output = Weight;
308
309    fn div(self, rhs: u64) -> Self::Output { Weight(self.0 / rhs) }
310}
311
312impl Div<Weight> for Weight {
313    type Output = u64;
314
315    fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
316}
317
318impl DivAssign<u64> for Weight {
319    fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
320}
321
322impl core::iter::Sum for Weight {
323    fn sum<I>(iter: I) -> Self
324    where
325        I: Iterator<Item = Self>,
326    {
327        Weight(iter.map(Weight::to_wu).sum())
328    }
329}
330
331impl<'a> core::iter::Sum<&'a Weight> for Weight {
332    fn sum<I>(iter: I) -> Self
333    where
334        I: Iterator<Item = &'a Weight>,
335    {
336        iter.cloned().sum()
337    }
338}
339
340crate::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);