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