use bitcoin::{OutPoint, Script, Transaction, TxIn, TxOut, Witness};
pub(crate) use inner::Weight;
mod inner {
use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
use crate::fee_rate::FeeRate;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct Weight(u64);
impl Weight {
pub(crate) const ZERO: Weight = Weight(0);
pub(crate) fn from_witness_data_size(size: u64) -> Self { Weight(size) }
pub(crate) fn from_non_witness_data_size(size: u64) -> Self { Weight(size * 4) }
pub(crate) fn manual_from_u64(weight: u64) -> Self { Weight(weight) }
}
impl From<Weight> for u64 {
fn from(value: Weight) -> Self { value.0 }
}
impl Add for Weight {
type Output = Weight;
fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
}
impl Sub for Weight {
type Output = Weight;
fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
}
impl AddAssign for Weight {
fn add_assign(&mut self, rhs: Weight) { self.0 += rhs.0 }
}
impl SubAssign for Weight {
fn sub_assign(&mut self, rhs: Weight) { self.0 -= rhs.0 }
}
impl Mul<u64> for Weight {
type Output = Weight;
fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
}
impl Div<Weight> for bitcoin::Amount {
type Output = FeeRate;
fn div(self, rhs: Weight) -> Self::Output {
FeeRate::from_sat_per_wu(self.to_sat() / rhs.0)
}
}
}
pub(crate) fn witness_weight(witness: &Witness) -> Weight {
if witness.is_empty() {
return Weight::ZERO;
}
let mut size = varint_size(witness.len() as u64);
for item in witness.iter() {
size += varint_size(item.len() as u64) + item.len() as u64;
}
Weight::from_witness_data_size(size)
}
pub(crate) trait ComputeWeight {
fn weight(&self) -> Weight;
}
pub(crate) trait ComputeSize {
fn encoded_size(&self) -> u64;
}
pub(crate) fn varint_size(number: u64) -> u64 {
match number {
0..=0xfc => 1,
0xfd..=0xffff => 3,
0x10000..=0xffffffff => 5,
0x100000000..=0xffffffffffffffff => 9,
}
}
impl ComputeSize for Script {
fn encoded_size(&self) -> u64 { self.len() as u64 + varint_size(self.len() as u64) }
}
impl ComputeWeight for TxOut {
fn weight(&self) -> Weight {
Weight::from_non_witness_data_size(
self.script_pubkey.encoded_size() + 8,
)
}
}
impl ComputeWeight for TxIn {
fn weight(&self) -> Weight {
Weight::from_non_witness_data_size(
self.script_sig.encoded_size() + 4,
) + self.previous_output.weight()
+ witness_weight(&self.witness)
}
}
impl ComputeWeight for OutPoint {
fn weight(&self) -> Weight {
Weight::from_non_witness_data_size(
32 + 4,
)
}
}
impl ComputeWeight for Transaction {
fn weight(&self) -> Weight { Weight::manual_from_u64(self.weight() as u64) }
}