satsnet_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 {
48        Weight(wu)
49    }
50
51    /// Directly constructs `Weight` from usize weight units.
52    pub const fn from_wu_usize(wu: usize) -> Self {
53        Weight(wu as u64)
54    }
55
56    /// Constructs `Weight` from kilo weight units returning `None` if an overflow occurred.
57    pub fn from_kwu(wu: u64) -> Option<Self> {
58        wu.checked_mul(1000).map(Weight)
59    }
60
61    /// Constructs `Weight` from virtual bytes, returning `None` on overflow.
62    pub fn from_vb(vb: u64) -> Option<Self> {
63        vb.checked_mul(Self::WITNESS_SCALE_FACTOR)
64            .map(Weight::from_wu)
65    }
66
67    /// Constructs `Weight` from virtual bytes panicking on overflow.
68    ///
69    /// # Panics
70    ///
71    /// If the conversion from virtual bytes overflows.
72    pub const fn from_vb_unwrap(vb: u64) -> Weight {
73        match vb.checked_mul(Self::WITNESS_SCALE_FACTOR) {
74            Some(weight) => Weight(weight),
75            None => {
76                // When MSRV is 1.57+ we can use `panic!()`.
77                #[allow(unconditional_panic)]
78                #[allow(clippy::let_unit_value)]
79                #[allow(clippy::out_of_bounds_indexing)]
80                let _int_overflow_scaling_weight = [(); 0][1];
81                Weight(0)
82            }
83        }
84    }
85
86    /// Constructs `Weight` from virtual bytes without an overflow check.
87    pub const fn from_vb_unchecked(vb: u64) -> Self {
88        Weight::from_wu(vb * 4)
89    }
90
91    /// Constructs `Weight` from witness size.
92    pub const fn from_witness_data_size(witness_size: u64) -> Self {
93        Weight(witness_size)
94    }
95
96    /// Constructs `Weight` from non-witness size.
97    pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
98        Weight(non_witness_size * Self::WITNESS_SCALE_FACTOR)
99    }
100
101    /// Returns raw weight units.
102    ///
103    /// Can be used instead of `into()` to avoid inference issues.
104    pub const fn to_wu(self) -> u64 {
105        self.0
106    }
107
108    /// Converts to kilo weight units rounding down.
109    pub const fn to_kwu_floor(self) -> u64 {
110        self.0 / 1000
111    }
112
113    /// Converts to vB rounding down.
114    pub const fn to_vbytes_floor(self) -> u64 {
115        self.0 / Self::WITNESS_SCALE_FACTOR
116    }
117
118    /// Converts to vB rounding up.
119    pub const fn to_vbytes_ceil(self) -> u64 {
120        (self.0 + Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
121    }
122
123    /// Checked addition.
124    ///
125    /// Computes `self + rhs` returning `None` if an overflow occurred.
126    pub fn checked_add(self, rhs: Self) -> Option<Self> {
127        self.0.checked_add(rhs.0).map(Self)
128    }
129
130    /// Checked subtraction.
131    ///
132    /// Computes `self - rhs` returning `None` if an overflow occurred.
133    pub fn checked_sub(self, rhs: Self) -> Option<Self> {
134        self.0.checked_sub(rhs.0).map(Self)
135    }
136
137    /// Checked multiplication.
138    ///
139    /// Computes `self * rhs` returning `None` if an overflow occurred.
140    pub fn checked_mul(self, rhs: u64) -> Option<Self> {
141        self.0.checked_mul(rhs).map(Self)
142    }
143
144    /// Checked division.
145    ///
146    /// Computes `self / rhs` returning `None` if `rhs == 0`.
147    pub fn checked_div(self, rhs: u64) -> Option<Self> {
148        self.0.checked_div(rhs).map(Self)
149    }
150
151    /// Scale by witness factor.
152    ///
153    /// Computes `self * WITNESS_SCALE_FACTOR` returning `None` if an overflow occurred.
154    pub fn scale_by_witness_factor(self) -> Option<Self> {
155        Self::checked_mul(self, Self::WITNESS_SCALE_FACTOR)
156    }
157}
158
159/// Alternative will display the unit.
160impl fmt::Display for Weight {
161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162        if f.alternate() {
163            write!(f, "{} wu", self.0)
164        } else {
165            fmt::Display::fmt(&self.0, f)
166        }
167    }
168}
169
170impl From<Weight> for u64 {
171    fn from(value: Weight) -> Self {
172        value.to_wu()
173    }
174}
175
176impl Add for Weight {
177    type Output = Weight;
178
179    fn add(self, rhs: Weight) -> Self::Output {
180        Weight(self.0 + rhs.0)
181    }
182}
183
184impl AddAssign for Weight {
185    fn add_assign(&mut self, rhs: Self) {
186        self.0 += rhs.0
187    }
188}
189
190impl Sub for Weight {
191    type Output = Weight;
192
193    fn sub(self, rhs: Weight) -> Self::Output {
194        Weight(self.0 - rhs.0)
195    }
196}
197
198impl SubAssign for Weight {
199    fn sub_assign(&mut self, rhs: Self) {
200        self.0 -= rhs.0
201    }
202}
203
204impl Mul<u64> for Weight {
205    type Output = Weight;
206
207    fn mul(self, rhs: u64) -> Self::Output {
208        Weight(self.0 * rhs)
209    }
210}
211
212impl Mul<Weight> for u64 {
213    type Output = Weight;
214
215    fn mul(self, rhs: Weight) -> Self::Output {
216        Weight(self * rhs.0)
217    }
218}
219
220impl MulAssign<u64> for Weight {
221    fn mul_assign(&mut self, rhs: u64) {
222        self.0 *= rhs
223    }
224}
225
226impl Div<u64> for Weight {
227    type Output = Weight;
228
229    fn div(self, rhs: u64) -> Self::Output {
230        Weight(self.0 / rhs)
231    }
232}
233
234impl Div<Weight> for Weight {
235    type Output = u64;
236
237    fn div(self, rhs: Weight) -> Self::Output {
238        self.to_wu() / rhs.to_wu()
239    }
240}
241
242impl DivAssign<u64> for Weight {
243    fn div_assign(&mut self, rhs: u64) {
244        self.0 /= rhs
245    }
246}
247
248impl core::iter::Sum for Weight {
249    fn sum<I>(iter: I) -> Self
250    where
251        I: Iterator<Item = Self>,
252    {
253        Weight(iter.map(Weight::to_wu).sum())
254    }
255}
256
257impl<'a> core::iter::Sum<&'a Weight> for Weight {
258    fn sum<I>(iter: I) -> Self
259    where
260        I: Iterator<Item = &'a Weight>,
261    {
262        iter.cloned().sum()
263    }
264}
265
266crate::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);