1use std::iter::Sum;
23use std::ops::{Add, AddAssign};
24
25use crate::{LenVarInt, ScriptPubkey, SigScript, Tx, TxIn, TxOut, Witness, LIB_NAME_BITCOIN};
26
27#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
28#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
29#[strict_type(lib = LIB_NAME_BITCOIN)]
30#[display("{0} vbytes")]
31pub struct VBytes(u32);
32
33impl Add for VBytes {
34 type Output = Self;
35 fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) }
36}
37
38impl AddAssign for VBytes {
39 fn add_assign(&mut self, rhs: Self) { self.0.add_assign(rhs.0) }
40}
41
42impl Sum for VBytes {
43 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { Self(iter.map(Self::into_u32).sum()) }
44}
45
46impl VBytes {
47 pub fn to_u32(&self) -> u32 { self.0 }
48 pub fn into_u32(self) -> u32 { self.0 }
49}
50
51#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
52#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
53#[strict_type(lib = LIB_NAME_BITCOIN)]
54#[display("{0} WU")]
55pub struct WeightUnits(u32);
56
57impl Add for WeightUnits {
58 type Output = Self;
59 fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) }
60}
61
62impl AddAssign for WeightUnits {
63 fn add_assign(&mut self, rhs: Self) { self.0.add_assign(rhs.0) }
64}
65
66impl Sum for WeightUnits {
67 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { Self(iter.map(Self::into_u32).sum()) }
68}
69
70impl From<WeightUnits> for VBytes {
71 fn from(wu: WeightUnits) -> Self { Self((wu.0 as f32 / 4.0).ceil() as u32) }
72}
73
74impl WeightUnits {
75 pub fn no_discount(bytes: usize) -> Self { WeightUnits(bytes as u32 * 4) }
76 pub fn witness_discount(bytes: usize) -> Self { WeightUnits(bytes as u32) }
77 pub fn to_u32(&self) -> u32 { self.0 }
78 pub fn into_u32(self) -> u32 { self.0 }
79}
80
81pub trait Weight {
82 fn weight_units(&self) -> WeightUnits;
83
84 #[inline]
85 fn vbytes(&self) -> VBytes { VBytes::from(self.weight_units()) }
86}
87
88impl Weight for Tx {
89 fn weight_units(&self) -> WeightUnits {
90 let bytes = 4 + self.inputs.len_var_int().len()
92 + self.outputs.len_var_int().len()
93 + 4; let mut weight = WeightUnits::no_discount(bytes)
96 + self.inputs().map(TxIn::weight_units).sum()
97 + self.outputs().map(TxOut::weight_units).sum();
98 if self.is_segwit() {
99 weight += WeightUnits::witness_discount(2); weight += self.inputs().map(|txin| &txin.witness).map(Witness::weight_units).sum();
101 }
102 weight
103 }
104}
105
106impl Weight for TxIn {
107 fn weight_units(&self) -> WeightUnits {
108 WeightUnits::no_discount(
109 32 + 4 + 4, ) + self.sig_script.weight_units()
113 }
114}
115
116impl Weight for TxOut {
117 fn weight_units(&self) -> WeightUnits {
118 WeightUnits::no_discount(8) + self.script_pubkey.weight_units()
120 }
121}
122
123impl Weight for ScriptPubkey {
124 fn weight_units(&self) -> WeightUnits {
125 WeightUnits::no_discount(self.len_var_int().len() + self.len())
126 }
127}
128
129impl Weight for SigScript {
130 fn weight_units(&self) -> WeightUnits {
131 WeightUnits::no_discount(self.len_var_int().len() + self.len())
132 }
133}
134
135impl Weight for Witness {
136 fn weight_units(&self) -> WeightUnits {
137 WeightUnits::witness_discount(
138 self.len_var_int().len()
139 + self.iter().map(|item| item.len_var_int().len() + item.len()).sum::<usize>(),
140 )
141 }
142}