From f3412325ea0ee7b40984b92b05c056a81de860fb Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 20 Jul 2023 09:32:23 +1000 Subject: [PATCH 1/3] weight: Make docs uniform and terse Make the docs use the same form as everywhere else, which also mimics stdlib docs on integer types. --- bitcoin/src/blockdata/weight.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bitcoin/src/blockdata/weight.rs b/bitcoin/src/blockdata/weight.rs index 0185e983..d066bc54 100644 --- a/bitcoin/src/blockdata/weight.rs +++ b/bitcoin/src/blockdata/weight.rs @@ -43,11 +43,7 @@ impl Weight { /// Constructs `Weight` from kilo weight units returning `None` if overflow occurred. pub fn from_kwu(wu: u64) -> Option { wu.checked_mul(1000).map(Weight) } - /// Constructs `Weight` from virtual bytes. - /// - /// # Errors - /// - /// Returns `None` on overflow. + /// Constructs `Weight` from virtual bytes, returning `None` on overflow. pub fn from_vb(vb: u64) -> Option { vb.checked_mul(4).map(Weight::from_wu) } /// Constructs `Weight` from virtual bytes without overflow check. From f00e93bdcdaecb9c70dcd3cdc8209d944e05c89d Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 2 Aug 2023 08:20:51 +1000 Subject: [PATCH 2/3] Fix typos in rustdoc --- bitcoin/src/blockdata/fee_rate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/blockdata/fee_rate.rs b/bitcoin/src/blockdata/fee_rate.rs index 1a7ccded..6b8c128e 100644 --- a/bitcoin/src/blockdata/fee_rate.rs +++ b/bitcoin/src/blockdata/fee_rate.rs @@ -82,8 +82,8 @@ impl FeeRate { /// Checked weight multiplication. /// - /// Computes `self * rhs` where rhs is of type Weight. `None` is returned if an overflow - /// occured. + /// Computes `self * rhs` where rhs is of type Weight. `None` is returned if an overflow + /// occurred. pub fn checked_mul_by_weight(self, rhs: Weight) -> Option { self.0.checked_mul(rhs.to_wu()).map(Amount::from_sat) } From 9eff2f2f5eb7e00bc646477bba3ace0467f244f4 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 20 Jul 2023 09:33:24 +1000 Subject: [PATCH 3/3] fee_rate: Add public absolute weight convenience functions Calculating the absolute fee from a fee rate can currently be achieved by creating a `Weight` object and using `FeeRate::checked_mul_by_weight`. This is kind of hard to discover, we can add two public convenience functions that make discovery of the functionality easier. Add two functions for calculating the absolute fee by multiplying by weight units (`Weight`) and virtual bytes (by first converting to weight units). --- bitcoin/src/blockdata/fee_rate.rs | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/bitcoin/src/blockdata/fee_rate.rs b/bitcoin/src/blockdata/fee_rate.rs index 6b8c128e..4bb0404e 100644 --- a/bitcoin/src/blockdata/fee_rate.rs +++ b/bitcoin/src/blockdata/fee_rate.rs @@ -87,6 +87,32 @@ impl FeeRate { pub fn checked_mul_by_weight(self, rhs: Weight) -> Option { self.0.checked_mul(rhs.to_wu()).map(Amount::from_sat) } + + /// Calculates fee by multiplying this fee rate by weight, in weight units, returning `None` + /// if overflow occurred. + /// + /// This is equivalent to `Self::checked_mul_by_weight()`. + /// + /// # Examples + /// + /// ```no_run + /// # use bitcoin::{absolute, FeeRate, Transaction}; + /// # // Dummy transaction. + /// # let tx = Transaction { version: 1, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![] }; + /// + /// let rate = FeeRate::from_sat_per_vb(1).expect("1 sat/vbyte is valid"); + /// let fee = rate.fee_wu(tx.weight()); + /// ``` + pub fn fee_wu(self, weight: Weight) -> Option { self.checked_mul_by_weight(weight) } + + /// Calculates fee by multiplying this fee rate by weight, in virtual bytes, returning `None` + /// if overflow occurred. + /// + /// This is equivalent to converting `vb` to `weight` using `Weight::from_vb` and then calling + /// `Self::fee_wu(weight)`. + pub fn fee_vb(self, vb: u64) -> Option { + Weight::from_vb(vb).and_then(|w| self.fee_wu(w)) + } } /// Alternative will display the unit. @@ -199,4 +225,20 @@ mod tests { let fee_rate = FeeRate(10).checked_div(0); assert!(fee_rate.is_none()); } + + #[test] + fn fee_convenience_functions_agree() { + use crate::blockdata::transaction::Transaction; + use crate::consensus::Decodable; + use crate::internal_macros::hex; + + const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; + + let raw_tx = hex!(SOME_TX); + let tx: Transaction = Decodable::consensus_decode(&mut raw_tx.as_slice()).unwrap(); + + let rate = FeeRate::from_sat_per_vb(1).expect("1 sat/byte is valid"); + + assert_eq!(rate.fee_vb(tx.vsize() as u64), rate.fee_wu(tx.weight())); + } }