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::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 weigth 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` on overflow.
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 on overflow.
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 => {
71                // When MSRV is 1.57+ we can use `panic!()`.
72                #[allow(unconditional_panic)]
73                #[allow(clippy::let_unit_value)]
74                #[allow(clippy::out_of_bounds_indexing)]
75                let _int_overflow_scaling_weight = [(); 0][1];
76                Weight(0)
77            }
78        }
79    }
80
81    /// Constructs `Weight` from virtual bytes without an overflow check.
82    pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
83
84    /// Constructs `Weight` from witness size.
85    pub const fn from_witness_data_size(witness_size: u64) -> Self { Weight(witness_size) }
86
87    /// Constructs `Weight` from non-witness size.
88    pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
89        Weight(non_witness_size * Self::WITNESS_SCALE_FACTOR)
90    }
91
92    /// Returns raw weight units.
93    ///
94    /// Can be used instead of `into()` to avoid inference issues.
95    pub const fn to_wu(self) -> u64 { self.0 }
96
97    /// Converts to kilo weight units rounding down.
98    pub const fn to_kwu_floor(self) -> u64 { self.0 / 1000 }
99
100    /// Converts to vB rounding down.
101    pub const fn to_vbytes_floor(self) -> u64 { self.0 / Self::WITNESS_SCALE_FACTOR }
102
103    /// Converts to vB rounding up.
104    pub const fn to_vbytes_ceil(self) -> u64 {
105        (self.0 + Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
106    }
107
108    /// Checked addition.
109    ///
110    /// Computes `self + rhs` returning `None` if an overflow occurred.
111    pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
112
113    /// Checked subtraction.
114    ///
115    /// Computes `self - rhs` returning `None` if an overflow occurred.
116    pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
117
118    /// Checked multiplication.
119    ///
120    /// Computes `self * rhs` returning `None` if an overflow occurred.
121    pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
122
123    /// Checked division.
124    ///
125    /// Computes `self / rhs` returning `None` if `rhs == 0`.
126    pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
127
128    /// Scale by witness factor.
129    ///
130    /// Computes `self * WITNESS_SCALE_FACTOR` returning `None` if an overflow occurred.
131    pub fn scale_by_witness_factor(self) -> Option<Self> {
132        Self::checked_mul(self, Self::WITNESS_SCALE_FACTOR)
133    }
134}
135
136/// Alternative will display the unit.
137impl fmt::Display for Weight {
138    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139        if f.alternate() {
140            write!(f, "{} wu", self.0)
141        } else {
142            fmt::Display::fmt(&self.0, f)
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn weight_constructor() {
153        assert_eq!(Weight::ZERO, Weight::from_wu(0));
154        assert_eq!(Weight::ZERO, Weight::from_wu_usize(0_usize));
155    }
156
157    #[test]
158    fn kilo_weight_constructor() {
159        assert_eq!(Weight(1_000), Weight::from_kwu(1).expect("expected weight unit"));
160    }
161
162    #[test]
163    #[should_panic]
164    fn kilo_weight_constructor_panic() {
165        Weight::from_kwu(u64::MAX).expect("expected weight unit");
166    }
167
168    #[test]
169    fn from_vb() {
170        let vb = Weight::from_vb(1).expect("expected weight unit");
171        assert_eq!(Weight(4), vb);
172
173        let vb = Weight::from_vb(u64::MAX);
174        assert_eq!(None, vb);
175    }
176
177    #[test]
178    fn from_vb_const() {
179        const WU: Weight = Weight::from_vb_unwrap(1);
180        assert_eq!(Weight(4), WU);
181    }
182
183    #[test]
184    fn from_vb_unchecked() {
185        let vb = Weight::from_vb_unchecked(1);
186        assert_eq!(Weight(4), vb);
187    }
188
189    #[test]
190    #[cfg(debug_assertions)]
191    #[should_panic]
192    fn from_vb_unchecked_panic() { Weight::from_vb_unchecked(u64::MAX); }
193
194    #[test]
195    fn from_witness_data_size() {
196        let witness_data_size = 1;
197        assert_eq!(Weight(witness_data_size), Weight::from_witness_data_size(witness_data_size));
198    }
199
200    #[test]
201    fn from_non_witness_data_size() {
202        assert_eq!(Weight(4), Weight::from_non_witness_data_size(1));
203    }
204
205    #[test]
206    fn to_kwu_floor() {
207        assert_eq!(1, Weight(1_000).to_kwu_floor());
208    }
209
210    #[test]
211    fn to_vb_floor() {
212        assert_eq!(1, Weight(4).to_vbytes_floor());
213        assert_eq!(1, Weight(5).to_vbytes_floor());
214    }
215
216    #[test]
217    fn to_vb_ceil() {
218        assert_eq!(1, Weight(4).to_vbytes_ceil());
219        assert_eq!(2, Weight(5).to_vbytes_ceil());
220    }
221
222    #[test]
223    fn checked_add() {
224        let result = Weight(1).checked_add(Weight(1)).expect("expected weight unit");
225        assert_eq!(Weight(2), result);
226
227        let result = Weight::MAX.checked_add(Weight(1));
228        assert_eq!(None, result);
229    }
230
231    #[test]
232    fn checked_sub() {
233        let result = Weight(1).checked_sub(Weight(1)).expect("expected weight unit");
234        assert_eq!(Weight::ZERO, result);
235
236        let result = Weight::MIN.checked_sub(Weight(1));
237        assert_eq!(None, result);
238    }
239
240    #[test]
241    fn checked_mul() {
242        let result = Weight(2).checked_mul(2).expect("expected weight unit");
243        assert_eq!(Weight(4), result);
244
245        let result = Weight::MAX.checked_mul(2);
246        assert_eq!(None, result);
247    }
248
249    #[test]
250    fn checked_div() {
251        let result = Weight(2).checked_div(2).expect("expected weight unit");
252        assert_eq!(Weight(1), result);
253
254        let result = Weight(2).checked_div(0);
255        assert_eq!(None, result);
256    }
257
258    #[test]
259    fn scale_by_witness_factor() {
260        let result = Weight(1).scale_by_witness_factor().expect("expected weight unit");
261        assert_eq!(Weight(4), result);
262
263        let result = Weight::MAX.scale_by_witness_factor();
264        assert_eq!(None, result);
265    }
266}
267
268impl From<Weight> for u64 {
269    fn from(value: Weight) -> Self { value.to_wu() }
270}
271
272impl Add for Weight {
273    type Output = Weight;
274
275    fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
276}
277
278impl AddAssign for Weight {
279    fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
280}
281
282impl Sub for Weight {
283    type Output = Weight;
284
285    fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
286}
287
288impl SubAssign for Weight {
289    fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
290}
291
292impl Mul<u64> for Weight {
293    type Output = Weight;
294
295    fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
296}
297
298impl Mul<Weight> for u64 {
299    type Output = Weight;
300
301    fn mul(self, rhs: Weight) -> Self::Output { Weight(self * rhs.0) }
302}
303
304impl MulAssign<u64> for Weight {
305    fn mul_assign(&mut self, rhs: u64) { self.0 *= rhs }
306}
307
308impl Div<u64> for Weight {
309    type Output = Weight;
310
311    fn div(self, rhs: u64) -> Self::Output { Weight(self.0 / rhs) }
312}
313
314impl Div<Weight> for Weight {
315    type Output = u64;
316
317    fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
318}
319
320impl DivAssign<u64> for Weight {
321    fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
322}
323
324impl core::iter::Sum for Weight {
325    fn sum<I>(iter: I) -> Self
326    where
327        I: Iterator<Item = Self>,
328    {
329        Weight(iter.map(Weight::to_wu).sum())
330    }
331}
332
333impl<'a> core::iter::Sum<&'a Weight> for Weight {
334    fn sum<I>(iter: I) -> Self
335    where
336        I: Iterator<Item = &'a Weight>,
337    {
338        iter.cloned().sum()
339    }
340}
341
342crate::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);
343
344#[cfg(feature = "arbitrary")]
345impl<'a> Arbitrary<'a> for Weight {
346    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
347        let w = u64::arbitrary(u)?;
348        Ok(Weight(w))
349    }
350}