From a2ff8ddbbbb45492c967c27c89f89205e77cdf0b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 8 May 2025 11:10:57 +1000 Subject: [PATCH 001/857] Improve relative::LockTime is_satisfied_by_{height, time} We recently improved the relative locktime function `is_satisfied_by` by adding mined at and chain tip. We can now do the same for the height/time satisfaction functions. Note I believe these functions should still be provided because a user may for some reason have either blocktime data or height data and not have the other. Requires some work to the errors, elect to just remove the original field that held the function argument. For now remove the examples in rustdocs, we can circle back to these once the dust settles. --- primitives/src/locktime/relative.rs | 96 ++++++++++------------------- 1 file changed, 31 insertions(+), 65 deletions(-) diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index 2c9668d1c5..eee8f0bafd 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -332,61 +332,41 @@ impl LockTime { } } - /// Returns true if this [`relative::LockTime`] is satisfied by [`NumberOfBlocks`]. + /// Returns true if an output with this locktime can be spent in the next block. /// /// # Errors /// /// Returns an error if this lock is not lock-by-height. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::Sequence; - /// # use bitcoin_primitives::relative; - /// - /// let required_height: u16 = 100; - /// let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height"); - /// assert!(lock.is_satisfied_by_height(relative::NumberOfBlocks::from(required_height + 1)).expect("a height")); - /// ``` #[inline] pub fn is_satisfied_by_height( self, - height: NumberOfBlocks, + chain_tip: BlockHeight, + utxo_mined_at: BlockHeight, ) -> Result { use LockTime as L; match self { - L::Blocks(required_height) => Ok(required_height <= height), - L::Time(time) => Err(IncompatibleHeightError { height, time }), + L::Blocks(blocks) => Ok(blocks.is_satisfied_by(chain_tip, utxo_mined_at)), + L::Time(time) => Err(IncompatibleHeightError { time }), } } - /// Returns true if this [`relative::LockTime`] is satisfied by [`Time`]. + /// Returns true if an output with this locktime can be spent in the next block. /// /// # Errors /// /// Returns an error if this lock is not lock-by-time. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::Sequence; - /// # use bitcoin_primitives::relative; - /// - /// let intervals: u16 = 70; // approx 10 hours; - /// let lock = Sequence::from_512_second_intervals(intervals).to_relative_lock_time().expect("valid time"); - /// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time")); - /// ``` #[inline] pub fn is_satisfied_by_time( self, - time: NumberOf512Seconds, + chain_tip: BlockMtp, + utxo_mined_at: BlockMtp, ) -> Result { use LockTime as L; match self { - L::Time(ref t) => Ok(t.to_512_second_intervals() <= time.to_512_second_intervals()), - L::Blocks(height) => Err(IncompatibleTimeError { time, height }), + L::Time(time) => Ok(time.is_satisfied_by(chain_tip, utxo_mined_at)), + L::Blocks(blocks) => Err(IncompatibleTimeError { blocks }), } } } @@ -457,16 +437,11 @@ impl std::error::Error for DisabledLockTimeError {} /// Tried to satisfy a lock-by-blocktime lock using a height value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct IncompatibleHeightError { - /// Attempted to satisfy a lock-by-blocktime lock with this height. - height: NumberOfBlocks, /// The inner time value of the lock-by-blocktime lock. time: NumberOf512Seconds, } impl IncompatibleHeightError { - /// Returns the height that was erroneously used to try and satisfy a lock-by-blocktime lock. - pub fn incompatible(&self) -> NumberOfBlocks { self.height } - /// Returns the time value of the lock-by-blocktime lock. pub fn expected(&self) -> NumberOf512Seconds { self.time } } @@ -474,11 +449,7 @@ impl IncompatibleHeightError { impl fmt::Display for IncompatibleHeightError { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "tried to satisfy a lock-by-blocktime lock {} with height: {}", - self.time, self.height - ) + write!(f, "tried to satisfy a lock-by-blocktime lock {} by height", self.time,) } } @@ -488,28 +459,19 @@ impl std::error::Error for IncompatibleHeightError {} /// Tried to satisfy a lock-by-blockheight lock using a time value. #[derive(Debug, Clone, PartialEq, Eq)] pub struct IncompatibleTimeError { - /// Attempted to satisfy a lock-by-blockheight lock with this time. - time: NumberOf512Seconds, - /// The inner height value of the lock-by-blockheight lock. - height: NumberOfBlocks, + /// The inner value of the lock-by-blockheight lock. + blocks: NumberOfBlocks, } impl IncompatibleTimeError { - /// Returns the time that was erroneously used to try and satisfy a lock-by-blockheight lock. - pub fn incompatible(&self) -> NumberOf512Seconds { self.time } - /// Returns the height value of the lock-by-blockheight lock. - pub fn expected(&self) -> NumberOfBlocks { self.height } + pub fn expected(&self) -> NumberOfBlocks { self.blocks } } impl fmt::Display for IncompatibleTimeError { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "tried to satisfy a lock-by-blockheight lock {} with time: {}", - self.height, self.time - ) + write!(f, "tried to satisfy a lock-by-blockheight lock {} by time", self.blocks,) } } @@ -664,25 +626,29 @@ mod tests { #[test] fn incompatible_height_error() { - let height = NumberOfBlocks::from(10); - let time = NumberOf512Seconds::from_512_second_intervals(70); - let lock_by_time = LockTime::from(time); - let err = lock_by_time.is_satisfied_by_height(height).unwrap_err(); + // This is an error test these values are not used in the error path. + let mined_at = BlockHeight::from_u32(700_000); + let chain_tip = BlockHeight::from_u32(800_000); - assert_eq!(err.incompatible(), height); - assert_eq!(err.expected(), time); + let lock_by_time = LockTime::from_512_second_intervals(70); // Arbitrary value. + let err = lock_by_time.is_satisfied_by_height(chain_tip, mined_at).unwrap_err(); + + let expected_time = NumberOf512Seconds::from_512_second_intervals(70); + assert_eq!(err.expected(), expected_time); assert!(!format!("{}", err).is_empty()); } #[test] fn incompatible_time_error() { - let height = NumberOfBlocks::from(10); - let time = NumberOf512Seconds::from_512_second_intervals(70); - let lock_by_height = LockTime::from(height); - let err = lock_by_height.is_satisfied_by_time(time).unwrap_err(); + // This is an error test these values are not used in the error path. + let mined_at = BlockMtp::from_u32(1_234_567_890); + let chain_tip = BlockMtp::from_u32(1_600_000_000); + + let lock_by_height = LockTime::from_height(10); // Arbitrary value. + let err = lock_by_height.is_satisfied_by_time(chain_tip, mined_at).unwrap_err(); - assert_eq!(err.incompatible(), time); - assert_eq!(err.expected(), height); + let expected_height = NumberOfBlocks::from(10); + assert_eq!(err.expected(), expected_height); assert!(!format!("{}", err).is_empty()); } From 3ffdc54ca5b8e38722a3b42ab69b49cadd586af3 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 12 May 2025 12:17:31 +1000 Subject: [PATCH 002/857] Fix off-by-one bug in relative locktime Define 'is satisfied by' - this is a classic off-by-one problem, if a relative lock is satisfied does that mean it can go in this block or the next? Its most useful if it means 'it can go in the next' and this is how relative height and MTP are used in Core. Ramifications: - When checking a time based lock we check against the chain tip MTP, then when Core verifies a block with the output in it it uses the previous block (and this is still the chain tip). - When checking a height base lock we check against chain tip height + 1 because Core checks against height of the block being verified. Additionally we currently have a false negative in the satisfaction functions when the `crate` type (height or MTP) is to big to fit in a u16 - in this case we should return true not false because a value too big definitely is > the lock value. One final API paper cut - currently if the caller puts the args in the wrong order they get a false negative instead of an error. Fix all this by making the satisfaction functions return errors, update the docs to explicitly define 'satisfaction'. For now remove the examples in rustdocs, we can circle back to these once the dust settles. API test of Errors: Some of the errors are being 'API tested' tested in `primitives` but they should be being done in `units/tests/api.rs` - put all the new errors in the correct places. --- bitcoin/src/blockdata/mod.rs | 2 +- primitives/src/locktime/relative.rs | 260 +++++++++++++++------------- primitives/tests/api.rs | 16 +- units/src/locktime/relative.rs | 117 ++++++++----- units/tests/api.rs | 12 +- 5 files changed, 227 insertions(+), 180 deletions(-) diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs index 9d904a1e1e..13ffc60592 100644 --- a/bitcoin/src/blockdata/mod.rs +++ b/bitcoin/src/blockdata/mod.rs @@ -71,7 +71,7 @@ pub mod locktime { /// Re-export everything from the `primitives::locktime::relative` module. pub use primitives::locktime::relative::{ - DisabledLockTimeError, IncompatibleHeightError, IncompatibleTimeError, LockTime, + DisabledLockTimeError, InvalidHeightError, InvalidTimeError, LockTime, NumberOf512Seconds, NumberOfBlocks, TimeOverflowError, }; diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index eee8f0bafd..343ebd682c 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -7,13 +7,15 @@ use core::{convert, fmt}; +use internals::write_err; + use crate::Sequence; #[cfg(all(doc, feature = "alloc"))] use crate::{relative, TxIn}; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] -pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds, TimeOverflowError}; +pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds, TimeOverflowError, InvalidHeightError, InvalidTimeError}; use units::{BlockHeight, BlockMtp}; #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] @@ -39,40 +41,6 @@ pub type Time = NumberOf512Seconds; /// /// * [BIP 68 Relative lock-time using consensus-enforced sequence numbers](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) /// * [BIP 112 CHECKSEQUENCEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) -/// -/// # Examples -/// -/// ``` -/// use bitcoin_primitives::relative; -/// use bitcoin_primitives::{BlockHeight, BlockMtp, BlockTime}; -/// let lock_by_height = relative::LockTime::from_height(144); // 144 blocks, approx 24h. -/// assert!(lock_by_height.is_block_height()); -/// -/// let lock_by_time = relative::LockTime::from_512_second_intervals(168); // 168 time intervals, approx 24h. -/// assert!(lock_by_time.is_block_time()); -/// -/// fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] { -/// let mut timestamps = [BlockTime::from_u32(0); 11]; -/// for (i, ts) in timestamps.iter_mut().enumerate() { -/// *ts = BlockTime::from_u32(start.saturating_sub((step * i as u16).into())); -/// } -/// timestamps -/// } -/// // time extracted from BlockHeader -/// let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200); -/// let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200); -/// -/// let current_height = BlockHeight::from(100); -/// let current_mtp = BlockMtp::new(timestamps); -/// -/// let utxo_height = BlockHeight::from(80); -/// let utxo_mtp = BlockMtp::new(utxo_timestamps); -/// -/// let locktime = relative::LockTime::Time(relative::NumberOf512Seconds::from_512_second_intervals(10)); -/// -/// // Check if locktime is satisfied -/// assert!(locktime.is_satisfied_by(current_height, current_mtp, utxo_height, utxo_mtp)); -/// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum LockTime { @@ -221,45 +189,27 @@ impl LockTime { pub const fn is_block_time(self) -> bool { !self.is_block_height() } /// Returns true if this [`relative::LockTime`] is satisfied by the given chain state. - /// # Examples /// - /// ```rust - /// # use bitcoin_primitives::relative::Time; - /// # use bitcoin_primitives::{BlockHeight, BlockMtp, BlockTime}; - /// # use bitcoin_primitives::relative::LockTime; - /// - /// fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] { - /// let mut timestamps = [BlockTime::from_u32(0); 11]; - /// for (i, ts) in timestamps.iter_mut().enumerate() { - /// *ts = BlockTime::from_u32(start.saturating_sub((step * i as u16).into())); - /// } - /// timestamps - /// } - /// // time extracted from BlockHeader - /// let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200); - /// let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200); - /// - /// let current_height = BlockHeight::from_u32(100); - /// let current_mtp = BlockMtp::new(timestamps); - /// let utxo_height = BlockHeight::from_u32(80); - /// let utxo_mtp = BlockMtp::new(utxo_timestamps); - /// - /// let locktime = LockTime::Time(Time::from_512_second_intervals(10)); - /// - /// // Check if locktime is satisfied - /// assert!(locktime.is_satisfied_by(current_height, current_mtp, utxo_height, utxo_mtp)); - /// ``` + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// + /// # Errors + /// + /// If `chain_tip` as not _after_ `utxo_mined_at` i.e., if you get the args mixed up. pub fn is_satisfied_by( self, chain_tip_height: BlockHeight, chain_tip_mtp: BlockMtp, utxo_mined_at_height: BlockHeight, utxo_mined_at_mtp: BlockMtp, - ) -> bool { + ) -> Result { match self { - LockTime::Blocks(blocks) => - blocks.is_satisfied_by(chain_tip_height, utxo_mined_at_height), - LockTime::Time(time) => time.is_satisfied_by(chain_tip_mtp, utxo_mined_at_mtp), + LockTime::Blocks(blocks) => blocks + .is_satisfied_by(chain_tip_height, utxo_mined_at_height) + .map_err(IsSatisfiedByError::Blocks), + LockTime::Time(time) => time + .is_satisfied_by(chain_tip_mtp, utxo_mined_at_mtp) + .map_err(IsSatisfiedByError::Time), } } @@ -334,6 +284,9 @@ impl LockTime { /// Returns true if an output with this locktime can be spent in the next block. /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// /// # Errors /// /// Returns an error if this lock is not lock-by-height. @@ -342,17 +295,22 @@ impl LockTime { self, chain_tip: BlockHeight, utxo_mined_at: BlockHeight, - ) -> Result { + ) -> Result { use LockTime as L; match self { - L::Blocks(blocks) => Ok(blocks.is_satisfied_by(chain_tip, utxo_mined_at)), - L::Time(time) => Err(IncompatibleHeightError { time }), + L::Blocks(blocks) => blocks + .is_satisfied_by(chain_tip, utxo_mined_at) + .map_err(IsSatisfiedByHeightError::Satisfaction), + L::Time(time) => Err(IsSatisfiedByHeightError::Incompatible(time)), } } /// Returns true if an output with this locktime can be spent in the next block. /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// /// # Errors /// /// Returns an error if this lock is not lock-by-time. @@ -361,12 +319,14 @@ impl LockTime { self, chain_tip: BlockMtp, utxo_mined_at: BlockMtp, - ) -> Result { + ) -> Result { use LockTime as L; match self { - L::Time(time) => Ok(time.is_satisfied_by(chain_tip, utxo_mined_at)), - L::Blocks(blocks) => Err(IncompatibleTimeError { blocks }), + L::Time(time) => time + .is_satisfied_by(chain_tip, utxo_mined_at) + .map_err(IsSatisfiedByTimeError::Satisfaction), + L::Blocks(blocks) => Err(IsSatisfiedByTimeError::Incompatible(blocks)), } } } @@ -434,49 +394,108 @@ impl fmt::Display for DisabledLockTimeError { #[cfg(feature = "std")] impl std::error::Error for DisabledLockTimeError {} -/// Tried to satisfy a lock-by-blocktime lock using a height value. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IncompatibleHeightError { - /// The inner time value of the lock-by-blocktime lock. - time: NumberOf512Seconds, +/// Error returned when attempting to satisfy lock fails. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum IsSatisfiedByError { + /// Error when attempting to satisfy lock by height. + Blocks(InvalidHeightError), + /// Error when attempting to satisfy lock by time. + Time(InvalidTimeError), } -impl IncompatibleHeightError { - /// Returns the time value of the lock-by-blocktime lock. - pub fn expected(&self) -> NumberOf512Seconds { self.time } +impl fmt::Display for IsSatisfiedByError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use IsSatisfiedByError as E; + + match *self { + E::Blocks(ref e) => write_err!(f, "blocks"; e), + E::Time(ref e) => write_err!(f, "time"; e), + } + } } -impl fmt::Display for IncompatibleHeightError { +#[cfg(feature = "std")] +impl std::error::Error for IsSatisfiedByError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use IsSatisfiedByError as E; + + match *self { + E::Blocks(ref e) => Some(e), + E::Time(ref e) => Some(e), + } + } +} + +/// Error returned when `is_satisfied_by_height` fails. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum IsSatisfiedByHeightError { + /// Satisfaction of the lock height value failed. + Satisfaction(InvalidHeightError), + /// Tried to satisfy a lock-by-height locktime using seconds. + // TODO: Hide inner value in a new struct error type. + Incompatible(NumberOf512Seconds), +} + +impl fmt::Display for IsSatisfiedByHeightError { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "tried to satisfy a lock-by-blocktime lock {} by height", self.time,) + use IsSatisfiedByHeightError as E; + + match *self { + E::Satisfaction(ref e) => write_err!(f, "satisfaction"; e), + E::Incompatible(time) => + write!(f, "tried to satisfy a lock-by-height locktime using seconds {}", time), + } } } #[cfg(feature = "std")] -impl std::error::Error for IncompatibleHeightError {} +impl std::error::Error for IsSatisfiedByHeightError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use IsSatisfiedByHeightError as E; -/// Tried to satisfy a lock-by-blockheight lock using a time value. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IncompatibleTimeError { - /// The inner value of the lock-by-blockheight lock. - blocks: NumberOfBlocks, + match *self { + E::Satisfaction(ref e) => Some(e), + E::Incompatible(_) => None, + } + } } -impl IncompatibleTimeError { - /// Returns the height value of the lock-by-blockheight lock. - pub fn expected(&self) -> NumberOfBlocks { self.blocks } +/// Error returned when `is_satisfied_by_time` fails. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum IsSatisfiedByTimeError { + /// Satisfaction of the lock time value failed. + Satisfaction(InvalidTimeError), + /// Tried to satisfy a lock-by-time locktime using number of blocks. + // TODO: Hide inner value in a new struct error type. + Incompatible(NumberOfBlocks), } -impl fmt::Display for IncompatibleTimeError { +impl fmt::Display for IsSatisfiedByTimeError { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "tried to satisfy a lock-by-blockheight lock {} by time", self.blocks,) + use IsSatisfiedByTimeError as E; + + match *self { + E::Satisfaction(ref e) => write_err!(f, "satisfaction"; e), + E::Incompatible(blocks) => + write!(f, "tried to satisfy a lock-by-height locktime using blocks {}", blocks), + } } } #[cfg(feature = "std")] -impl std::error::Error for IncompatibleTimeError {} +impl std::error::Error for IsSatisfiedByTimeError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use IsSatisfiedByTimeError as E; + + match *self { + E::Satisfaction(ref e) => Some(e), + E::Incompatible(_) => None, + } + } +} #[cfg(test)] mod tests { @@ -634,7 +653,7 @@ mod tests { let err = lock_by_time.is_satisfied_by_height(chain_tip, mined_at).unwrap_err(); let expected_time = NumberOf512Seconds::from_512_second_intervals(70); - assert_eq!(err.expected(), expected_time); + assert_eq!(err, IsSatisfiedByHeightError::Incompatible(expected_time)); assert!(!format!("{}", err).is_empty()); } @@ -648,7 +667,7 @@ mod tests { let err = lock_by_height.is_satisfied_by_time(chain_tip, mined_at).unwrap_err(); let expected_height = NumberOfBlocks::from(10); - assert_eq!(err.expected(), expected_height); + assert_eq!(err, IsSatisfiedByTimeError::Incompatible(expected_height)); assert!(!format!("{}", err).is_empty()); } @@ -671,49 +690,46 @@ mod tests { let utxo_mtp = BlockMtp::new(utxo_timestamps); let lock1 = LockTime::Blocks(NumberOfBlocks::from(10)); - assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); let lock2 = LockTime::Blocks(NumberOfBlocks::from(21)); - assert!(!lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); let lock3 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(10)); - assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); let lock4 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(20000)); - assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); - assert!(LockTime::ZERO.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); - assert!(LockTime::from_512_second_intervals(0).is_satisfied_by( - chain_height, - chain_mtp, - utxo_height, - utxo_mtp - )); + assert!(LockTime::ZERO + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); + assert!(LockTime::from_512_second_intervals(0) + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); let lock6 = LockTime::from_seconds_floor(5000).unwrap(); - assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); let max_height_lock = LockTime::Blocks(NumberOfBlocks::MAX); - assert!(!max_height_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(!max_height_lock + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); let max_time_lock = LockTime::Time(NumberOf512Seconds::MAX); - assert!(!max_time_lock.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp)); + assert!(!max_time_lock + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); let max_chain_height = BlockHeight::from_u32(u32::MAX); let max_chain_mtp = BlockMtp::new(generate_timestamps(u32::MAX, 100)); let max_utxo_height = BlockHeight::MAX; let max_utxo_mtp = max_chain_mtp; - assert!(!max_height_lock.is_satisfied_by( - max_chain_height, - max_chain_mtp, - max_utxo_height, - max_utxo_mtp - )); - assert!(!max_time_lock.is_satisfied_by( - max_chain_height, - max_chain_mtp, - max_utxo_height, - max_utxo_mtp - )); + assert!(!max_height_lock + .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp) + .unwrap()); + assert!(!max_time_lock + .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp) + .unwrap()); } } diff --git a/primitives/tests/api.rs b/primitives/tests/api.rs index 913089cdbd..b03a7611b1 100644 --- a/primitives/tests/api.rs +++ b/primitives/tests/api.rs @@ -163,14 +163,12 @@ struct Default { #[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG). struct Errors { a: transaction::ParseOutPointError, - b: relative::IncompatibleHeightError, - c: relative::IncompatibleTimeError, - d: relative::IncompatibleHeightError, - e: relative::IncompatibleTimeError, - f: relative::DisabledLockTimeError, - g: relative::DisabledLockTimeError, - h: script::RedeemScriptSizeError, - i: script::WitnessScriptSizeError, + b: relative::DisabledLockTimeError, + c: relative::IsSatisfiedByError, + d: relative::IsSatisfiedByHeightError, + e: relative::IsSatisfiedByTimeError, + f: script::RedeemScriptSizeError, + g: script::WitnessScriptSizeError, } #[test] @@ -212,7 +210,7 @@ fn api_can_use_types_from_crate_root() { #[test] fn api_can_use_all_types_from_module_locktime() { use bitcoin_primitives::locktime::relative::{ - DisabledLockTimeError, IncompatibleHeightError, IncompatibleTimeError, LockTime, + DisabledLockTimeError, InvalidHeightError, InvalidTimeError, LockTime, }; use bitcoin_primitives::locktime::{absolute, relative}; } diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 6bd5e6c134..1fb3db1db4 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -55,29 +55,27 @@ impl NumberOfBlocks { self.0 as u32 // cast safety: u32 is wider than u16 on all architectures } - /// Determines whether a relative‐height locktime has matured, taking into account - /// both the chain tip and the height at which the UTXO was confirmed. + /// Returns true if an output locked by height can be spent in the next block. /// - /// If you have two height intervals `x` and `y`, and want to know whether `x` - /// is satisfied by `y`, use `x >= y`. - /// - /// # Parameters - /// - `self` – the relative block‐height delay (`h`) required after confirmation. - /// - `chain_tip` – the height of the current chain tip - /// - `utxo_mined_at` – the height of the UTXO’s confirmation block + /// # Errors /// - /// # Returns - /// - `true` if a UTXO locked by `self` can be spent in a block after `chain_tip`. - /// - `false` if the UTXO is still locked at `chain_tip`. + /// If `chain_tip` as not _after_ `utxo_mined_at` i.e., if you get the args mixed up. pub fn is_satisfied_by( self, chain_tip: crate::BlockHeight, utxo_mined_at: crate::BlockHeight, - ) -> bool { - chain_tip - .checked_sub(utxo_mined_at) - .and_then(|diff: crate::BlockHeightInterval| diff.try_into().ok()) - .map_or(false, |diff: Self| diff >= self) + ) -> Result { + match chain_tip.checked_sub(utxo_mined_at) { + Some(diff) => { + if diff.to_u32() == u32::MAX { + // Weird but ok none the less - protects against overflow below. + return Ok(true); + } + // +1 because the next block will have height 1 higher than `chain_tip`. + Ok(u32::from(self.to_height()) <= diff.to_u32() + 1) + } + None => Err(InvalidHeightError { chain_tip, utxo_mined_at }), + } } } @@ -181,29 +179,24 @@ impl NumberOf512Seconds { (1u32 << 22) | self.0 as u32 // cast safety: u32 is wider than u16 on all architectures } - /// Determines whether a relative‑time lock has matured, taking into account both - /// the UTXO’s Median Time Past at confirmation and the required delay. - /// - /// If you have two MTP intervals `x` and `y`, and want to know whether `x` - /// is satisfied by `y`, use `x >= y`. + /// Returns true if an output locked by time can be spent in the next block. /// - /// # Parameters - /// - `self` – the relative time delay (`t`) in 512‑second intervals. - /// - `chain_tip` – the MTP of the current chain tip - /// - `utxo_mined_at` – the MTP of the UTXO’s confirmation block + /// # Errors /// - /// # Returns - /// - `true` if the relative‐time lock has expired by the tip’s MTP - /// - `false` if the lock has not yet expired by the tip’s MTP + /// If `chain_tip` as not _after_ `utxo_mined_at` i.e., if you get the args mixed up. pub fn is_satisfied_by( self, chain_tip: crate::BlockMtp, utxo_mined_at: crate::BlockMtp, - ) -> bool { - chain_tip - .checked_sub(utxo_mined_at) - .and_then(|diff: crate::BlockMtpInterval| diff.to_relative_mtp_interval_floor().ok()) - .map_or(false, |diff: Self| diff >= self) + ) -> Result { + match chain_tip.checked_sub(utxo_mined_at) { + Some(diff) => { + // The locktime check in Core during block validation uses the MTP of the previous + // block - which is `chain_tip` here. + Ok(self.to_seconds() <= diff.to_u32()) + } + None => Err(InvalidTimeError { chain_tip, utxo_mined_at }), + } } } @@ -246,6 +239,44 @@ impl fmt::Display for TimeOverflowError { #[cfg(feature = "std")] impl std::error::Error for TimeOverflowError {} +/// Error returned when `NumberOfBlocks::is_satisfied_by` is incorrectly called. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidHeightError { + /// The `chain_tip` argument. + pub(crate) chain_tip: crate::BlockHeight, + /// The `utxo_mined_at` argument. + pub(crate) utxo_mined_at: crate::BlockHeight, +} + +impl fmt::Display for InvalidHeightError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidHeightError {} + +/// Error returned when `NumberOf512Seconds::is_satisfied_by` is incorrectly called. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidTimeError { + /// The `chain_tip` argument. + pub(crate) chain_tip: crate::BlockMtp, + /// The `utxo_mined_at` argument. + pub(crate) utxo_mined_at: crate::BlockMtp, +} + +impl fmt::Display for InvalidTimeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidTimeError {} + #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for NumberOfBlocks { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { @@ -383,24 +414,24 @@ mod tests { let time_lock = NumberOf512Seconds::from_512_second_intervals(10); let chain_state1 = BlockMtp::new(timestamps); let utxo_state1 = BlockMtp::new(utxo_timestamps); - assert!(time_lock.is_satisfied_by(chain_state1, utxo_state1)); + assert!(time_lock.is_satisfied_by(chain_state1, utxo_state1).unwrap()); // Test case 2: Not satisfied (current_mtp < utxo_mtp + required_seconds) let chain_state2 = BlockMtp::new(timestamps2); let utxo_state2 = BlockMtp::new(utxo_timestamps2); - assert!(!time_lock.is_satisfied_by(chain_state2, utxo_state2)); + assert!(!time_lock.is_satisfied_by(chain_state2, utxo_state2).unwrap()); // Test case 3: Test with a larger value (100 intervals = 51200 seconds) let larger_lock = NumberOf512Seconds::from_512_second_intervals(100); let chain_state3 = BlockMtp::new(timestamps3); let utxo_state3 = BlockMtp::new(utxo_timestamps3); - assert!(larger_lock.is_satisfied_by(chain_state3, utxo_state3)); + assert!(larger_lock.is_satisfied_by(chain_state3, utxo_state3).unwrap()); // Test case 4: Overflow handling - tests that is_satisfied_by handles overflow gracefully let max_time_lock = NumberOf512Seconds::MAX; let chain_state4 = BlockMtp::new(timestamps); let utxo_state4 = BlockMtp::new(utxo_timestamps); - assert!(!max_time_lock.is_satisfied_by(chain_state4, utxo_state4)); + assert!(!max_time_lock.is_satisfied_by(chain_state4, utxo_state4).unwrap()); } #[test] @@ -410,19 +441,19 @@ mod tests { let height_lock = NumberOfBlocks(10); // Test case 1: Satisfaction (current_height >= utxo_height + required) - let chain_state1 = BlockHeight::from_u32(100); + let chain_state1 = BlockHeight::from_u32(89); let utxo_state1 = BlockHeight::from_u32(80); - assert!(height_lock.is_satisfied_by(chain_state1, utxo_state1)); + assert!(height_lock.is_satisfied_by(chain_state1, utxo_state1).unwrap()); // Test case 2: Not satisfied (current_height < utxo_height + required) - let chain_state2 = BlockHeight::from_u32(89); + let chain_state2 = BlockHeight::from_u32(88); let utxo_state2 = BlockHeight::from_u32(80); - assert!(!height_lock.is_satisfied_by(chain_state2, utxo_state2)); + assert!(!height_lock.is_satisfied_by(chain_state2, utxo_state2).unwrap()); // Test case 3: Overflow handling - tests that is_satisfied_by handles overflow gracefully let max_height_lock = NumberOfBlocks::MAX; let chain_state3 = BlockHeight::from_u32(1000); let utxo_state3 = BlockHeight::from_u32(80); - assert!(!max_height_lock.is_satisfied_by(chain_state3, utxo_state3)); + assert!(!max_height_lock.is_satisfied_by(chain_state3, utxo_state3).unwrap()); } } diff --git a/units/tests/api.rs b/units/tests/api.rs index 33b60bc7bb..3e6dd97f63 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -139,11 +139,13 @@ struct Errors { x: locktime::absolute::ConversionError, y: locktime::absolute::Height, z: locktime::absolute::ParseHeightError, - _a: locktime::absolute::ParseTimeError, - _b: locktime::relative::TimeOverflowError, - _e: parse::ParseIntError, - _f: parse::PrefixedHexError, - _g: parse::UnprefixedHexError, + aa: locktime::absolute::ParseTimeError, + ab: locktime::relative::TimeOverflowError, + ac: locktime::relative::InvalidHeightError, + ad: locktime::relative::InvalidTimeError, + ae: parse::ParseIntError, + af: parse::PrefixedHexError, + ag: parse::UnprefixedHexError, } #[test] From 727047bd393f4616392a1966fd997526add35e33 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sun, 11 May 2025 10:56:13 +1000 Subject: [PATCH 003/857] Fix off-by-one-bug in absolute locktime When checking a locktime against block height we add 1 because when the next block is being validated that is what the height will be and `is_satisfied_by` is defined to return true if a transaction with this locktime can be included in the next block. As we have in `relative`, and for the same reasons, add an API to the absolute `Height` and `MedianTimePast`: `is_satisfied_by`. Also add `is_satisfied_by_{height, time}` variants to `absolute::LockTime`. Call through to the new functions in `units`. --- primitives/src/locktime/absolute.rs | 109 +++++++++++++++++++++++++++- units/src/locktime/absolute.rs | 23 ++++++ 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs index c10d2ff790..0ec07fb14e 100644 --- a/primitives/src/locktime/absolute.rs +++ b/primitives/src/locktime/absolute.rs @@ -233,13 +233,21 @@ impl LockTime { /// is satisfied if a transaction with `nLockTime` ([`Transaction::lock_time`]) set to /// `height`/`time` is valid. /// + /// If `height` and `mtp` represent the current chain tip then a transaction with this + /// locktime can be broadcast for inclusion in the next block. + /// + /// If you do not have, or do not wish to calculate, both parameters consider using: + /// + /// * [`is_satisfied_by_height()`](absolute::LockTime::is_satisfied_by_height) + /// * [`is_satisfied_by_time()`](absolute::LockTime::is_satisfied_by_time) + /// /// # Examples /// /// ```no_run /// # use bitcoin_primitives::absolute; /// // Can be implemented if block chain data is available. /// fn get_height() -> absolute::Height { todo!("return the current block height") } - /// fn get_time() -> absolute::MedianTimePast { todo!("return the current block time") } + /// fn get_time() -> absolute::MedianTimePast { todo!("return the current block MTP") } /// /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`. /// if n.is_satisfied_by(get_height(), get_time()) { @@ -247,12 +255,43 @@ impl LockTime { /// } /// ```` #[inline] - pub fn is_satisfied_by(self, height: Height, time: MedianTimePast) -> bool { + pub fn is_satisfied_by(self, height: Height, mtp: MedianTimePast) -> bool { + match self { + LockTime::Blocks(blocks) => blocks.is_satisfied_by(height), + LockTime::Seconds(time) => time.is_satisfied_by(mtp), + } + } + + /// Returns true if a transaction with this locktime can be spent in the next block. + /// + /// If `height` is the current block height of the chain then a transaction with this locktime + /// can be broadcast for inclusion in the next block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-height. + #[inline] + pub fn is_satisfied_by_height(self, height: Height) -> Result { use LockTime as L; match self { - L::Blocks(n) => n <= height, - L::Seconds(n) => n <= time, + L::Blocks(blocks) => Ok(blocks.is_satisfied_by(height)), + L::Seconds(time) => Err(IncompatibleHeightError { lock: time, incompatible: height }), + } + } + + /// Returns true if a transaction with this locktime can be included in the next block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-time. + #[inline] + pub fn is_satisfied_by_time(self, mtp: MedianTimePast) -> Result { + use LockTime as L; + + match self { + L::Seconds(time) => Ok(time.is_satisfied_by(mtp)), + L::Blocks(blocks) => Err(IncompatibleTimeError { lock: blocks, incompatible: mtp }), } } @@ -407,6 +446,68 @@ impl<'de> serde::Deserialize<'de> for LockTime { } } +/// Tried to satisfy a lock-by-time lock using a height value. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IncompatibleHeightError { + /// The inner value of the lock-by-time lock. + lock: MedianTimePast, + /// Attempted to satisfy a lock-by-time lock with this height. + incompatible: Height, +} + +impl IncompatibleHeightError { + /// Returns the value of the lock-by-time lock. + pub fn lock(&self) -> MedianTimePast { self.lock } + + /// Returns the height that was erroneously used to try and satisfy a lock-by-time lock. + pub fn incompatible(&self) -> Height { self.incompatible } +} + +impl fmt::Display for IncompatibleHeightError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "tried to satisfy a lock-by-time lock {} with height: {}", + self.lock, self.incompatible + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IncompatibleHeightError {} + +/// Tried to satisfy a lock-by-height lock using a height value. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IncompatibleTimeError { + /// The inner value of the lock-by-height lock. + lock: Height, + /// Attempted to satisfy a lock-by-height lock with this MTP. + incompatible: MedianTimePast, +} + +impl IncompatibleTimeError { + /// Returns the value of the lock-by-height lock. + pub fn lock(&self) -> Height { self.lock } + + /// Returns the MTP that was erroneously used to try and satisfy a lock-by-height lock. + pub fn incompatible(&self) -> MedianTimePast { self.incompatible } +} + +impl fmt::Display for IncompatibleTimeError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "tried to satisfy a lock-by-height lock {} with MTP: {}", + self.lock, self.incompatible + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IncompatibleTimeError {} + #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for LockTime { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index f80ccdfee2..c256df2e07 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -83,6 +83,17 @@ impl Height { /// Converts this [`Height`] to a raw `u32` value. #[inline] pub const fn to_u32(self) -> u32 { self.0 } + + /// Returns true if a transaction with this locktime can be included in the next block. + /// + /// `self` is value of the `LockTime` and if `height` is the current chain tip then + /// a transaction with this lock can be broadcast for inclusion in the next block. + #[inline] + pub fn is_satisfied_by(self, height: Height) -> bool { + // Use u64 so that there can be no overflow. + let next_block_height = u64::from(height.to_u32()) + 1; + u64::from(self.to_u32()) <= next_block_height + } } impl fmt::Display for Height { @@ -217,6 +228,18 @@ impl MedianTimePast { /// Converts this [`MedianTimePast`] to a raw `u32` value. #[inline] pub const fn to_u32(self) -> u32 { self.0 } + + /// Returns true if a transaction with this locktime can be included in the next block. + /// + /// `self`is the value of the `LockTime` and if `time` is the median time past of the block at + /// the chain tip then a transaction with this lock can be broadcast for inclusion in the next + /// block. + #[inline] + pub fn is_satisfied_by(self, time: MedianTimePast) -> bool { + // The locktime check in Core during block validation uses the MTP + // of the previous block - which is the expected to be `time` here. + self <= time + } } impl fmt::Display for MedianTimePast { From f9d6453d5b2893fe6b025f05485ae71b04c3052e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 12 May 2025 12:26:06 +1000 Subject: [PATCH 004/857] Shorten locktime type term Use lock-by-time and lock-by-height instead of lock-by-blocktime and lock-by-blockheight respectively with no loss of clarity. --- bitcoin/src/blockdata/mod.rs | 4 ++-- primitives/src/locktime/absolute.rs | 2 +- primitives/src/locktime/relative.rs | 2 +- units/src/locktime/absolute.rs | 10 +++++----- units/src/locktime/relative.rs | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs index 13ffc60592..7974ba8075 100644 --- a/bitcoin/src/blockdata/mod.rs +++ b/bitcoin/src/blockdata/mod.rs @@ -32,7 +32,7 @@ pub mod locktime { pub mod absolute { //! Provides type [`LockTime`] that implements the logic around nLockTime/OP_CHECKLOCKTIMEVERIFY. //! - //! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by + //! There are two types of lock time: lock-by-height and lock-by-time, distinguished by //! whether `LockTime < LOCKTIME_THRESHOLD`. use io::{BufRead, Write}; @@ -66,7 +66,7 @@ pub mod locktime { pub mod relative { //! Provides type [`LockTime`] that implements the logic around nSequence/OP_CHECKSEQUENCEVERIFY. //! - //! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by + //! There are two types of lock time: lock-by-height and lock-by-time, distinguished by //! whether bit 22 of the `u32` consensus value is set. /// Re-export everything from the `primitives::locktime::relative` module. diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs index 0ec07fb14e..4971aadb68 100644 --- a/primitives/src/locktime/absolute.rs +++ b/primitives/src/locktime/absolute.rs @@ -2,7 +2,7 @@ //! Provides type [`LockTime`] that implements the logic around `nLockTime`/`OP_CHECKLOCKTIMEVERIFY`. //! -//! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by +//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by //! whether `LockTime < LOCKTIME_THRESHOLD`. use core::fmt; diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index 343ebd682c..56edad60b7 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -2,7 +2,7 @@ //! Provides type [`LockTime`] that implements the logic around `nSequence`/`OP_CHECKSEQUENCEVERIFY`. //! -//! There are two types of lock time: lock-by-blockheight and lock-by-blocktime, distinguished by +//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by //! whether bit 22 of the `u32` consensus value is set. use core::{convert, fmt}; diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index c256df2e07..96e1bf1fd4 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -349,7 +349,7 @@ impl std::error::Error for ConversionError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } -/// Describes the two types of locking, lock-by-blockheight and lock-by-blocktime. +/// Describes the two types of locking, lock-by-height and lock-by-time. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] enum LockTimeUnit { /// Lock by blockheight. @@ -364,9 +364,9 @@ impl fmt::Display for LockTimeUnit { match *self { L::Blocks => - write!(f, "expected lock-by-blockheight (must be < {})", LOCK_TIME_THRESHOLD), + write!(f, "expected lock-by-height (must be < {})", LOCK_TIME_THRESHOLD), L::Seconds => - write!(f, "expected lock-by-blocktime (must be >= {})", LOCK_TIME_THRESHOLD), + write!(f, "expected lock-by-time (must be >= {})", LOCK_TIME_THRESHOLD), } } } @@ -580,8 +580,8 @@ mod tests { let blocks = LockTimeUnit::Blocks; let seconds = LockTimeUnit::Seconds; - assert_eq!(format!("{}", blocks), "expected lock-by-blockheight (must be < 500000000)"); - assert_eq!(format!("{}", seconds), "expected lock-by-blocktime (must be >= 500000000)"); + assert_eq!(format!("{}", blocks), "expected lock-by-height (must be < 500000000)"); + assert_eq!(format!("{}", seconds), "expected lock-by-time (must be >= 500000000)"); } #[test] diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 1fb3db1db4..e3d9f8d694 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; #[doc(hidden)] pub type Height = NumberOfBlocks; -/// A relative lock time lock-by-blockheight value. +/// A relative lock time lock-by-height value. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct NumberOfBlocks(u16); @@ -94,9 +94,9 @@ impl fmt::Display for NumberOfBlocks { #[doc(hidden)] pub type Time = NumberOf512Seconds; -/// A relative lock time lock-by-blocktime value. +/// A relative lock time lock-by-time value. /// -/// For BIP 68 relative lock-by-blocktime locks, time is measured in 512 second intervals. +/// For BIP 68 relative lock-by-time locks, time is measured in 512 second intervals. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct NumberOf512Seconds(u16); From 480a2cd62aa5ddfea15cc1ccbf0e03f92bc663d9 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 12 May 2025 12:29:33 +1000 Subject: [PATCH 005/857] Favour new function `from_mtp` over deprecated Use the new function and not the deprecated on in rustdcos and tests. --- bitcoin/tests/serde.rs | 2 +- primitives/src/locktime/absolute.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index f9e7e4a6a3..3bc1c3deba 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -64,7 +64,7 @@ fn serde_regression_absolute_lock_time_height() { #[test] fn serde_regression_absolute_lock_time_time() { let seconds: u32 = 1653195600; // May 22nd, 5am UTC. - let t = absolute::LockTime::from_time(seconds).expect("valid time"); + let t = absolute::LockTime::from_mtp(seconds).expect("valid time"); let got = serialize(&t).unwrap(); let want = include_bytes!("data/serde/absolute_lock_time_seconds_bincode") as &[_]; diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs index 4971aadb68..48b2318102 100644 --- a/primitives/src/locktime/absolute.rs +++ b/primitives/src/locktime/absolute.rs @@ -79,7 +79,7 @@ pub enum LockTime { /// use bitcoin_primitives::absolute; /// /// let seconds: u32 = 1653195600; // May 22nd, 5am UTC. - /// let n = absolute::LockTime::from_time(seconds).expect("valid time"); + /// let n = absolute::LockTime::from_mtp(seconds).expect("valid time"); /// assert!(n.is_block_time()); /// assert_eq!(n.to_consensus_u32(), seconds); /// ``` @@ -197,8 +197,8 @@ impl LockTime { /// /// ```rust /// # use bitcoin_primitives::absolute; - /// assert!(absolute::LockTime::from_time(1653195600).is_ok()); - /// assert!(absolute::LockTime::from_time(741521).is_err()); + /// assert!(absolute::LockTime::from_mtp(1653195600).is_ok()); + /// assert!(absolute::LockTime::from_mtp(741521).is_err()); /// ``` #[inline] pub fn from_mtp(n: u32) -> Result { From 40bb177bc2b75f976f24885ca69fc20591884cb4 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 12 May 2025 12:35:01 +1000 Subject: [PATCH 006/857] Put is_satisfied_by functions together Move the `_by_{height,time}` functions to be underneath the `is_satisfied_by` function. Code move only, no logic change. --- primitives/src/locktime/relative.rs | 96 ++++++++++++++--------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index 56edad60b7..fd58ff1db2 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -213,6 +213,54 @@ impl LockTime { } } + /// Returns true if an output with this locktime can be spent in the next block. + /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-height. + #[inline] + pub fn is_satisfied_by_height( + self, + chain_tip: BlockHeight, + utxo_mined_at: BlockHeight, + ) -> Result { + use LockTime as L; + + match self { + L::Blocks(blocks) => blocks + .is_satisfied_by(chain_tip, utxo_mined_at) + .map_err(IsSatisfiedByHeightError::Satisfaction), + L::Time(time) => Err(IsSatisfiedByHeightError::Incompatible(time)), + } + } + + /// Returns true if an output with this locktime can be spent in the next block. + /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-time. + #[inline] + pub fn is_satisfied_by_time( + self, + chain_tip: BlockMtp, + utxo_mined_at: BlockMtp, + ) -> Result { + use LockTime as L; + + match self { + L::Time(time) => time + .is_satisfied_by(chain_tip, utxo_mined_at) + .map_err(IsSatisfiedByTimeError::Satisfaction), + L::Blocks(blocks) => Err(IsSatisfiedByTimeError::Incompatible(blocks)), + } + } + /// Returns true if satisfaction of `other` lock time implies satisfaction of this /// [`relative::LockTime`]. /// @@ -281,54 +329,6 @@ impl LockTime { false } } - - /// Returns true if an output with this locktime can be spent in the next block. - /// - /// If this function returns true then an output with this locktime can be spent in the next - /// block. - /// - /// # Errors - /// - /// Returns an error if this lock is not lock-by-height. - #[inline] - pub fn is_satisfied_by_height( - self, - chain_tip: BlockHeight, - utxo_mined_at: BlockHeight, - ) -> Result { - use LockTime as L; - - match self { - L::Blocks(blocks) => blocks - .is_satisfied_by(chain_tip, utxo_mined_at) - .map_err(IsSatisfiedByHeightError::Satisfaction), - L::Time(time) => Err(IsSatisfiedByHeightError::Incompatible(time)), - } - } - - /// Returns true if an output with this locktime can be spent in the next block. - /// - /// If this function returns true then an output with this locktime can be spent in the next - /// block. - /// - /// # Errors - /// - /// Returns an error if this lock is not lock-by-time. - #[inline] - pub fn is_satisfied_by_time( - self, - chain_tip: BlockMtp, - utxo_mined_at: BlockMtp, - ) -> Result { - use LockTime as L; - - match self { - L::Time(time) => time - .is_satisfied_by(chain_tip, utxo_mined_at) - .map_err(IsSatisfiedByTimeError::Satisfaction), - L::Blocks(blocks) => Err(IsSatisfiedByTimeError::Incompatible(blocks)), - } - } } impl From for LockTime { From caebb1bf73ec34f0ca87c54a072a79f154ef853a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 12 May 2025 12:48:05 +1000 Subject: [PATCH 007/857] units: relative: Do minor rustdocs fixes Slightly improve grammar and fix column width to 100. --- units/src/locktime/relative.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index e3d9f8d694..e50fe8f936 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -111,7 +111,8 @@ impl NumberOf512Seconds { /// The maximum relative block time (33,554,432 seconds or approx 388 days). pub const MAX: Self = NumberOf512Seconds(u16::MAX); - /// Constructs a new [`NumberOf512Seconds`] using time intervals where each interval is equivalent to 512 seconds. + /// Constructs a new [`NumberOf512Seconds`] using time intervals where each interval is + /// equivalent to 512 seconds. /// /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin. #[inline] @@ -122,8 +123,8 @@ impl NumberOf512Seconds { #[must_use] pub const fn to_512_second_intervals(self) -> u16 { self.0 } - /// Constructs a new [`NumberOf512Seconds`] from seconds, converting the seconds into 512 second - /// interval with truncating division. + /// Constructs a new [`NumberOf512Seconds`] from seconds, converting the seconds into a 512 + /// second interval using truncating division. /// /// # Errors /// @@ -139,8 +140,8 @@ impl NumberOf512Seconds { } } - /// Constructs a new [`NumberOf512Seconds`] from seconds, converting the seconds into 512 second - /// intervals with ceiling division. + /// Constructs a new [`NumberOf512Seconds`] from seconds, converting the seconds into a 512 + /// second interval using ceiling division. /// /// # Errors /// From 4ccecf5decfead9818b74fbdee73115c349e2f3e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 12 May 2025 12:57:08 +1000 Subject: [PATCH 008/857] Fix stale Height type link `units::locktime::relative::Height` type is now deprecated, use the new name in rustdoc. --- units/src/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/block.rs b/units/src/block.rs index 778fb1beae..4c832f18ea 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -127,7 +127,7 @@ impl_u32_wrapper! { /// Block interval is an integer type representing a difference between the heights of two blocks. /// /// This type is not meant for constructing relative height based timelocks. It is a general - /// purpose block interval abstraction. For locktimes please see [`locktime::relative::Height`]. + /// purpose block interval abstraction. For locktimes please see [`locktime::relative::NumberOfBlocks`]. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] // Public to try and make it really clear that there are no invariants. From c1d2f0386d4f0b177e9dfb524b842e5a9257b757 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 20 May 2025 16:04:23 +0100 Subject: [PATCH 009/857] Add tests to block New mutants found in weekly mutation testing. Add tests to kill them. --- units/src/block.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/units/src/block.rs b/units/src/block.rs index 4efe0547b5..57cae8ed79 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -439,6 +439,7 @@ impl<'a> core::iter::Sum<&'a BlockMtpInterval> for BlockMtpInterval { #[cfg(test)] mod tests { use super::*; + use crate::locktime::relative::NumberOf512Seconds; #[test] fn sanity_check() { @@ -479,6 +480,7 @@ mod tests { // interval - interval = interval assert!(BlockHeightInterval(10) - BlockHeightInterval(7) == BlockHeightInterval(3)); + // Sum for BlockHeightInterval by reference and by value assert!( [BlockHeightInterval(1), BlockHeightInterval(2), BlockHeightInterval(3)] .iter() @@ -492,6 +494,20 @@ mod tests { == BlockHeightInterval(15) ); + // Sum for BlockMtpInterval by reference and by value + assert!( + [BlockMtpInterval(1), BlockMtpInterval(2), BlockMtpInterval(3)] + .iter() + .sum::() + == BlockMtpInterval(6) + ); + assert!( + [BlockMtpInterval(4), BlockMtpInterval(5), BlockMtpInterval(6)] + .into_iter() + .sum::() + == BlockMtpInterval(15) + ); + // interval += interval let mut int = BlockHeightInterval(1); int += BlockHeightInterval(2); @@ -502,4 +518,54 @@ mod tests { int -= BlockHeightInterval(7); assert_eq!(int, BlockHeightInterval(3)); } + + #[test] + fn block_height_checked() { + let a = BlockHeight(10); + let b = BlockHeight(5); + assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5))); + assert_eq!(a.checked_add(BlockHeightInterval(5)), Some(BlockHeight(15))); + assert_eq!(a.checked_sub(BlockHeight(11)), None); + assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None); + } + + #[test] + fn block_height_interval_checked() { + let a = BlockHeightInterval(10); + let b = BlockHeightInterval(5); + assert_eq!(a.checked_sub(b), Some(BlockHeightInterval(5))); + assert_eq!(a.checked_add(b), Some(BlockHeightInterval(15))); + assert_eq!(a.checked_sub(BlockHeightInterval(11)), None); + assert_eq!(a.checked_add(BlockHeightInterval(u32::MAX - 5)), None); + } + + #[test] + fn block_mtp_interval_checked() { + let a = BlockMtpInterval(10); + let b = BlockMtpInterval(5); + assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5))); + assert_eq!(a.checked_add(b), Some(BlockMtpInterval(15))); + assert_eq!(a.checked_sub(BlockMtpInterval(11)), None); + assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None); + } + + #[test] + fn block_mtp_checked() { + let a = BlockMtp(10); + let b = BlockMtp(5); + assert_eq!(a.checked_sub(b), Some(BlockMtpInterval(5))); + assert_eq!(a.checked_add(BlockMtpInterval(5)), Some(BlockMtp(15))); + assert_eq!(a.checked_sub(BlockMtp(11)), None); + assert_eq!(a.checked_add(BlockMtpInterval(u32::MAX - 5)), None); + } + + #[test] + fn block_mtp_interval_from_number_of_512seconds() { + let n = NumberOf512Seconds::from_seconds_floor(0).unwrap(); + let interval = BlockMtpInterval::from(n); + assert_eq!(interval, BlockMtpInterval(0)); + let n = NumberOf512Seconds::from_seconds_floor(1024).unwrap(); + let interval = BlockMtpInterval::from(n); + assert_eq!(interval, BlockMtpInterval(1024)); + } } From 24cc059a78648fd6412dc84c8734c16ddf130cb4 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 20 May 2025 16:04:59 +0100 Subject: [PATCH 010/857] Add tests to result New mutants found in weekly mutation testing. Add tests to kill them. --- units/src/result.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/units/src/result.rs b/units/src/result.rs index f0587b2b2a..1685778ae1 100644 --- a/units/src/result.rs +++ b/units/src/result.rs @@ -311,3 +311,34 @@ impl fmt::Display for MathOp { } } } + +#[cfg(test)] +mod tests { + use crate::MathOp; + + #[test] + fn mathop_predicates() { + assert!(MathOp::Add.is_overflow()); + assert!(MathOp::Sub.is_overflow()); + assert!(MathOp::Mul.is_overflow()); + assert!(MathOp::Neg.is_overflow()); + assert!(!MathOp::Div.is_overflow()); + assert!(!MathOp::Rem.is_overflow()); + + assert!(MathOp::Div.is_div_by_zero()); + assert!(MathOp::Rem.is_div_by_zero()); + assert!(!MathOp::Add.is_div_by_zero()); + + assert!(MathOp::Add.is_addition()); + assert!(!MathOp::Sub.is_addition()); + + assert!(MathOp::Sub.is_subtraction()); + assert!(!MathOp::Add.is_subtraction()); + + assert!(MathOp::Mul.is_multiplication()); + assert!(!MathOp::Div.is_multiplication()); + + assert!(MathOp::Neg.is_negation()); + assert!(!MathOp::Add.is_negation()); + } +} From fd0a756344f1f9790efb0e8b08c9e4f3ebf01bef Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 20 May 2025 16:05:47 +0100 Subject: [PATCH 011/857] Add tests to relative locktime New mutants found in weekly mutation testing. Add tests to kill them. --- units/src/locktime/relative.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 4aa330710a..23be03ca3d 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -333,6 +333,7 @@ mod tests { NumberOf512Seconds::from_512_second_intervals(100).to_consensus_u32(), 4_194_404u32 ); // 0x400064 + assert_eq!(NumberOf512Seconds::from_512_second_intervals(1).to_seconds(), 512); } #[test] From b538a1095652f535aeb15f6e3bbc44969db1ea88 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 20 May 2025 16:07:03 +0100 Subject: [PATCH 012/857] Add deprecated functions to mutants exclude list New mutants found in deprecated functions in the weekly mutation testing. Add the deprecated functions to the exclude list so they are not mutated. --- .cargo/mutants.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml index 87cffbcf21..70a1b8fd3e 100644 --- a/.cargo/mutants.toml +++ b/.cargo/mutants.toml @@ -23,6 +23,8 @@ exclude_re = [ "FeeRate::fee_vb", # Deprecated "FeeRate::fee_wu", # Deprecated "SignedAmount::checked_abs", # Deprecated + "NumberOfBlocks::value", # Deprecated + "NumberOf512Seconds::to_consensus_u32", # Deprecated # primitives "Sequence::from_512_second_intervals", # Mutant from replacing | with ^, this returns the same value since the XOR is taken against the u16 with an all-zero bitmask From e8a9a89e25158c3823004d54a803ae6efec08921 Mon Sep 17 00:00:00 2001 From: Erick Cestari Date: Sat, 17 May 2025 20:00:34 -0300 Subject: [PATCH 013/857] feat(p2p): add `AddrV2` <> `IpAddr` conversions --- bitcoin/src/p2p/address.rs | 172 ++++++++++++++++++++++++++++++++++--- 1 file changed, 159 insertions(+), 13 deletions(-) diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 576b257b2f..65603bae11 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -6,7 +6,7 @@ //! network addresses in Bitcoin messages. use core::{fmt, iter}; -use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; use io::{BufRead, Read, Write}; @@ -140,7 +140,7 @@ pub enum AddrV2 { /// Error types for [`AddrV2`] to [`SocketAddr`] conversion. #[derive(Debug, PartialEq, Eq)] -pub enum AddrV2ConversionError { +pub enum AddrV2ToSocketAddrError { /// A [`AddrV2::TorV3`] address cannot be converted to a [`SocketAddr`]. TorV3NotSupported, /// A [`AddrV2::I2p`] address cannot be converted to a [`SocketAddr`]. @@ -152,7 +152,7 @@ pub enum AddrV2ConversionError { UnknownNotSupported, } -impl fmt::Display for AddrV2ConversionError { +impl fmt::Display for AddrV2ToSocketAddrError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::TorV3NotSupported => write!(f, "TorV3 addresses cannot be converted to SocketAddr"), @@ -163,7 +163,7 @@ impl fmt::Display for AddrV2ConversionError { } } -impl std::error::Error for AddrV2ConversionError {} +impl std::error::Error for AddrV2ToSocketAddrError {} impl From for AddrV2 { fn from(addr: SocketAddr) -> Self { @@ -184,20 +184,82 @@ impl From for AddrV2 { } impl TryFrom for SocketAddr { - type Error = AddrV2ConversionError; + type Error = AddrV2ToSocketAddrError; fn try_from(addr: AddrV2) -> Result { match addr { AddrV2::Ipv4(ip) => Ok(SocketAddr::V4(SocketAddrV4::new(ip, 0))), AddrV2::Ipv6(ip) => Ok(SocketAddr::V6(SocketAddrV6::new(ip, 0, 0, 0))), - AddrV2::Cjdns(_) => Err(AddrV2ConversionError::CjdnsNotRecommended), - AddrV2::TorV3(_) => Err(AddrV2ConversionError::TorV3NotSupported), - AddrV2::I2p(_) => Err(AddrV2ConversionError::I2pNotSupported), - AddrV2::Unknown(_, _) => Err(AddrV2ConversionError::UnknownNotSupported), + AddrV2::Cjdns(_) => Err(AddrV2ToSocketAddrError::CjdnsNotRecommended), + AddrV2::TorV3(_) => Err(AddrV2ToSocketAddrError::TorV3NotSupported), + AddrV2::I2p(_) => Err(AddrV2ToSocketAddrError::I2pNotSupported), + AddrV2::Unknown(_, _) => Err(AddrV2ToSocketAddrError::UnknownNotSupported), } } } +impl TryFrom for IpAddr { + type Error = AddrV2ToIpAddrError; + + fn try_from(addr: AddrV2) -> Result { + match addr { + AddrV2::Ipv4(ip) => Ok(IpAddr::V4(ip)), + AddrV2::Ipv6(ip) => Ok(IpAddr::V6(ip)), + AddrV2::Cjdns(_) => Err(AddrV2ToIpAddrError::Cjdns), + AddrV2::TorV3(_) => Err(AddrV2ToIpAddrError::TorV3), + AddrV2::I2p(_) => Err(AddrV2ToIpAddrError::I2p), + AddrV2::Unknown(_, _) => Err(AddrV2ToIpAddrError::Unknown), + } + } +} + +impl TryFrom for Ipv4Addr { + type Error = AddrV2ToIpv4AddrError; + + fn try_from(addr: AddrV2) -> Result { + match addr { + AddrV2::Ipv4(ip) => Ok(ip), + AddrV2::Ipv6(_) => Err(AddrV2ToIpv4AddrError::Ipv6), + AddrV2::Cjdns(_) => Err(AddrV2ToIpv4AddrError::Cjdns), + AddrV2::TorV3(_) => Err(AddrV2ToIpv4AddrError::TorV3), + AddrV2::I2p(_) => Err(AddrV2ToIpv4AddrError::I2p), + AddrV2::Unknown(_, _) => Err(AddrV2ToIpv4AddrError::Unknown), + } + } +} + +impl TryFrom for Ipv6Addr { + type Error = AddrV2ToIpv6AddrError; + + fn try_from(addr: AddrV2) -> Result { + match addr { + AddrV2::Ipv6(ip) => Ok(ip), + AddrV2::Cjdns(_) => Err(AddrV2ToIpv6AddrError::Cjdns), + AddrV2::Ipv4(_) => Err(AddrV2ToIpv6AddrError::Ipv4), + AddrV2::TorV3(_) => Err(AddrV2ToIpv6AddrError::TorV3), + AddrV2::I2p(_) => Err(AddrV2ToIpv6AddrError::I2p), + AddrV2::Unknown(_, _) => Err(AddrV2ToIpv6AddrError::Unknown), + } + } +} + +impl From for AddrV2 { + fn from(addr: IpAddr) -> Self { + match addr { + IpAddr::V4(ip) => AddrV2::Ipv4(ip), + IpAddr::V6(ip) => AddrV2::Ipv6(ip), + } + } +} + +impl From for AddrV2 { + fn from(addr: Ipv4Addr) -> Self { AddrV2::Ipv4(addr) } +} + +impl From for AddrV2 { + fn from(addr: Ipv6Addr) -> Self { AddrV2::Ipv6(addr) } +} + impl Encodable for AddrV2 { fn consensus_encode(&self, w: &mut W) -> Result { fn encode_addr( @@ -348,6 +410,90 @@ impl ToSocketAddrs for AddrV2Message { } } +/// Error types for [`AddrV2`] to [`IpAddr`] conversion. +#[derive(Debug, PartialEq, Eq)] +pub enum AddrV2ToIpAddrError { + /// A [`AddrV2::TorV3`] address cannot be converted to a [`IpAddr`]. + TorV3, + /// A [`AddrV2::I2p`] address cannot be converted to a [`IpAddr`]. + I2p, + /// A [`AddrV2::Cjdns`] address cannot be converted to a [`IpAddr`], + Cjdns, + /// A [`AddrV2::Unknown`] address cannot be converted to a [`IpAddr`]. + Unknown, +} + +impl fmt::Display for AddrV2ToIpAddrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TorV3 => write!(f, "TorV3 addresses cannot be converted to IpAddr"), + Self::I2p => write!(f, "I2P addresses cannot be converted to IpAddr"), + Self::Cjdns => write!(f, "Cjdns addresses cannot be converted to IpAddr"), + Self::Unknown => write!(f, "Unknown address type cannot be converted to IpAddr"), + } + } +} + +impl std::error::Error for AddrV2ToIpAddrError {} + +/// Error types for [`AddrV2`] to [`Ipv4Addr`] conversion. +#[derive(Debug, PartialEq, Eq)] +pub enum AddrV2ToIpv4AddrError { + /// A [`AddrV2::Ipv6`] address cannot be converted to a [`Ipv4Addr`]. + Ipv6, + /// A [`AddrV2::TorV3`] address cannot be converted to a [`Ipv4Addr`]. + TorV3, + /// A [`AddrV2::I2p`] address cannot be converted to a [`Ipv4Addr`]. + I2p, + /// A [`AddrV2::Cjdns`] address cannot be converted to a [`Ipv4Addr`], + Cjdns, + /// A [`AddrV2::Unknown`] address cannot be converted to a [`Ipv4Addr`]. + Unknown, +} + +impl fmt::Display for AddrV2ToIpv4AddrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ipv6 => write!(f, "Ipv6 addresses cannot be converted to Ipv4Addr"), + Self::TorV3 => write!(f, "TorV3 addresses cannot be converted to Ipv4Addr"), + Self::I2p => write!(f, "I2P addresses cannot be converted to Ipv4Addr"), + Self::Cjdns => write!(f, "Cjdns addresses cannot be converted to Ipv4Addr"), + Self::Unknown => write!(f, "Unknown address type cannot be converted to Ipv4Addr"), + } + } +} + +impl std::error::Error for AddrV2ToIpv4AddrError {} + +/// Error types for [`AddrV2`] to [`Ipv6Addr`] conversion. +#[derive(Debug, PartialEq, Eq)] +pub enum AddrV2ToIpv6AddrError { + /// A [`AddrV2::Ipv4`] address cannot be converted to a [`Ipv6Addr`]. + Ipv4, + /// A [`AddrV2::TorV3`] address cannot be converted to a [`Ipv6Addr`]. + TorV3, + /// A [`AddrV2::I2p`] address cannot be converted to a [`Ipv6Addr`]. + I2p, + /// A [`AddrV2::Cjdns`] address cannot be converted to a [`Ipv6Addr`], + Cjdns, + /// A [`AddrV2::Unknown`] address cannot be converted to a [`Ipv6Addr`]. + Unknown, +} + +impl fmt::Display for AddrV2ToIpv6AddrError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ipv4 => write!(f, "Ipv addresses cannot be converted to Ipv6Addr"), + Self::TorV3 => write!(f, "TorV3 addresses cannot be converted to Ipv6Addr"), + Self::I2p => write!(f, "I2P addresses cannot be converted to Ipv6Addr"), + Self::Cjdns => write!(f, "Cjdns addresses cannot be converted to Ipv6Addr"), + Self::Unknown => write!(f, "Unknown address type cannot be converted to Ipv6Addr"), + } + } +} + +impl std::error::Error for AddrV2ToIpv6AddrError {} + #[cfg(test)] mod test { use std::net::IpAddr; @@ -658,7 +804,7 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::CjdnsNotRecommended); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::CjdnsNotRecommended); } #[test] @@ -667,7 +813,7 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::TorV3NotSupported); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::TorV3NotSupported); } #[test] @@ -676,7 +822,7 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::I2pNotSupported); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::I2pNotSupported); } #[test] @@ -685,6 +831,6 @@ mod test { let result = SocketAddr::try_from(addr); assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ConversionError::UnknownNotSupported); + assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::UnknownNotSupported); } } From 7ad89df3921f6bc794695569fc0dd5111901bdbb Mon Sep 17 00:00:00 2001 From: Erick Cestari Date: Sat, 17 May 2025 20:20:50 -0300 Subject: [PATCH 014/857] test(p2p): add tests for `AddrV2` <> `IpAddr` conversions --- bitcoin/src/p2p/address.rs | 158 +++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 65603bae11..7961c03362 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -833,4 +833,162 @@ mod test { assert!(result.is_err()); assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::UnknownNotSupported); } + + #[test] + fn addrv2_to_ipaddr_ipv4() { + let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)); + let ip_addr = IpAddr::try_from(addr).unwrap(); + + assert_eq!(ip_addr, IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))); + } + + #[test] + fn addrv2_to_ipaddr_ipv6() { + let addr = AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); + let ip_addr = IpAddr::try_from(addr).unwrap(); + + assert_eq!(ip_addr, IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1))); + } + + #[test] + fn addrv2_to_ipaddr_cjdns() { + let addr = AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1)); + let result = IpAddr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::Cjdns); + } + + #[test] + fn addrv2_to_ipaddr_torv3() { + let addr = AddrV2::TorV3([0; 32]); + let result = IpAddr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::TorV3); + } + + #[test] + fn addrv2_to_ipaddr_i2p() { + let addr = AddrV2::I2p([0; 32]); + let result = IpAddr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::I2p); + } + + #[test] + fn addrv2_to_ipaddr_unknown() { + let addr = AddrV2::Unknown(42, vec![1, 2, 3, 4]); + let result = IpAddr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpAddrError::Unknown); + } + + #[test] + fn addrv2_to_ipv4addr_ipv4() { + let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)); + let ip_addr = Ipv4Addr::try_from(addr).unwrap(); + + assert_eq!(ip_addr, Ipv4Addr::new(192, 168, 1, 1)); + } + + #[test] + fn addrv2_to_ipv4addr_ipv6() { + let addr = AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); + let result = Ipv4Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv4AddrError::Ipv6); + } + + #[test] + fn addrv2_to_ipv4addr_cjdns() { + let addr = AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1)); + let result = Ipv4Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv4AddrError::Cjdns); + } + + #[test] + fn addrv2_to_ipv4addr_torv3() { + let addr = AddrV2::TorV3([0; 32]); + let result = Ipv4Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv4AddrError::TorV3); + } + + #[test] + fn addrv2_to_ipv4addr_i2p() { + let addr = AddrV2::I2p([0; 32]); + let result = Ipv4Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv4AddrError::I2p); + } + + #[test] + fn addrv2_to_ipv4addr_unknown() { + let addr = AddrV2::Unknown(42, vec![1, 2, 3, 4]); + let result = Ipv4Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv4AddrError::Unknown); + } + + #[test] + fn addrv2_to_ipv6addr_ipv4() { + let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)); + let result = Ipv6Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv6AddrError::Ipv4); + } + + #[test] + fn addrv2_to_ipv6addr_ipv6() { + let addr = AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); + let ip_addr = Ipv6Addr::try_from(addr).unwrap(); + + assert_eq!(ip_addr, Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); + } + + #[test] + fn addrv2_to_ipv6addr_cjdns() { + let addr = AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1)); + let result = Ipv6Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv6AddrError::Cjdns); + } + + #[test] + fn addrv2_to_ipv6addr_torv3() { + let addr = AddrV2::TorV3([0; 32]); + let result = Ipv6Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv6AddrError::TorV3); + } + + #[test] + fn addrv2_to_ipv6addr_i2p() { + let addr = AddrV2::I2p([0; 32]); + let result = Ipv6Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv6AddrError::I2p); + } + + #[test] + fn addrv2_to_ipv6addr_unknown() { + let addr = AddrV2::Unknown(42, vec![1, 2, 3, 4]); + let result = Ipv6Addr::try_from(addr); + + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), AddrV2ToIpv6AddrError::Unknown); + } } From 2c236ae24fbda928c35556a5961ef58aea5ecf4d Mon Sep 17 00:00:00 2001 From: Erick Cestari Date: Mon, 19 May 2025 14:38:32 -0300 Subject: [PATCH 015/857] fuzz: Add p2p address round-trip fuzzing test --- .github/workflows/cron-daily-fuzz.yml | 1 + fuzz/Cargo.toml | 4 + .../bitcoin/p2p_address_roundtrip.rs | 86 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs diff --git a/.github/workflows/cron-daily-fuzz.yml b/.github/workflows/cron-daily-fuzz.yml index 253be2af24..d3ab431e15 100644 --- a/.github/workflows/cron-daily-fuzz.yml +++ b/.github/workflows/cron-daily-fuzz.yml @@ -27,6 +27,7 @@ jobs: bitcoin_deserialize_witness, bitcoin_deser_net_msg, bitcoin_outpoint_string, + bitcoin_p2p_address_roundtrip, bitcoin_script_bytes_to_asm_fmt, hashes_json, hashes_ripemd160, diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index f69af96f7a..38adb8b8c9 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -85,3 +85,7 @@ path = "fuzz_targets/hashes/sha512.rs" [[bin]] name = "units_deserialize_amount" path = "fuzz_targets/units/deserialize_amount.rs" + +[[bin]] +name = "bitcoin_p2p_address_roundtrip" +path = "fuzz_targets/bitcoin/p2p_address_roundtrip.rs" diff --git a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs new file mode 100644 index 0000000000..f5dd65a641 --- /dev/null +++ b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs @@ -0,0 +1,86 @@ +use std::convert::TryFrom; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; + +use bitcoin::consensus::Decodable; +use bitcoin::p2p::address::AddrV2; +use honggfuzz::fuzz; + +fn do_test(data: &[u8]) { + if data.len() < 2 { + return; + } + + let mut cursor = std::io::Cursor::new(data); + let addr_v2 = if let Ok(addr) = AddrV2::consensus_decode(&mut cursor) { + addr + } else { + return; + }; + + if let Ok(ip_addr) = IpAddr::try_from(addr_v2.clone()) { + let round_trip: AddrV2 = AddrV2::from(ip_addr); + assert_eq!( + addr_v2, round_trip, + "AddrV2 -> IpAddr -> AddrV2 should round-trip correctly" + ); + } + + if let Ok(ip_addr) = Ipv4Addr::try_from(addr_v2.clone()) { + let round_trip: AddrV2 = AddrV2::from(ip_addr); + assert_eq!( + addr_v2, round_trip, + "AddrV2 -> Ipv4Addr -> AddrV2 should round-trip correctly" + ); + } + + if let Ok(ip_addr) = Ipv6Addr::try_from(addr_v2.clone()) { + let round_trip: AddrV2 = AddrV2::from(ip_addr); + assert_eq!( + addr_v2, round_trip, + "AddrV2 -> Ipv6Addr -> AddrV2 should round-trip correctly" + ); + } + + if let Ok(socket_addr) = SocketAddr::try_from(addr_v2.clone()) { + let round_trip: AddrV2 = AddrV2::from(socket_addr); + assert_eq!( + addr_v2, round_trip, + "AddrV2 -> SocketAddr -> AddrV2 should round-trip correctly" + ); + } +} + +fn main() { + loop { + fuzz!(|data| { + do_test(data); + }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00", &mut a); + super::do_test(&a); + } +} From 3c920d1acb23d84976c0b8e632d8f1068ebbd1fd Mon Sep 17 00:00:00 2001 From: Erick Cestari Date: Wed, 21 May 2025 14:10:43 -0300 Subject: [PATCH 016/857] fix(p2p): Remove `SocketAddr::V6` <> `AddrV2::Cjdns` conversions --- bitcoin/src/p2p/address.rs | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 7961c03362..0a3809bfda 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -169,16 +169,7 @@ impl From for AddrV2 { fn from(addr: SocketAddr) -> Self { match addr { SocketAddr::V4(sock) => AddrV2::Ipv4(*sock.ip()), - SocketAddr::V6(sock) => { - // CJDNS uses the IPv6 network `fc00::/8` - // All CJDNS addresses must have `0xfc00` as the first and second octets - let ip = *sock.ip(); - if ip.octets()[0] == 0xfc && ip.octets()[1] == 0x00 { - AddrV2::Cjdns(ip) - } else { - AddrV2::Ipv6(ip) - } - } + SocketAddr::V6(sock) => AddrV2::Ipv6(*sock.ip()), } } } @@ -761,19 +752,6 @@ mod test { assert_eq!(addr, AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1))); } - #[test] - fn socketaddr_to_addrv2_cjdns() { - let socket = SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1), - 8333, - 0, - 0, - )); - let addr = AddrV2::from(socket); - - assert_eq!(addr, AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1))); - } - #[test] fn addrv2_to_socketaddr_ipv4() { let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)); From a1ce2d1ac8d646b63532ed9ac459ffea39ec8c20 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 19 May 2025 13:09:59 +1000 Subject: [PATCH 017/857] Use _u32 in FeeRate constructor instead of _unchecked When constructing an `Amount` it was observed recently that a `u32` is often big enough. For the same reason we can use a `u32` to construct a fee rate instead of overflowing. Use `_u32`in the constructor and remove the panic. --- bitcoin/src/blockdata/script/tests.rs | 4 ++-- bitcoin/src/psbt/mod.rs | 2 +- units/src/fee_rate/mod.rs | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs index b1bfae4e04..590d233d36 100644 --- a/bitcoin/src/blockdata/script/tests.rs +++ b/bitcoin/src/blockdata/script/tests.rs @@ -751,7 +751,7 @@ fn default_dust_value() { assert!(script_p2wpkh.is_p2wpkh()); assert_eq!(script_p2wpkh.minimal_non_dust(), Amount::from_sat_u32(294)); assert_eq!( - script_p2wpkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_unchecked(6)), + script_p2wpkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_u32(6)), Some(Amount::from_sat_u32(588)) ); @@ -765,7 +765,7 @@ fn default_dust_value() { assert!(script_p2pkh.is_p2pkh()); assert_eq!(script_p2pkh.minimal_non_dust(), Amount::from_sat_u32(546)); assert_eq!( - script_p2pkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_unchecked(6)), + script_p2pkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_u32(6)), Some(Amount::from_sat_u32(1092)) ); } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9418ae8bf7..d7ebf59bdf 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -130,7 +130,7 @@ impl Psbt { /// 1000 sats/vByte. 25k sats/vByte is obviously a mistake at this point. /// /// [`extract_tx`]: Psbt::extract_tx - pub const DEFAULT_MAX_FEE_RATE: FeeRate = FeeRate::from_sat_per_vb_unchecked(25_000); + pub const DEFAULT_MAX_FEE_RATE: FeeRate = FeeRate::from_sat_per_vb_u32(25_000); /// An alias for [`extract_tx_fee_rate_limit`]. /// diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 520790e370..c8da2afdb6 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -49,10 +49,10 @@ impl FeeRate { /// Minimum fee rate required to broadcast a transaction. /// /// The value matches the default Bitcoin Core policy at the time of library release. - pub const BROADCAST_MIN: FeeRate = FeeRate::from_sat_per_vb_unchecked(1); + pub const BROADCAST_MIN: FeeRate = FeeRate::from_sat_per_vb_u32(1); /// Fee rate used to compute dust amount. - pub const DUST: FeeRate = FeeRate::from_sat_per_vb_unchecked(3); + pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. /// @@ -66,8 +66,9 @@ impl FeeRate { Some(FeeRate::from_sat_per_kwu(sat_vb.checked_mul(1000 / 4)?)) } - /// Constructs a new [`FeeRate`] from satoshis per virtual bytes without overflow check. - pub const fn from_sat_per_vb_unchecked(sat_vb: u64) -> Self { + /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. + pub const fn from_sat_per_vb_u32(sat_vb: u32) -> Self { + let sat_vb = sat_vb as u64; // No `Into` in const context. FeeRate::from_sat_per_kwu(sat_vb * (1000 / 4)) } @@ -304,15 +305,14 @@ mod tests { } #[test] - fn from_sat_per_vb_unchecked() { - let fee_rate = FeeRate::from_sat_per_vb_unchecked(10); + fn from_sat_per_vb_u32() { + let fee_rate = FeeRate::from_sat_per_vb_u32(10); assert_eq!(FeeRate::from_sat_per_kwu(2500), fee_rate); } #[test] #[cfg(debug_assertions)] - #[should_panic = "attempt to multiply with overflow"] - fn from_sat_per_vb_unchecked_panic() { FeeRate::from_sat_per_vb_unchecked(u64::MAX); } + fn from_sat_per_vb_u32_cannot_panic() { FeeRate::from_sat_per_vb_u32(u32::MAX); } #[test] fn raw_feerate() { From 7e67737393bc1a966bf2ce544d291ea30dc4f0f7 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 19 May 2025 13:25:48 +1000 Subject: [PATCH 018/857] Use / to divide fee by weight Looks like this code was written before we added support for dividing `Amount` by `Weight`. Refactor, no logic change. --- bitcoin/src/psbt/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9418ae8bf7..14eeb7e7b4 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -20,6 +20,7 @@ use std::collections::{HashMap, HashSet}; use internals::write_err; use secp256k1::{Keypair, Message, Secp256k1, Signing, Verification}; +use units::NumOpResult; use crate::bip32::{self, DerivationPath, KeySource, Xpriv, Xpub}; use crate::crypto::key::{PrivateKey, PublicKey}; @@ -209,11 +210,14 @@ impl Psbt { let tx = self.internal_extract_tx(); // Now that the extracted Transaction is made, decide how to return it. - let fee_rate = - FeeRate::from_sat_per_kwu(fee.to_sat().saturating_mul(1000) / tx.weight().to_wu()); - // Prefer to return an AbsurdFeeRate error when both trigger. - if fee_rate > max_fee_rate { - return Err(ExtractTxError::AbsurdFeeRate { fee_rate, tx }); + match fee / tx.weight() { + NumOpResult::Valid(fee_rate) => { + // Prefer to return an AbsurdFeeRate error when both trigger. + if fee_rate > max_fee_rate { + return Err(ExtractTxError::AbsurdFeeRate { fee_rate, tx }); + } + } + NumOpResult::Error(_) => unreachable!("weight() is always non-zero"), } Ok(tx) From 1fef5a3dc55bfc1858c32f81f18840ec1d01c807 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 22 May 2025 10:50:34 +1000 Subject: [PATCH 019/857] units: re-order ceil/floor functions We have 4 functions, 2 ceil, 2 floor but they are ordered ceil, floor, floor, ceil - this causes my head to twitch when I read it. The logic in the floor versions is easier so put them first, this is uniform with `fee_rate/mod.rs`. Code move only. --- units/src/fee.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index e08c9c89a0..4dc6c4b562 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -18,6 +18,24 @@ use NumOpResult as R; use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight}; impl Amount { + /// Checked weight floor division. + /// + /// Be aware that integer division loses the remainder if no exact division + /// can be made. See also [`Self::checked_div_by_weight_ceil`]. + /// + /// Returns [`None`] if overflow occurred. + #[must_use] + pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option { + // No `?` operator in const context. + match self.to_sat().checked_mul(1_000) { + Some(res) => match res.checked_div(weight.to_wu()) { + Some(fee_rate) => Some(FeeRate::from_sat_per_kwu(fee_rate)), + None => None, + }, + None => None, + } + } + /// Checked weight ceiling division. /// /// Be aware that integer division loses the remainder if no exact division @@ -52,24 +70,6 @@ impl Amount { None } - /// Checked weight floor division. - /// - /// Be aware that integer division loses the remainder if no exact division - /// can be made. See also [`Self::checked_div_by_weight_ceil`]. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option { - // No `?` operator in const context. - match self.to_sat().checked_mul(1_000) { - Some(res) => match res.checked_div(weight.to_wu()) { - Some(fee_rate) => Some(FeeRate::from_sat_per_kwu(fee_rate)), - None => None, - }, - None => None, - } - } - /// Checked fee rate floor division. /// /// Computes the maximum weight that would result in a fee less than or equal to this amount From 395252c6d95fdd581ce5e8ad5d7978515aafea23 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 10:28:59 +1000 Subject: [PATCH 020/857] Fix FeeRate::checked_add/sub Currently the `checked_add` and `checked_sub` functions use a `u64` for the right hand side. This leaks the inner unit because the RHS value is implicitly in the same unit. Make the functions have `FeeRate` on the RHS. --- units/src/fee_rate/mod.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 520790e370..6b1cd3ca5d 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -110,9 +110,9 @@ impl FeeRate { /// /// Computes `self + rhs` returning [`None`] if overflow occurred. #[must_use] - pub const fn checked_add(self, rhs: u64) -> Option { + pub const fn checked_add(self, rhs: FeeRate) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu().checked_add(rhs) { + match self.to_sat_per_kwu().checked_add(rhs.to_sat_per_kwu()) { Some(res) => Some(Self::from_sat_per_kwu(res)), None => None, } @@ -122,9 +122,9 @@ impl FeeRate { /// /// Computes `self - rhs` returning [`None`] if overflow occurred. #[must_use] - pub const fn checked_sub(self, rhs: u64) -> Option { + pub const fn checked_sub(self, rhs: FeeRate) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu().checked_sub(rhs) { + match self.to_sat_per_kwu().checked_sub(rhs.to_sat_per_kwu()) { Some(res) => Some(Self::from_sat_per_kwu(res)), None => None, } @@ -260,19 +260,24 @@ mod tests { #[test] fn checked_add() { - let f = FeeRate::from_sat_per_kwu(1).checked_add(2).unwrap(); - assert_eq!(FeeRate::from_sat_per_kwu(3), f); + let one = FeeRate::from_sat_per_kwu(1); + let two = FeeRate::from_sat_per_kwu(2); + let three = FeeRate::from_sat_per_kwu(3); + + assert_eq!(one.checked_add(two).unwrap(), three); - let f = FeeRate::from_sat_per_kwu(u64::MAX).checked_add(1); + let f = FeeRate::from_sat_per_kwu(u64::MAX).checked_add(one); assert!(f.is_none()); } #[test] fn checked_sub() { - let f = FeeRate::from_sat_per_kwu(2).checked_sub(1).unwrap(); - assert_eq!(FeeRate::from_sat_per_kwu(1), f); + let one = FeeRate::from_sat_per_kwu(1); + let two = FeeRate::from_sat_per_kwu(2); + let three = FeeRate::from_sat_per_kwu(3); + assert_eq!(three.checked_sub(two).unwrap(), one); - let f = FeeRate::ZERO.checked_sub(1); + let f = FeeRate::ZERO.checked_sub(one); assert!(f.is_none()); } From c63f80baec0780622d70e4c8699369b0a972cb62 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 10:32:17 +1000 Subject: [PATCH 021/857] Remove impl From for FeeRate This function leaks the inner unit of `FeeRate`. We want to change the unit, best to break downstream so they notice. --- units/src/fee_rate/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 520790e370..6f7fe7fabe 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -131,10 +131,6 @@ impl FeeRate { } } -impl From for u64 { - fn from(value: FeeRate) -> Self { value.to_sat_per_kwu() } -} - crate::internal_macros::impl_op_for_references! { impl ops::Add for FeeRate { type Output = FeeRate; @@ -195,12 +191,6 @@ mod tests { use super::*; - #[test] - fn sanity_check() { - let fee_rate: u64 = u64::from(FeeRate::from_sat_per_kwu(100)); - assert_eq!(fee_rate, 100_u64); - } - #[test] #[allow(clippy::op_ref)] fn feerate_div_nonzero() { From 0a0e23fedf3552df677b379d86a1e0ac6b063152 Mon Sep 17 00:00:00 2001 From: frankomosh Date: Thu, 22 May 2025 20:12:11 +0300 Subject: [PATCH 022/857] style: use Self:: instead of type aliases in error impls Use instead of 'use FooError as E' when pattern matching on the same type in Display/Error trait implementations. --- primitives/src/transaction.rs | 20 ++++++++------------ units/src/amount/error.rs | 9 +++------ units/src/locktime/absolute.rs | 20 +++++++++----------- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 10176ef767..ef322e62be 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -471,14 +471,12 @@ impl From for ParseOutPointError { #[cfg(feature = "hex")] impl fmt::Display for ParseOutPointError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use ParseOutPointError as E; - match *self { - E::Txid(ref e) => write_err!(f, "error parsing TXID"; e), - E::Vout(ref e) => write_err!(f, "error parsing vout"; e), - E::Format => write!(f, "OutPoint not in : format"), - E::TooLong => write!(f, "vout should be at most 10 digits"), - E::VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"), + Self::Txid(ref e) => write_err!(f, "error parsing TXID"; e), + Self::Vout(ref e) => write_err!(f, "error parsing vout"; e), + Self::Format => write!(f, "OutPoint not in : format"), + Self::TooLong => write!(f, "vout should be at most 10 digits"), + Self::VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"), } } } @@ -487,12 +485,10 @@ impl fmt::Display for ParseOutPointError { #[cfg(feature = "hex")] impl std::error::Error for ParseOutPointError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use ParseOutPointError as E; - match self { - E::Txid(e) => Some(e), - E::Vout(e) => Some(e), - E::Format | E::TooLong | E::VoutNotCanonical => None, + Self::Txid(e) => Some(e), + Self::Vout(e) => Some(e), + Self::Format | Self::TooLong | Self::VoutNotCanonical => None, } } } diff --git a/units/src/amount/error.rs b/units/src/amount/error.rs index dd06db041d..fbb1cfdfd9 100644 --- a/units/src/amount/error.rs +++ b/units/src/amount/error.rs @@ -337,11 +337,9 @@ impl From for ParseDenominationError { impl fmt::Display for ParseDenominationError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use ParseDenominationError as E; - match *self { - E::Unknown(ref e) => write_err!(f, "denomination parse error"; e), - E::PossiblyConfusing(ref e) => write_err!(f, "denomination parse error"; e), + Self::Unknown(ref e) => write_err!(f, "denomination parse error"; e), + Self::PossiblyConfusing(ref e) => write_err!(f, "denomination parse error"; e), } } } @@ -349,10 +347,9 @@ impl fmt::Display for ParseDenominationError { #[cfg(feature = "std")] impl std::error::Error for ParseDenominationError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use ParseDenominationError as E; match *self { - E::Unknown(_) | E::PossiblyConfusing(_) => None, + Self::Unknown(_) | Self::PossiblyConfusing(_) => None, } } } diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index f80ccdfee2..ee50262ef2 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -377,10 +377,9 @@ impl ParseError { ) -> fmt::Result { use core::num::IntErrorKind; - use ParseError as E; match self { - E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) + Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) if *source.kind() == IntErrorKind::PosOverflow => { // Outputs "failed to parse as absolute Height/MedianTimePast ( is above limit )" @@ -392,7 +391,7 @@ impl ParseError { upper_bound ) } - E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) + Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) if *source.kind() == IntErrorKind::NegOverflow => { // Outputs "failed to parse as absolute Height/MedianTimePast ( is below limit )" @@ -404,7 +403,7 @@ impl ParseError { lower_bound ) } - E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => { + Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => { write!( f, "{} ({})", @@ -412,10 +411,10 @@ impl ParseError { subject ) } - E::Conversion(value) if *value < i64::from(lower_bound) => { + Self::Conversion(value) if *value < i64::from(lower_bound) => { write!(f, "{} {} is below limit {}", subject, value, lower_bound) } - E::Conversion(value) => { + Self::Conversion(value) => { write!(f, "{} {} is above limit {}", subject, value, upper_bound) } } @@ -426,17 +425,16 @@ impl ParseError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use core::num::IntErrorKind; - use ParseError as E; match self { - E::ParseInt(ParseIntError { source, .. }) + Self::ParseInt(ParseIntError { source, .. }) if *source.kind() == IntErrorKind::PosOverflow => None, - E::ParseInt(ParseIntError { source, .. }) + Self::ParseInt(ParseIntError { source, .. }) if *source.kind() == IntErrorKind::NegOverflow => None, - E::ParseInt(ParseIntError { source, .. }) => Some(source), - E::Conversion(_) => None, + Self::ParseInt(ParseIntError { source, .. }) => Some(source), + Self::Conversion(_) => None, } } } From cd610464ec17b59fedc875e4da75ec4217d6b784 Mon Sep 17 00:00:00 2001 From: Fallengirl <155266340+Fallengirl@users.noreply.github.com> Date: Thu, 22 May 2025 19:57:15 +0200 Subject: [PATCH 023/857] fix dead link CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9787a84c4f..bf35defc27 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -419,7 +419,7 @@ hacking on this codebase. Consider the following format, not all sections will b /// /// ### Relevant BIPs /// -/// * [BIP X - FooBar in Bitcoin](https://github.com/bitcoin/bips/blob/master/bip-0000.mediawiki) +/// * [BIP X - FooBar in Bitcoin](https://github.com/bitcoin/bips/blob/master/bip-0001.mediawiki) pub struct FooBar { /// The version in use. pub version: Version From 62026c1e2dd0a1d0b8f12fc6d55c06de0ddc002e Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Tue, 13 May 2025 22:05:56 -0500 Subject: [PATCH 024/857] Don't use PSBT_GLOBAL_XPUB as an unknown key in Psbt serde test The previous test used global key id 1 which is not unknown, it's PSBT_GLOBAL_XPUB. That's an inconsistent state for a Psbt to be in, and will cause a deserialization error when the Psbt serde implementation is modified to use the BIP-174 format. --- bitcoin/src/psbt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9418ae8bf7..9b146a9d6d 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1586,7 +1586,7 @@ mod tests { }], }; let unknown: BTreeMap> = - vec![(raw::Key { type_value: 1, key_data: vec![0, 1] }, vec![3, 4, 5])] + vec![(raw::Key { type_value: 42, key_data: vec![0, 1] }, vec![3, 4, 5])] .into_iter() .collect(); let key_source = ("deadbeef".parse().unwrap(), "0'/1".parse().unwrap()); From d7e9a8433939e23838123932ef0186fe315e5c42 Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Tue, 13 May 2025 22:06:16 -0500 Subject: [PATCH 025/857] Fix Psbt preimage keys in serde test The preimage values in the serde Psbt don't actually correspond to the hash keys they should in the serde test. This doesn't cause an error currently because the derived serde implementation doesn't enforce their validity during deserialization, but it will when the serde implementation is modified to use the BIP-174 format. --- bitcoin/src/psbt/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9b146a9d6d..47be38fa82 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1641,10 +1641,10 @@ mod tests { )].into_iter().collect(), bip32_derivation: keypaths.clone(), final_script_witness: Some(Witness::from_slice(&[vec![1, 3], vec![5]])), - ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), - sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), - hash160_preimages: vec![(hash160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), - hash256_preimages: vec![(sha256d::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), + ripemd160_preimages: vec![(ripemd160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), + sha256_preimages: vec![(sha256::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), + hash160_preimages: vec![(hash160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), + hash256_preimages: vec![(sha256d::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), proprietary: proprietary.clone(), unknown: unknown.clone(), ..Default::default() From 9aa235c24d65d23de2afc21fcbd019892bf4ad2a Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Sun, 11 May 2025 10:28:19 -0500 Subject: [PATCH 026/857] BREAKING: Change Psbt serde implementations Replace derived Psbt serde implementation with one that conforms to BIP-174. In human readable serde contexts, serialize to the base64 encoded format, and in binary serde contexts, serialize to the raw binary format. The previous derived serde implementation cannot be used in a backward or forward compatible way in binary formats like bincode, which means that every field added to the Psbt struct would break serde de/serialization into binary formats. Instead, this one-time breaking change will fix the issue going forward. Downstream users with persisted data in the old serde format should continue using 0.32.x to create migrations to the new format. --- bitcoin/CHANGELOG.md | 4 + bitcoin/Cargo.toml | 2 +- bitcoin/src/lib.rs | 2 - bitcoin/src/psbt/map/input.rs | 12 - bitcoin/src/psbt/map/output.rs | 5 - bitcoin/src/psbt/mod.rs | 50 ++- bitcoin/src/psbt/raw.rs | 7 - bitcoin/src/serde_utils.rs | 298 ------------------ .../tests/data/serde/proprietary_key_bincode | Bin 32 -> 0 bytes bitcoin/tests/data/serde/psbt_base64.json | 1 + bitcoin/tests/data/serde/psbt_bincode | Bin 1377 -> 810 bytes bitcoin/tests/data/serde/raw_pair_bincode | Bin 32 -> 0 bytes bitcoin/tests/serde.rs | 29 +- 13 files changed, 58 insertions(+), 352 deletions(-) delete mode 100644 bitcoin/src/serde_utils.rs delete mode 100644 bitcoin/tests/data/serde/proprietary_key_bincode create mode 100644 bitcoin/tests/data/serde/psbt_base64.json delete mode 100644 bitcoin/tests/data/serde/raw_pair_bincode diff --git a/bitcoin/CHANGELOG.md b/bitcoin/CHANGELOG.md index bbe596b713..6b593c7bfc 100644 --- a/bitcoin/CHANGELOG.md +++ b/bitcoin/CHANGELOG.md @@ -4,6 +4,10 @@ - Use MAX_MONEY in serde regression test [#3950](https://github.com/rust-bitcoin/rust-bitcoin/pull/3950) +## Breaking changes + +- Change Psbt serde implementation to contextually use the PSBT binary or base64 encoded formats described in BIP-174. + # 0.33.0-alpha.0 - 2024-11-18 This series of alpha releases is meant for two things: diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index 075ddbd893..39547f0235 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -19,7 +19,7 @@ default = [ "std", "secp-recovery" ] std = ["base58/std", "bech32/std", "hashes/std", "hex/std", "internals/std", "io/std", "primitives/std", "secp256k1/std", "units/std", "base64?/std", "bitcoinconsensus?/std"] rand-std = ["secp256k1/rand", "std"] rand = ["secp256k1/rand"] -serde = ["dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"] +serde = ["base64", "dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"] secp-lowmemory = ["secp256k1/lowmemory"] secp-recovery = ["secp256k1/recovery"] arbitrary = ["dep:arbitrary", "units/arbitrary", "primitives/arbitrary"] diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index a57ababdeb..cb68c35434 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -92,8 +92,6 @@ pub extern crate secp256k1; extern crate serde; mod internal_macros; -#[cfg(feature = "serde")] -mod serde_utils; #[macro_use] pub mod p2p; diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index d33be651b5..287c7f3625 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -65,7 +65,6 @@ const PSBT_IN_PROPRIETARY: u64 = 0xFC; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Input { /// The non-witness transaction this input spends from. Should only be /// `Option::Some` for inputs which spend non-SegWit outputs or @@ -87,7 +86,6 @@ pub struct Input { pub witness_script: Option, /// A map from public keys needed to sign this input to their corresponding /// master key fingerprints and derivation paths. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub bip32_derivation: BTreeMap, /// The finalized, fully-constructed scriptSig with signatures and any other /// scripts necessary for this input to pass validation. @@ -96,37 +94,28 @@ pub struct Input { /// other scripts necessary for this input to pass validation. pub final_script_witness: Option, /// RIPEMD160 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub ripemd160_preimages: BTreeMap>, /// SHA256 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub sha256_preimages: BTreeMap>, /// HASH160 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub hash160_preimages: BTreeMap>, /// HASH256 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub hash256_preimages: BTreeMap>, /// Serialized Taproot signature with sighash type for key spend. pub tap_key_sig: Option, /// Map of `|` with signature. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), taproot::Signature>, /// Map of Control blocks to Script version pair. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_scripts: BTreeMap, /// Map of tap root x only keys to origin info and leaf hashes contained in it. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_key_origins: BTreeMap, KeySource)>, /// Taproot Internal key. pub tap_internal_key: Option, /// Taproot Merkle root. pub tap_merkle_root: Option, /// Proprietary key-value pairs for this input. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this input. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub unknown: BTreeMap>, } @@ -147,7 +136,6 @@ pub struct Input { /// let _tap_sighash_all: PsbtSighashType = TapSighashType::All.into(); /// ``` #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PsbtSighashType { pub(in crate::psbt) inner: u32, } diff --git a/bitcoin/src/psbt/map/output.rs b/bitcoin/src/psbt/map/output.rs index 22e28abc63..7f86bdb659 100644 --- a/bitcoin/src/psbt/map/output.rs +++ b/bitcoin/src/psbt/map/output.rs @@ -26,7 +26,6 @@ const PSBT_OUT_PROPRIETARY: u64 = 0xFC; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Output { /// The redeem script for this output. pub redeem_script: Option, @@ -34,20 +33,16 @@ pub struct Output { pub witness_script: Option, /// A map from public keys needed to spend this output to their /// corresponding master key fingerprints and derivation paths. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub bip32_derivation: BTreeMap, /// The internal pubkey. pub tap_internal_key: Option, /// Taproot Output tree. pub tap_tree: Option, /// Map of tap root x only keys to origin info and leaf hashes contained in it. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_key_origins: BTreeMap, KeySource)>, /// Proprietary key-value pairs for this output. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this output. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub unknown: BTreeMap>, } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 47be38fa82..a9c8c39516 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -40,7 +40,6 @@ pub use self::{ /// A Partially Signed Transaction. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Psbt { /// The unsigned transaction, scriptSigs and witnesses for each input must be empty. pub unsigned_tx: Transaction, @@ -50,10 +49,8 @@ pub struct Psbt { /// derivation path as defined by BIP 32. pub xpub: BTreeMap, /// Global proprietary key-value pairs. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, /// Unknown global key-value pairs. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub unknown: BTreeMap>, /// The corresponding key-value map for each input in the unsigned transaction. @@ -731,6 +728,53 @@ impl Psbt { } } +#[cfg(feature = "serde")] +impl serde::Serialize for Psbt { + fn serialize(&self, serializer: S) -> Result { + use crate::prelude::ToString; + + if serializer.is_human_readable() { + serializer.serialize_str(&self.to_string()) + } else { + serializer.serialize_bytes(&self.serialize()) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Psbt { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> + { + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor + { + type Value = Psbt; + + fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "a psbt") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result { + Psbt::deserialize(bytes) + .map_err(|e| serde::de::Error::custom(e)) + } + + fn visit_str(self, s: &str) -> Result { + s.parse().map_err(|e| serde::de::Error::custom(e)) + } + } + + if deserializer.is_human_readable() { + deserializer.deserialize_str(Visitor) + } else { + deserializer.deserialize_bytes(Visitor) + } + } +} + /// Data required to call [`GetKey`] to get the private key to sign an input. #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] diff --git a/bitcoin/src/psbt/raw.rs b/bitcoin/src/psbt/raw.rs index 4502bde61f..205d076b57 100644 --- a/bitcoin/src/psbt/raw.rs +++ b/bitcoin/src/psbt/raw.rs @@ -21,25 +21,21 @@ use crate::psbt::Error; /// /// ` := ` #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Key { /// The type of this PSBT key. pub type_value: u64, // Encoded as a compact size. /// The key data itself in raw byte form. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub key_data: Vec, } /// A PSBT key-value pair in its raw byte form. /// ` := ` #[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Pair { /// The key of this key-value pair. pub key: Key, /// The value data of this key-value pair in raw byte form. /// ` := ` - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub value: Vec, } @@ -49,19 +45,16 @@ pub type ProprietaryType = u64; /// Proprietary keys (i.e. keys starting with 0xFC byte) with their internal /// structure according to BIP 174. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ProprietaryKey where Subtype: Copy + From + Into, { /// Proprietary type prefix used for grouping together keys under some /// application and avoid namespace collision - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub prefix: Vec, /// Custom proprietary subtype pub subtype: Subtype, /// Additional key bytes (like serialized public key data etc) - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub key: Vec, } diff --git a/bitcoin/src/serde_utils.rs b/bitcoin/src/serde_utils.rs deleted file mode 100644 index df306d9df5..0000000000 --- a/bitcoin/src/serde_utils.rs +++ /dev/null @@ -1,298 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Bitcoin serde utilities. -//! -//! This module is for special serde serializations. - -pub(crate) struct SerializeBytesAsHex<'a>(pub(crate) &'a [u8]); - -impl serde::Serialize for SerializeBytesAsHex<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use hex::DisplayHex; - - serializer.collect_str(&format_args!("{:x}", self.0.as_hex())) - } -} - -pub mod btreemap_byte_values { - //! Module for serialization of BTreeMaps with hex byte values. - #![allow(missing_docs)] - - // NOTE: This module can be exactly copied to use with HashMap. - - use hex::FromHex; - - use crate::prelude::{BTreeMap, Vec}; - - pub fn serialize(v: &BTreeMap>, s: S) -> Result - where - S: serde::Serializer, - T: serde::Serialize + core::hash::Hash + Eq + Ord, - { - use serde::ser::SerializeMap; - - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(v, s) - } else { - let mut map = s.serialize_map(Some(v.len()))?; - for (key, value) in v.iter() { - map.serialize_entry(key, &super::SerializeBytesAsHex(value))?; - } - map.end() - } - } - - pub fn deserialize<'de, D, T>(d: D) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - use core::marker::PhantomData; - - struct Visitor(PhantomData); - impl<'de, T> serde::de::Visitor<'de> for Visitor - where - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - type Value = BTreeMap>; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a map with hexadecimal values") - } - - fn visit_map>( - self, - mut a: A, - ) -> Result { - let mut ret = BTreeMap::new(); - while let Some((key, value)) = a.next_entry()? { - ret.insert(key, FromHex::from_hex(value).map_err(serde::de::Error::custom)?); - } - Ok(ret) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_map(Visitor(PhantomData)) - } - } -} - -pub mod btreemap_as_seq { - //! Module for serialization of BTreeMaps as lists of sequences because - //! serde_json will not serialize hashmaps with non-string keys be default. - #![allow(missing_docs)] - - // NOTE: This module can be exactly copied to use with HashMap. - - use crate::prelude::BTreeMap; - - pub fn serialize(v: &BTreeMap, s: S) -> Result - where - S: serde::Serializer, - T: serde::Serialize + core::hash::Hash + Eq + Ord, - U: serde::Serialize, - { - use serde::ser::SerializeSeq; - - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(v, s) - } else { - let mut seq = s.serialize_seq(Some(v.len()))?; - for pair in v.iter() { - seq.serialize_element(&pair)?; - } - seq.end() - } - } - - pub fn deserialize<'de, D, T, U>(d: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - U: serde::Deserialize<'de>, - { - use core::marker::PhantomData; - - struct Visitor(PhantomData<(T, U)>); - impl<'de, T, U> serde::de::Visitor<'de> for Visitor - where - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - U: serde::Deserialize<'de>, - { - type Value = BTreeMap; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a sequence of pairs") - } - - fn visit_seq>( - self, - mut a: A, - ) -> Result { - let mut ret = BTreeMap::new(); - while let Some((key, value)) = a.next_element()? { - ret.insert(key, value); - } - Ok(ret) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_seq(Visitor(PhantomData)) - } - } -} - -pub mod btreemap_as_seq_byte_values { - //! Module for serialization of BTreeMaps as lists of sequences because - //! serde_json will not serialize hashmaps with non-string keys be default. - #![allow(missing_docs)] - - // NOTE: This module can be exactly copied to use with HashMap. - - use crate::prelude::{BTreeMap, Vec}; - - /// A custom key-value pair type that serialized the bytes as hex. - #[derive(Debug, Deserialize)] - struct OwnedPair( - T, - #[serde(deserialize_with = "crate::serde_utils::hex_bytes::deserialize")] Vec, - ); - - /// A custom key-value pair type that serialized the bytes as hex. - #[derive(Debug, Serialize)] - struct BorrowedPair<'a, T: 'static>( - &'a T, - #[serde(serialize_with = "crate::serde_utils::hex_bytes::serialize")] &'a [u8], - ); - - pub fn serialize(v: &BTreeMap>, s: S) -> Result - where - S: serde::Serializer, - T: serde::Serialize + core::hash::Hash + Eq + Ord + 'static, - { - use serde::ser::SerializeSeq; - - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(v, s) - } else { - let mut seq = s.serialize_seq(Some(v.len()))?; - for (key, value) in v.iter() { - seq.serialize_element(&BorrowedPair(key, value))?; - } - seq.end() - } - } - - pub fn deserialize<'de, D, T>(d: D) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - use core::marker::PhantomData; - - struct Visitor(PhantomData); - impl<'de, T> serde::de::Visitor<'de> for Visitor - where - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - type Value = BTreeMap>; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a sequence of pairs") - } - - fn visit_seq>( - self, - mut a: A, - ) -> Result { - let mut ret = BTreeMap::new(); - while let Option::Some(OwnedPair(key, value)) = a.next_element()? { - ret.insert(key, value); - } - Ok(ret) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_seq(Visitor(PhantomData)) - } - } -} - -pub mod hex_bytes { - //! Module for serialization of byte arrays as hex strings. - #![allow(missing_docs)] - - use hex::FromHex; - - pub fn serialize(bytes: &T, s: S) -> Result - where - T: serde::Serialize + AsRef<[u8]>, - S: serde::Serializer, - { - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(bytes, s) - } else { - serde::Serialize::serialize(&super::SerializeBytesAsHex(bytes.as_ref()), s) - } - } - - pub fn deserialize<'de, D, B>(d: D) -> Result - where - D: serde::Deserializer<'de>, - B: serde::Deserialize<'de> + FromHex, - { - struct Visitor(core::marker::PhantomData); - - impl serde::de::Visitor<'_> for Visitor { - type Value = B; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_str("an ASCII hex string") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - if let Ok(hex) = core::str::from_utf8(v) { - FromHex::from_hex(hex).map_err(E::custom) - } else { - Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)) - } - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - FromHex::from_hex(v).map_err(E::custom) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_str(Visitor(core::marker::PhantomData)) - } - } -} diff --git a/bitcoin/tests/data/serde/proprietary_key_bincode b/bitcoin/tests/data/serde/proprietary_key_bincode deleted file mode 100644 index 8c0100713be8a87a97c9e4926701c50a89dcac89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 TcmZQ!fC5G)W=1HJ1xXA50dN2o diff --git a/bitcoin/tests/data/serde/psbt_base64.json b/bitcoin/tests/data/serde/psbt_base64.json new file mode 100644 index 0000000000..6bb318f103 --- /dev/null +++ b/bitcoin/tests/data/serde/psbt_base64.json @@ -0,0 +1 @@ +"cHNidP8BAFMBAAAAAYmjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAAAD/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAAAAAE8BBIiyHgAAAAAAAAAAAIc9/4HAL1JWI/0f5RZ+rDpVoEnePTFLtC7iJ//tN9UIAzmjYBMwFZfa70H75ZOgLMUT0LVVJ+wt8QUOLo/0nIXCDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAAEAjwEAAAAAAQGJo8ceq00g4Dcbu6TMaY+ilclGOvouOX+FM8y2L5Vn5QEAAAAXFgAUvhjRUqmwEgOdrz2n3k9TNJ7suYX/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUAAAAAAQEgcv74TiwAAAAXqRQzlyW6Ie/WKsdTqbzQZ9bHpqOdBYciAgM5iA3JI5S3NV49BDn6KDwx3nWQgS6gEcQkXAZ0poXog0cwRAIgT2fir7dhQtRPrliiSV0zo0GdqibNDbjQTzRStjKJrA8CIBB2Kp+2fpTMXK2QJvbcmf9/Bw9CeNMPvH0Mhp3TjH/nAQEDBIMAAAABBAFRIgYDOYgNySOUtzVePQQ5+ig8Md51kIEuoBHEJFwGdKaF6IMM3q2+7wAAAIABAAAAAQgGAgIBAwEFFQoYn3yLGjhv/o7tkbODDHp7zR53jAIBAiELoShx/uIQ+4YZKR6uoZRYHL0lMeSyN1nSJfaAaSP2MiICAQIVDBXMSeGRy8Ug2RlEYApct3r2qjKRAgECIQ12pWrO2RXSUT3NhMLDeLLoqlzWMrW3HKLyrFsOOmSb2wIBAhD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFACICAzmIDckjlLc1Xj0EOfooPDHedZCBLqARxCRcBnSmheiDDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAA==" \ No newline at end of file diff --git a/bitcoin/tests/data/serde/psbt_bincode b/bitcoin/tests/data/serde/psbt_bincode index 2c352b99c33227c4258ba8380928e5fa0a2e694f..35d580f4b0ddd26395b7974739e0cd48ad82fbe4 100644 GIT binary patch delta 447 zcmaFJwTewtiJ1Wm3W}3T{xdQJGXi;x6D3sn{sRGH(Z3&lIzSQe$pK8_^&o}*j4U0S z8KE zSw*=d=GSyfS>*rgdpmJ+Gf!3ZS-J8aCPpSj?#WA;6TzdDCGnxI1rk-@O`lV-C-)ekjoBq`Fr!e&(<^O>I zs*M3AUi9yWpAJw^94fI=#CW>uF2(oPw2lX_+;buQ+VN$J=d!kgWMNwJp-L+XN|VgY z41Fto%N+}Yl9Js@BGQ9RizB@poeB%xEhBw$olOD_gHjR;EYpKsE&K{g$}5xHGg1R0 zjnboxEM0@$vI@QOol6aaN(-`5Eh0%tr&yIK8cG#D>n!+&s}f3{GNZX$-Fl^TS3tRGhPvD zEc2y@VI@ zQ?{GN*|J#v(y%eSS303lZ-L+ul^C{?Wvwro-Jlu_T$mL6(;uzhp6GPNe_g~P&sgKd zj&oP3o#owe!QUikn^ET)ekKKhGOhXB>ZY8DSvx`P+nt&J>)H98DlYTyspV;#d%36n zIXBd_U{7}s$6$|mM;{-?W}p~6_yggokeQInU}*$By)ZDsVj4y>GQ)x&9;_lzhe*t? z>6Ws{|JV0+;^t?vECb?&CHdN|}8dp%dybY!uA#G|e}NQiJ^Xf;*n3E(QSM&@@m0 diff --git a/bitcoin/tests/data/serde/raw_pair_bincode b/bitcoin/tests/data/serde/raw_pair_bincode deleted file mode 100644 index bf1d3218ac25dc751f2281d92e2067b95d236da0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 TcmZQ%fB+UK&A`aSjLZfA0W1I( diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index f9e7e4a6a3..136d724183 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -30,7 +30,7 @@ use bitcoin::consensus::encode::deserialize; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use bitcoin::hex::FromHex; use bitcoin::locktime::{absolute, relative}; -use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; +use bitcoin::psbt::raw; use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; use bitcoin::script::ScriptBufExt as _; use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; @@ -320,30 +320,11 @@ fn serde_regression_psbt() { let got = serialize(&psbt).unwrap(); let want = include_bytes!("data/serde/psbt_bincode") as &[_]; - assert_eq!(got, want) -} - -#[test] -fn serde_regression_raw_pair() { - let pair = Pair { - key: Key { type_value: 1u64, key_data: vec![0u8, 1u8, 2u8, 3u8] }, - value: vec![0u8, 1u8, 2u8, 3u8], - }; - let got = serialize(&pair).unwrap(); - let want = include_bytes!("data/serde/raw_pair_bincode") as &[_]; - assert_eq!(got, want) -} + assert_eq!(got, want); -#[test] -fn serde_regression_proprietary_key() { - let key = ProprietaryKey { - prefix: vec![0u8, 1u8, 2u8, 3u8], - subtype: 1u64, - key: vec![0u8, 1u8, 2u8, 3u8], - }; - let got = serialize(&key).unwrap(); - let want = include_bytes!("data/serde/proprietary_key_bincode") as &[_]; - assert_eq!(got, want) + let got = serde_json::to_string(&psbt).unwrap(); + let want = include_str!("data/serde/psbt_base64.json"); + assert_eq!(got, want); } #[test] From 2e16dbb7e5a25fb85f513c4fe6d432e232f5c34a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 11:05:03 +1000 Subject: [PATCH 027/857] fee_rate: Put test assertions in correct order By convention we put assertions in the order `got` then `want`. This makes debugging easier. --- units/src/fee_rate/mod.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index d21fa6aafa..f132c01c7f 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -274,23 +274,23 @@ mod tests { #[test] fn fee_rate_const() { - assert_eq!(0, FeeRate::ZERO.to_sat_per_kwu()); - assert_eq!(u64::MIN, FeeRate::MIN.to_sat_per_kwu()); - assert_eq!(u64::MAX, FeeRate::MAX.to_sat_per_kwu()); - assert_eq!(250, FeeRate::BROADCAST_MIN.to_sat_per_kwu()); - assert_eq!(750, FeeRate::DUST.to_sat_per_kwu()); + assert_eq!(FeeRate::ZERO.to_sat_per_kwu(), 0); + assert_eq!(FeeRate::MIN.to_sat_per_kwu(), u64::MIN); + assert_eq!(FeeRate::MAX.to_sat_per_kwu(), u64::MAX); + assert_eq!(FeeRate::BROADCAST_MIN.to_sat_per_kwu(), 250); + assert_eq!(FeeRate::DUST.to_sat_per_kwu(), 750); } #[test] fn fee_rate_from_sat_per_vb() { let fee_rate = FeeRate::from_sat_per_vb(10).expect("expected feerate in sat/kwu"); - assert_eq!(FeeRate::from_sat_per_kwu(2500), fee_rate); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); } #[test] fn fee_rate_from_sat_per_kvb() { let fee_rate = FeeRate::from_sat_per_kvb(11); - assert_eq!(FeeRate::from_sat_per_kwu(2), fee_rate); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2)); } #[test] @@ -302,7 +302,7 @@ mod tests { #[test] fn from_sat_per_vb_u32() { let fee_rate = FeeRate::from_sat_per_vb_u32(10); - assert_eq!(FeeRate::from_sat_per_kwu(2500), fee_rate); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); } #[test] @@ -312,16 +312,16 @@ mod tests { #[test] fn raw_feerate() { let fee_rate = FeeRate::from_sat_per_kwu(749); - assert_eq!(749, fee_rate.to_sat_per_kwu()); - assert_eq!(2, fee_rate.to_sat_per_vb_floor()); - assert_eq!(3, fee_rate.to_sat_per_vb_ceil()); + assert_eq!(fee_rate.to_sat_per_kwu(), 749); + assert_eq!(fee_rate.to_sat_per_vb_floor(), 2); + assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3); } #[test] fn checked_mul() { let fee_rate = FeeRate::from_sat_per_kwu(10).checked_mul(10).expect("expected feerate in sat/kwu"); - assert_eq!(FeeRate::from_sat_per_kwu(100), fee_rate); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100)); let fee_rate = FeeRate::from_sat_per_kwu(10).checked_mul(u64::MAX); assert!(fee_rate.is_none()); @@ -331,7 +331,7 @@ mod tests { fn checked_div() { let fee_rate = FeeRate::from_sat_per_kwu(10).checked_div(10).expect("expected feerate in sat/kwu"); - assert_eq!(FeeRate::from_sat_per_kwu(1), fee_rate); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); let fee_rate = FeeRate::from_sat_per_kwu(10).checked_div(0); assert!(fee_rate.is_none()); From dc2cbc21f973251e22901dbf3b4fe80e2fa25b58 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 22 May 2025 11:26:59 +1000 Subject: [PATCH 028/857] Make fee_rate test identifiers uniform We have a bunch of unit tests, some use `f` and some use `fee_rate`. Uniform would be better. Elect to use the longer form just because there are only 4 instances of the shorter one (although I personally prefer the shorter form). --- units/src/fee_rate/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index f132c01c7f..b9aa229ca3 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -257,8 +257,8 @@ mod tests { assert_eq!(one.checked_add(two).unwrap(), three); - let f = FeeRate::from_sat_per_kwu(u64::MAX).checked_add(one); - assert!(f.is_none()); + let fee_rate = FeeRate::from_sat_per_kwu(u64::MAX).checked_add(one); + assert!(fee_rate.is_none()); } #[test] @@ -268,8 +268,8 @@ mod tests { let three = FeeRate::from_sat_per_kwu(3); assert_eq!(three.checked_sub(two).unwrap(), one); - let f = FeeRate::ZERO.checked_sub(one); - assert!(f.is_none()); + let fee_rate = FeeRate::ZERO.checked_sub(one); + assert!(fee_rate.is_none()); } #[test] From 4ed0b8918b19f81dd6da0841d55868d840375cdb Mon Sep 17 00:00:00 2001 From: Update Nightly Rustc Bot Date: Sat, 24 May 2025 01:52:51 +0000 Subject: [PATCH 029/857] Automated update to Github CI to rustc nightly-2025-05-23 --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index 8adb8e5801..0ed7b6b402 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-05-16 +nightly-2025-05-23 From 07c4f760523b7a196bf160f585c2b437dea5b532 Mon Sep 17 00:00:00 2001 From: yancy Date: Thu, 22 May 2025 15:44:00 -0500 Subject: [PATCH 030/857] Add comparison traits to InputWeightPrediction * Partial Eq is added to Enable symmetric and transitive comparison. * Eq is added to enable reflexive comparison. --- bitcoin/src/blockdata/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 9cc1c59399..b521f2cda9 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -928,7 +928,7 @@ pub const fn predict_weight_from_slices( /// This helper type collects information about an input to be used in [`predict_weight`] function. /// It can only be created using the [`new`](InputWeightPrediction::new) function or using other /// associated constants/methods. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct InputWeightPrediction { script_size: usize, witness_size: usize, From c73131c8f0ea7654ac392e4170737092515c1abc Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 25 May 2025 01:42:57 +0000 Subject: [PATCH 031/857] 2025-05-25 automated rustfmt nightly --- bitcoin/src/psbt/mod.rs | 32 ++++++++----------- bitcoin/tests/serde.rs | 3 +- .../bitcoin/p2p_address_roundtrip.rs | 15 ++------- units/src/amount/error.rs | 1 - units/src/locktime/absolute.rs | 2 -- 5 files changed, 18 insertions(+), 35 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 72f053c2fb..325322816a 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -749,12 +749,11 @@ impl serde::Serialize for Psbt { impl<'de> serde::Deserialize<'de> for Psbt { fn deserialize(deserializer: D) -> Result where - D: serde::Deserializer<'de> + D: serde::Deserializer<'de>, { struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor - { + impl<'de> serde::de::Visitor<'de> for Visitor { type Value = Psbt; fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -762,8 +761,7 @@ impl<'de> serde::Deserialize<'de> for Psbt { } fn visit_bytes(self, bytes: &[u8]) -> Result { - Psbt::deserialize(bytes) - .map_err(|e| serde::de::Error::custom(e)) + Psbt::deserialize(bytes).map_err(|e| serde::de::Error::custom(e)) } fn visit_str(self, s: &str) -> Result { @@ -900,11 +898,11 @@ impl GetKey for $map { KeyRequest::XOnlyPubkey(xonly) => { let pubkey_even = xonly.public_key(secp256k1::Parity::Even); let key = self.get(&pubkey_even).cloned(); - + if key.is_some() { return Ok(key); } - + let pubkey_odd = xonly.public_key(secp256k1::Parity::Odd); if let Some(priv_key) = self.get(&pubkey_odd).copied() { let negated_priv_key = priv_key.negate(); @@ -937,18 +935,18 @@ impl GetKey for $map { KeyRequest::XOnlyPubkey(xonly) => Ok(self.get(xonly).cloned()), KeyRequest::Pubkey(pk) => { let (xonly, parity) = pk.inner.x_only_public_key(); - + if let Some(mut priv_key) = self.get(&XOnlyPublicKey::from(xonly)).cloned() { let computed_pk = priv_key.public_key(&secp); let (_, computed_parity) = computed_pk.inner.x_only_public_key(); - + if computed_parity != parity { priv_key = priv_key.negate(); } - + return Ok(Some(priv_key)); } - + Ok(None) }, KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported), @@ -1456,17 +1454,15 @@ mod tests { Err(ABSURD_FEE_RATE) ); assert_eq!( - psbt.clone() - .extract_tx_with_fee_rate_limit(JUST_BELOW_ABSURD_FEE_RATE) - .map_err(|e| match e { + psbt.clone().extract_tx_with_fee_rate_limit(JUST_BELOW_ABSURD_FEE_RATE).map_err(|e| { + match e { ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, _ => panic!(""), - }), + } + }), Err(ABSURD_FEE_RATE) ); - assert!(psbt - .extract_tx_with_fee_rate_limit(ABSURD_FEE_RATE) - .is_ok()); + assert!(psbt.extract_tx_with_fee_rate_limit(ABSURD_FEE_RATE).is_ok()); // Testing that extract_tx will error at 25k sat/vbyte (6250000 sat/kwu) assert_eq!( diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index 136d724183..dce8faf384 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -30,8 +30,7 @@ use bitcoin::consensus::encode::deserialize; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use bitcoin::hex::FromHex; use bitcoin::locktime::{absolute, relative}; -use bitcoin::psbt::raw; -use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; +use bitcoin::psbt::{raw, Input, Output, Psbt, PsbtSighashType}; use bitcoin::script::ScriptBufExt as _; use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder}; diff --git a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs index f5dd65a641..669c5ea928 100644 --- a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs +++ b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs @@ -19,26 +19,17 @@ fn do_test(data: &[u8]) { if let Ok(ip_addr) = IpAddr::try_from(addr_v2.clone()) { let round_trip: AddrV2 = AddrV2::from(ip_addr); - assert_eq!( - addr_v2, round_trip, - "AddrV2 -> IpAddr -> AddrV2 should round-trip correctly" - ); + assert_eq!(addr_v2, round_trip, "AddrV2 -> IpAddr -> AddrV2 should round-trip correctly"); } if let Ok(ip_addr) = Ipv4Addr::try_from(addr_v2.clone()) { let round_trip: AddrV2 = AddrV2::from(ip_addr); - assert_eq!( - addr_v2, round_trip, - "AddrV2 -> Ipv4Addr -> AddrV2 should round-trip correctly" - ); + assert_eq!(addr_v2, round_trip, "AddrV2 -> Ipv4Addr -> AddrV2 should round-trip correctly"); } if let Ok(ip_addr) = Ipv6Addr::try_from(addr_v2.clone()) { let round_trip: AddrV2 = AddrV2::from(ip_addr); - assert_eq!( - addr_v2, round_trip, - "AddrV2 -> Ipv6Addr -> AddrV2 should round-trip correctly" - ); + assert_eq!(addr_v2, round_trip, "AddrV2 -> Ipv6Addr -> AddrV2 should round-trip correctly"); } if let Ok(socket_addr) = SocketAddr::try_from(addr_v2.clone()) { diff --git a/units/src/amount/error.rs b/units/src/amount/error.rs index fbb1cfdfd9..e0946d15c0 100644 --- a/units/src/amount/error.rs +++ b/units/src/amount/error.rs @@ -347,7 +347,6 @@ impl fmt::Display for ParseDenominationError { #[cfg(feature = "std")] impl std::error::Error for ParseDenominationError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match *self { Self::Unknown(_) | Self::PossiblyConfusing(_) => None, } diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index ee50262ef2..46e8a7403c 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -377,7 +377,6 @@ impl ParseError { ) -> fmt::Result { use core::num::IntErrorKind; - match self { Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) if *source.kind() == IntErrorKind::PosOverflow => @@ -425,7 +424,6 @@ impl ParseError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use core::num::IntErrorKind; - match self { Self::ParseInt(ParseIntError { source, .. }) if *source.kind() == IntErrorKind::PosOverflow => From 9fb48bc0efec96e332beb8e0d4c6239eb23b6da5 Mon Sep 17 00:00:00 2001 From: Alex Pikme Date: Sun, 25 May 2025 12:47:49 +0200 Subject: [PATCH 032/857] fix error grater to greater array_vec.rs --- internals/src/array_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internals/src/array_vec.rs b/internals/src/array_vec.rs index 76d0490d5f..98bb3ea85f 100644 --- a/internals/src/array_vec.rs +++ b/internals/src/array_vec.rs @@ -212,7 +212,7 @@ mod verification { } } - #[kani::unwind(16)] // One grater than 15. + #[kani::unwind(16)] // One greater than 15. #[kani::proof] fn no_out_of_bounds_upto_cap() { const CAP: usize = 15; From 3e8e6d9aa14f6eeffb77961326bd6b4c055b82ee Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Thu, 1 May 2025 10:52:50 -0500 Subject: [PATCH 033/857] Add BIP-373 PSBT_{IN,OUT}_MUSIG2_PARTICIPANT_PUBKEYS serialization and deserialization --- bitcoin/src/psbt/map/input.rs | 15 +++++++++++++++ bitcoin/src/psbt/map/output.rs | 14 ++++++++++++++ bitcoin/src/psbt/serialize.rs | 22 ++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index 287c7f3625..2422c57d26 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -59,6 +59,8 @@ const PSBT_IN_TAP_BIP32_DERIVATION: u64 = 0x16; const PSBT_IN_TAP_INTERNAL_KEY: u64 = 0x17; /// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18 const PSBT_IN_TAP_MERKLE_ROOT: u64 = 0x18; +/// Type: MuSig2 Public Keys Participating in Aggregate Input PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS = 0x1a +const PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS: u64 = 0x1a; /// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC const PSBT_IN_PROPRIETARY: u64 = 0xFC; @@ -113,6 +115,8 @@ pub struct Input { pub tap_internal_key: Option, /// Taproot Merkle root. pub tap_merkle_root: Option, + /// Mapping from MuSig2 aggregate keys to the participant keys from which they were aggregated. + pub musig2_participant_pubkeys: BTreeMap>, /// Proprietary key-value pairs for this input. pub proprietary: BTreeMap>, /// Unknown key-value pairs for this input. @@ -352,6 +356,11 @@ impl Input { self.tap_merkle_root <= |< raw_value: TapNodeHash> } } + PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS => { + impl_psbt_insert_pair! { + self.musig2_participant_pubkeys <= |< raw_value: Vec > + } + } PSBT_IN_PROPRIETARY => { let key = raw::ProprietaryKey::try_from(raw_key.clone())?; match self.proprietary.entry(key) { @@ -390,6 +399,7 @@ impl Input { self.tap_script_sigs.extend(other.tap_script_sigs); self.tap_scripts.extend(other.tap_scripts); self.tap_key_origins.extend(other.tap_key_origins); + self.musig2_participant_pubkeys.extend(other.musig2_participant_pubkeys); self.proprietary.extend(other.proprietary); self.unknown.extend(other.unknown); @@ -482,6 +492,11 @@ impl Map for Input { impl_psbt_get_pair! { rv.push(self.tap_merkle_root, PSBT_IN_TAP_MERKLE_ROOT) } + + impl_psbt_get_pair! { + rv.push_map(self.musig2_participant_pubkeys, PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS) + } + for (key, value) in self.proprietary.iter() { rv.push(raw::Pair { key: key.to_key(), value: value.clone() }); } diff --git a/bitcoin/src/psbt/map/output.rs b/bitcoin/src/psbt/map/output.rs index 7f86bdb659..37e853f816 100644 --- a/bitcoin/src/psbt/map/output.rs +++ b/bitcoin/src/psbt/map/output.rs @@ -20,6 +20,8 @@ const PSBT_OUT_TAP_INTERNAL_KEY: u64 = 0x05; const PSBT_OUT_TAP_TREE: u64 = 0x06; /// Type: Taproot Key BIP 32 Derivation Path PSBT_OUT_TAP_BIP32_DERIVATION = 0x07 const PSBT_OUT_TAP_BIP32_DERIVATION: u64 = 0x07; +/// Type: MuSig2 Public Keys Participating in Aggregate Output PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS = 0x08 +const PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS: u64 = 0x08; /// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC const PSBT_OUT_PROPRIETARY: u64 = 0xFC; @@ -40,6 +42,8 @@ pub struct Output { pub tap_tree: Option, /// Map of tap root x only keys to origin info and leaf hashes contained in it. pub tap_key_origins: BTreeMap, KeySource)>, + /// Mapping from MuSig2 aggregate keys to the participant keys from which they were aggregated. + pub musig2_participant_pubkeys: BTreeMap>, /// Proprietary key-value pairs for this output. pub proprietary: BTreeMap>, /// Unknown key-value pairs for this output. @@ -90,6 +94,11 @@ impl Output { self.tap_key_origins <= |< raw_value: (Vec, KeySource)> } } + PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS => { + impl_psbt_insert_pair! { + self.musig2_participant_pubkeys <= |< raw_value: Vec > + } + } _ => match self.unknown.entry(raw_key) { btree_map::Entry::Vacant(empty_key) => { empty_key.insert(raw_value); @@ -107,6 +116,7 @@ impl Output { self.proprietary.extend(other.proprietary); self.unknown.extend(other.unknown); self.tap_key_origins.extend(other.tap_key_origins); + self.musig2_participant_pubkeys.extend(other.musig2_participant_pubkeys); combine!(redeem_script, self, other); combine!(witness_script, self, other); @@ -143,6 +153,10 @@ impl Map for Output { rv.push_map(self.tap_key_origins, PSBT_OUT_TAP_BIP32_DERIVATION) } + impl_psbt_get_pair! { + rv.push_map(self.musig2_participant_pubkeys, PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS) + } + for (key, value) in self.proprietary.iter() { rv.push(raw::Pair { key: key.to_key(), value: value.clone() }); } diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 8f6193fd2d..270f8a75e5 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -172,6 +172,28 @@ impl Deserialize for secp256k1::PublicKey { } } +impl Serialize for Vec { + fn serialize(&self) -> Vec { + let mut result: Vec = Vec::with_capacity(secp256k1::constants::PUBLIC_KEY_SIZE * self.len()); + + for pubkey in self.iter() { + result.extend(Serialize::serialize(pubkey)); + } + + result + } +} + +impl Deserialize for Vec { + fn deserialize(bytes: &[u8]) -> Result { + bytes.chunks(secp256k1::constants::PUBLIC_KEY_SIZE) + .map(|pubkey_bytes| { + secp256k1::PublicKey::deserialize(pubkey_bytes) + }) + .collect() + } +} + impl Serialize for ecdsa::Signature { fn serialize(&self) -> Vec { self.to_vec() } } From 2481695b456bcccbb25c247c1fd39bbda24dbb30 Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Thu, 1 May 2025 11:47:59 -0500 Subject: [PATCH 034/857] Add tests for BIP-373 PSBT_{IN,OUT}_MUSIG2_PARTICIPANT_PUBKEYS serialization and deserialization --- bitcoin/src/psbt/mod.rs | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 72f053c2fb..1c3e7368b0 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1341,6 +1341,8 @@ mod tests { secp256k1::{All, SecretKey}, }; + use std::str::FromStr; + use super::*; use crate::address::script_pubkey::ScriptExt as _; use crate::bip32::ChildNumber; @@ -2237,6 +2239,49 @@ mod tests { assert!(!rtt.proprietary.is_empty()); } + // Deserialize MuSig2 PSBT participant keys according to BIP-373 + #[test] + fn serialize_and_deserialize_musig2_participants() { + // XXX: Does not cover PSBT_IN_MUSIG2_PUB_NONCE, PSBT_IN_MUSIG2_PARTIAL_SIG (yet) + + let expected_in_agg_pk = secp256k1::PublicKey::from_str("021401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e00").unwrap(); + let expected_in_pubkeys = vec![ + secp256k1::PublicKey::from_str("02bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a").unwrap(), + secp256k1::PublicKey::from_str("0355212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e2").unwrap(), + ]; + + let expected_out_agg_pk = secp256k1::PublicKey::from_str("0364934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba5").unwrap(); + + let expected_out_pubkeys = vec![ + secp256k1::PublicKey::from_str("02841d69a8b80ae23a8090e6f3765540ea5efd8c287b1307c983a6e2a3a171b525").unwrap(), + secp256k1::PublicKey::from_str("02bad833849a98cdfb0a0749609ddccab16ad54485ecc67f828df4bdc4f2b90d4c").unwrap(), + ]; + + const PSBT_HEX: &str = "70736274ff01005e02000000017b42be5ea467afe0d0571dc4a91bef97ff9605a590c0b8d5892323946414d1810000000000ffffffff01f0b9f50500000000225120bc7e18f55e2c7a28d78cadac1bc72c248372375d269bafe6b315bc40505d07e5000000000001012b00e1f50500000000225120de564ebf8ff7bd9bb41bd88264c04b1713ebb9dc8df36319091d2eabb16cda6221161401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e000500eb4cbe62211655212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e20500755abbf92116bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a05002a33dfd90117201401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e00221a021401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e004202bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a0355212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e20001052064934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba5210764934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba50500fa4c6afa22080364934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba54202841d69a8b80ae23a8090e6f3765540ea5efd8c287b1307c983a6e2a3a171b52502bad833849a98cdfb0a0749609ddccab16ad54485ecc67f828df4bdc4f2b90d4c00"; + + let psbt = hex_psbt(PSBT_HEX).unwrap(); + + assert_eq!(psbt.inputs[0].musig2_participant_pubkeys.len(), 1); + assert_eq!( + psbt.inputs[0].musig2_participant_pubkeys.iter().next().unwrap(), + (&expected_in_agg_pk, &expected_in_pubkeys) + ); + + assert_eq!(psbt.outputs[0].musig2_participant_pubkeys.len(), 1); + assert_eq!( + psbt.outputs[0].musig2_participant_pubkeys.iter().next().unwrap(), + (&expected_out_agg_pk, &expected_out_pubkeys) + ); + + // Check round trip de/serialization + assert_eq!(psbt.serialize_hex(), PSBT_HEX); + + const PSBT_TRUNCATED_MUSIG_PARTICIPANTS_HEX: &str = "70736274ff01005e0200000001f034711ce319b1db76ce73440f2cb64a7e3a02e75c936b8d8a4958a024ea8d870000000000ffffffff01f0b9f50500000000225120bc7e18f55e2c7a28d78cadac1bc72c248372375d269bafe6b315bc40505d07e5000000000001012b00e1f50500000000225120de564ebf8ff7bd9bb41bd88264c04b1713ebb9dc8df36319091d2eabb16cda6221161401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e000500eb4cbe62211655212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e20500755abbf92116bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a05002a33dfd90117201401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e00221a021401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e002a02bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a0355212dff7b3d7e810001052064934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba5210764934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba50500fa4c6afa22080364934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba52a02841d69a8b80ae23a8090e6f3765540ea5efd8c287b1307c983a6e2a3a171b52502bad833849a98cdfb00"; + + hex_psbt(PSBT_TRUNCATED_MUSIG_PARTICIPANTS_HEX) + .expect_err("Deserializing PSBT with truncated musig participants should error"); + } + // PSBTs taken from BIP 174 test vectors. #[test] fn combine_psbts() { From 8dd24cb67b948e619038b387d6c3bd79252a5de1 Mon Sep 17 00:00:00 2001 From: yancy Date: Sat, 24 May 2025 16:47:41 -0500 Subject: [PATCH 035/857] Add Arbitrary type for InputWeightPrediction This type creates sane Arbitrary InputWeightPrediction types that do not panic. To this end, when a custom type is created by calling new() or from_slice() constructor, only use values that would no greater than block size 4 Mwu. --- bitcoin/src/blockdata/transaction.rs | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index b521f2cda9..0e64bdd3c2 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -12,6 +12,8 @@ use core::fmt; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use hashes::sha256d; use internals::{compact_size, write_err, ToU64}; use io::{BufRead, Write}; @@ -1141,6 +1143,38 @@ mod sealed { impl Sealed for super::Version {} } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for InputWeightPrediction { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + // limit script size to 4Mwu block size. + let max_block = Weight::MAX_BLOCK.to_wu() as usize; + let input_script_len = u.int_in_range(0..=max_block)?; + let remaining = max_block - input_script_len; + + // create witness data if there is remaining space. + let mut witness_length = u.int_in_range(0..=remaining)?; + let mut witness_element_lengths = Vec::new(); + + // build vec of random witness element lengths. + while witness_length > 0 { + let elem = u.int_in_range(1..=witness_length)?; + witness_element_lengths.push(elem); + witness_length -= elem; + } + + match u.int_in_range(0..=7)? { + 0 => Ok(InputWeightPrediction::P2WPKH_MAX), + 1 => Ok(InputWeightPrediction::NESTED_P2WPKH_MAX), + 2 => Ok(InputWeightPrediction::P2PKH_COMPRESSED_MAX), + 3 => Ok(InputWeightPrediction::P2PKH_UNCOMPRESSED_MAX), + 4 => Ok(InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH), + 5 => Ok(InputWeightPrediction::P2TR_KEY_NON_DEFAULT_SIGHASH), + 6 => Ok(InputWeightPrediction::new(input_script_len, witness_element_lengths)), + _ => Ok(InputWeightPrediction::from_slice(input_script_len, &witness_element_lengths)), + } + } +} + #[cfg(test)] mod tests { use hex::FromHex; From 0dbcd09bbcd817cafd2108e2b470cad88aed4eb8 Mon Sep 17 00:00:00 2001 From: yancy Date: Mon, 26 May 2025 18:04:33 -0500 Subject: [PATCH 036/857] Move CheckedSum trait to crate root In order to add other types to CheckedSum, remove from the Amount module. In so doing, other types added to CheeckSum do not need to be imported into Amount. --- bitcoin/src/lib.rs | 7 ++++--- units/src/amount/mod.rs | 18 +----------------- units/src/lib.rs | 17 +++++++++++++++++ units/tests/api.rs | 4 ++-- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index cb68c35434..60e1513554 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -204,14 +204,15 @@ pub mod amount { #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] + pub use units::CheckedSum; + #[cfg(feature = "serde")] + pub use units::amount::serde; pub use units::amount::{ - Amount, CheckedSum, Denomination, Display, InvalidCharacterError, MissingDenominationError, + Amount, Denomination, Display, InvalidCharacterError, MissingDenominationError, MissingDigitsError, OutOfRangeError, ParseAmountError, ParseDenominationError, ParseError, PossiblyConfusingDenominationError, SignedAmount, TooPreciseError, UnknownDenominationError, }; - #[cfg(feature = "serde")] - pub use units::amount::serde; impl Decodable for Amount { #[inline] diff --git a/units/src/amount/mod.rs b/units/src/amount/mod.rs index b08e6ebb49..19b4a9832f 100644 --- a/units/src/amount/mod.rs +++ b/units/src/amount/mod.rs @@ -26,6 +26,7 @@ use core::str::FromStr; use arbitrary::{Arbitrary, Unstructured}; use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner}; +use crate::CheckedSum; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -593,13 +594,6 @@ enum DisplayStyle { DynamicDenomination, } -/// Calculates the sum over the iterator using checked arithmetic. -pub trait CheckedSum: sealed::Sealed { - /// Calculates the sum over the iterator using checked arithmetic. If an - /// overflow happens it returns [`None`]. - fn checked_sum(self) -> Option; -} - impl CheckedSum for T where T: Iterator, @@ -616,16 +610,6 @@ where } } -mod sealed { - use super::{Amount, SignedAmount}; - - /// Used to seal the `CheckedSum` trait - pub trait Sealed {} - - impl Sealed for T where T: Iterator {} - impl Sealed for T where T: Iterator {} -} - #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Denomination { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { diff --git a/units/src/lib.rs b/units/src/lib.rs index 06d24d7188..e6b36a7dd6 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -69,3 +69,20 @@ pub(crate) use self::result::OptionExt; #[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")] #[doc(hidden)] pub type BlockInterval = BlockHeightInterval; + +/// Calculates the sum over the iterator using checked arithmetic. +pub trait CheckedSum: sealed::Sealed { + /// Calculates the sum over the iterator using checked arithmetic. If an + /// overflow happens it returns [`None`]. + fn checked_sum(self) -> Option; +} + +mod sealed { + use super::{Amount, SignedAmount}; + + /// Used to seal the `CheckedSum` trait + pub trait Sealed {} + + impl Sealed for T where T: Iterator {} + impl Sealed for T where T: Iterator {} +} diff --git a/units/tests/api.rs b/units/tests/api.rs index 33b60bc7bb..cf5f5def42 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -15,7 +15,7 @@ use arbitrary::{Arbitrary, Unstructured}; use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::Height`. use bitcoin_units::{ amount, block, fee_rate, locktime, parse, weight, Amount, BlockHeight, BlockInterval, BlockMtp, - BlockMtpInterval, BlockTime, FeeRate, SignedAmount, Weight, + BlockMtpInterval, BlockTime, CheckedSum, FeeRate, SignedAmount, Weight, }; /// A struct that includes all public non-error enums. @@ -272,7 +272,7 @@ fn regression_default() { fn dyn_compatible() { // If this builds then traits are dyn compatible. struct Traits { - a: Box>, + a: Box>, // These traits are explicitly not dyn compatible. // b: Box, // c: Box, From 9dac4d69e0f142e9a2dc4b61ea49365a8cae3f4b Mon Sep 17 00:00:00 2001 From: yancy Date: Fri, 23 May 2025 14:58:03 -0500 Subject: [PATCH 037/857] Implement CheckedSum for Weight iterator Expose `checked_sum` method to sum an iterator of Weights checked. --- units/src/lib.rs | 3 ++- units/src/weight.rs | 21 +++++++++++++++++++++ units/tests/api.rs | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/units/src/lib.rs b/units/src/lib.rs index e6b36a7dd6..6431202231 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -78,11 +78,12 @@ pub trait CheckedSum: sealed::Sealed { } mod sealed { - use super::{Amount, SignedAmount}; + use super::{Amount, SignedAmount, Weight}; /// Used to seal the `CheckedSum` trait pub trait Sealed {} impl Sealed for T where T: Iterator {} impl Sealed for T where T: Iterator {} + impl Sealed for T where T: Iterator {} } diff --git a/units/src/weight.rs b/units/src/weight.rs index d801dd254c..6649b4d641 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -10,6 +10,8 @@ use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use crate::CheckedSum; + /// The factor that non-witness serialization data is multiplied by during weight calculation. pub const WITNESS_SCALE_FACTOR: usize = 4; @@ -241,6 +243,13 @@ impl ops::RemAssign for Weight { fn rem_assign(&mut self, rhs: u64) { *self = Weight::from_wu(self.to_wu() % rhs); } } +impl CheckedSum for T +where + T: Iterator, +{ + fn checked_sum(mut self) -> Option { self.try_fold(Weight::ZERO, Weight::checked_add) } +} + impl core::iter::Sum for Weight { fn sum(iter: I) -> Self where @@ -524,4 +533,16 @@ mod tests { weight %= 3; assert_eq!(weight, Weight::from_wu(1)); } + + #[test] + #[cfg(feature = "alloc")] + fn checked_sum_weights() { + assert_eq!([].into_iter().checked_sum(), Some(Weight::ZERO)); + + let sum = alloc::vec![0, 1, 2].iter().map(|&w| Weight::from_wu(w)).checked_sum().unwrap(); + assert_eq!(sum, Weight::from_wu(3)); + + let sum = alloc::vec![1, u64::MAX].iter().map(|&w| Weight::from_wu(w)).checked_sum(); + assert!(sum.is_none()); + } } diff --git a/units/tests/api.rs b/units/tests/api.rs index cf5f5def42..c440252958 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -273,6 +273,7 @@ fn dyn_compatible() { // If this builds then traits are dyn compatible. struct Traits { a: Box>, + b: Box>, // These traits are explicitly not dyn compatible. // b: Box, // c: Box, From e47836fb1e0c96936096efb2dfca4e2cbc9b9e5f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 27 May 2025 08:09:56 +0100 Subject: [PATCH 038/857] Do not derive Default on CompactTarget It is not immediately obvious what a zero value compact target is. Because of this and the fact that we are trying to release minimal code in `primitives 1.0` its best to remove the `Default` derive. This is an API breaking change. --- primitives/src/pow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/pow.rs b/primitives/src/pow.rs index b7f5fc46ce..7f01074842 100644 --- a/primitives/src/pow.rs +++ b/primitives/src/pow.rs @@ -18,7 +18,7 @@ use core::fmt; /// `CompactTarget` and `Target` is lossy *in both directions* (there are multiple `CompactTarget` /// values that map to the same `Target` value). Ordering and equality for this type are defined in /// terms of the underlying `u32`. -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct CompactTarget(u32); From 2a3e606d89d25ce54ff91b38b0aa29f7f733b9d9 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 27 May 2025 08:36:18 +0100 Subject: [PATCH 039/857] units: Move some things out of impl_u32_macro Recently we added a private `impl_u32_macro`. It included a bunch of associated consts and a pair of u32 constructor/getter functions. We overlooked the fact that the macro produces incorrect docs. Move the offending code out of the macro and into the already existent impl block for each type. Docs only, no other logic change. --- units/src/block.rs | 80 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/units/src/block.rs b/units/src/block.rs index 57cae8ed79..4192f4bb12 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -30,23 +30,6 @@ macro_rules! impl_u32_wrapper { $(#[$($type_attrs)*])* $type_vis struct $newtype($inner_vis u32); - impl $newtype { - /// Block height 0, the genesis block. - pub const ZERO: Self = Self(0); - - /// The minimum block height (0), the genesis block. - pub const MIN: Self = Self::ZERO; - - /// The maximum block height. - pub const MAX: Self = Self(u32::MAX); - - /// Constructs a new block height from a `u32`. - pub const fn from_u32(inner: u32) -> Self { Self(inner) } - - /// Returns block height as a `u32`. - pub const fn to_u32(self) -> u32 { self.0 } - } - impl fmt::Display for $newtype { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } @@ -89,6 +72,21 @@ impl_u32_wrapper! { } impl BlockHeight { + /// Block height 0, the genesis block. + pub const ZERO: Self = Self(0); + + /// The minimum block height (0), the genesis block. + pub const MIN: Self = Self::ZERO; + + /// The maximum block height. + pub const MAX: Self = Self(u32::MAX); + + /// Constructs a new block height from a `u32`. + pub const fn from_u32(inner: u32) -> Self { Self(inner) } + + /// Returns block height as a `u32`. + pub const fn to_u32(self) -> u32 { self.0 } + /// Attempt to subtract two [`BlockHeight`]s, returning `None` in case of overflow. pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(BlockHeightInterval) @@ -133,6 +131,21 @@ impl_u32_wrapper! { } impl BlockHeightInterval { + /// Block interval 0. + pub const ZERO: Self = Self(0); + + /// The minimum block interval, equivalent to `Self::ZERO`. + pub const MIN: Self = Self::ZERO; + + /// The maximum block interval. + pub const MAX: Self = Self(u32::MAX); + + /// Constructs a new block interval from a `u32`. + pub const fn from_u32(inner: u32) -> Self { Self(inner) } + + /// Returns block interval as a `u32`. + pub const fn to_u32(self) -> u32 { self.0 } + /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` in case of overflow. pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } @@ -175,6 +188,24 @@ impl_u32_wrapper! { } impl BlockMtp { + /// Block MTP 0. + /// + /// Since MTP is a timestamp, 0 is before Bitcoin was invented. This const may still be useful + /// for some use cases e.g., folding a sum of intervals. + pub const ZERO: Self = Self(0); + + /// The minimum block MTP, equivalent to `Self::ZERO`. + pub const MIN: Self = Self::ZERO; + + /// The maximum block MTP. + pub const MAX: Self = Self(u32::MAX); + + /// Constructs a new block MTP from a `u32`. + pub const fn from_u32(inner: u32) -> Self { Self(inner) } + + /// Returns block MTP as a `u32`. + pub const fn to_u32(self) -> u32 { self.0 } + /// Constructs a [`BlockMtp`] by computing the median‐time‐past from the last 11 block timestamps /// /// Because block timestamps are not monotonic, this function internally sorts them; @@ -229,6 +260,21 @@ impl_u32_wrapper! { } impl BlockMtpInterval { + /// Block MTP interval 0. + pub const ZERO: Self = Self(0); + + /// The minimum block MTP interval, equivalent to `Self::ZERO`. + pub const MIN: Self = Self::ZERO; + + /// The maximum block MTP interval. + pub const MAX: Self = Self(u32::MAX); + + /// Constructs a new block MTP interval from a `u32`. + pub const fn from_u32(inner: u32) -> Self { Self(inner) } + + /// Returns block MTP interval as a `u32`. + pub const fn to_u32(self) -> u32 { self.0 } + /// Converts a [`BlockMtpInterval`] to a [`locktime::relative::NumberOf512Seconds`], rounding down. /// /// Relative timelock MTP intervals have a resolution of 512 seconds, while From 9d956e8643214b3c1ad0e42cc630e2f35f7b7994 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Tue, 27 May 2025 10:09:44 +0100 Subject: [PATCH 040/857] test: remove redundant `ServiceFlags` test The `ServiceFlags` type is already tested within p2p/mod.rs with a nearly identical test. This type also has nothing to do with `network` --- bitcoin/src/network/mod.rs | 42 -------------------------------------- 1 file changed, 42 deletions(-) diff --git a/bitcoin/src/network/mod.rs b/bitcoin/src/network/mod.rs index 6137afda97..11e0f2e5b2 100644 --- a/bitcoin/src/network/mod.rs +++ b/bitcoin/src/network/mod.rs @@ -364,7 +364,6 @@ impl TryFrom for Network { mod tests { use super::{Network, TestnetVersion}; use crate::consensus::encode::{deserialize, serialize}; - use crate::p2p::ServiceFlags; #[test] fn serialize_deserialize() { @@ -409,47 +408,6 @@ mod tests { assert!("fakenet".parse::().is_err()); } - #[test] - fn service_flags() { - let all = [ - ServiceFlags::NETWORK, - ServiceFlags::GETUTXO, - ServiceFlags::BLOOM, - ServiceFlags::WITNESS, - ServiceFlags::COMPACT_FILTERS, - ServiceFlags::NETWORK_LIMITED, - ServiceFlags::P2P_V2, - ]; - - let mut flags = ServiceFlags::NONE; - for f in all.iter() { - assert!(!flags.has(*f)); - } - - flags |= ServiceFlags::WITNESS; - assert_eq!(flags, ServiceFlags::WITNESS); - - let mut flags2 = flags | ServiceFlags::GETUTXO; - for f in all.iter() { - assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO); - } - - flags2 ^= ServiceFlags::WITNESS; - assert_eq!(flags2, ServiceFlags::GETUTXO); - - flags2 |= ServiceFlags::COMPACT_FILTERS; - flags2 ^= ServiceFlags::GETUTXO; - assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS); - - // Test formatting. - assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string()); - assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string()); - let flag = ServiceFlags::WITNESS | ServiceFlags::BLOOM | ServiceFlags::NETWORK; - assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS)", flag.to_string()); - let flag = ServiceFlags::WITNESS | 0xf0.into(); - assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string()); - } - #[test] #[cfg(feature = "serde")] fn serde_roundtrip() { From aa7610831582551bffaa274e947bf5fea1d96252 Mon Sep 17 00:00:00 2001 From: Jose Storopoli Date: Tue, 27 May 2025 08:25:40 -0300 Subject: [PATCH 041/857] bitcoin: secp256k1 global-context feature re-export Often we want to have the global-context feature in secp256k1 without having to add manually the secp256k1 dependency and enabling the global-context feature. Having the ability to do that directly from bitcoin without having to add secp256k1 and do the whole tango of tightly coupling the two dependecy versions together, e.g. bitcoin 0.32.x and secp256k1 0.29.x would be really nice and would also simplify a lot code maintainability for anyone who depends on bitcoin. This needs to be backported to 0.32.x, which I'll gladly do as well. --- bitcoin/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index 39547f0235..f6bff55c99 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -20,6 +20,7 @@ std = ["base58/std", "bech32/std", "hashes/std", "hex/std", "internals/std", "io rand-std = ["secp256k1/rand", "std"] rand = ["secp256k1/rand"] serde = ["base64", "dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"] +secp-global-context = ["secp256k1/global-context"] secp-lowmemory = ["secp256k1/lowmemory"] secp-recovery = ["secp256k1/recovery"] arbitrary = ["dep:arbitrary", "units/arbitrary", "primitives/arbitrary"] From 94bcff28b19715061c38af418afd8f0b979792a8 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Tue, 27 May 2025 13:55:21 +0100 Subject: [PATCH 042/857] p2p: Add wrappers for messages that use `Vec` In preparation to move `p2p` to its own crate, any `Vec` that satisfies `T: Encodable` will not trivially implement `Encodable` because of the orphan rule. A type defined within p2p may implement `Encodable`, however, and the simplest possible type is one that simply wraps the vector. Three types that will implement `Encodable` within `p2p` are added here. --- bitcoin/src/p2p/message.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bitcoin/src/p2p/message.rs b/bitcoin/src/p2p/message.rs index bb69ec86d5..b464623ef3 100644 --- a/bitcoin/src/p2p/message.rs +++ b/bitcoin/src/p2p/message.rs @@ -163,6 +163,18 @@ pub struct V2NetworkMessage { payload: NetworkMessage, } +/// A list of inventory items. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct InventoryPayload(pub Vec); + +/// A list of legacy p2p address messages. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct AddrPayload(pub Vec<(u32, Address)>); + +/// A list of v2 address messages. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct AddrV2Payload(pub Vec); + /// A Network message payload. Proper documentation is available on at /// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification) #[derive(Clone, PartialEq, Eq, Debug)] From 6335c623f65f434a6ae7f72e57819a7b148a3efa Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Tue, 27 May 2025 10:32:23 -0300 Subject: [PATCH 043/857] fix(p2p): remove `AddrV2` <> `SocketAddr` conversions --- bitcoin/src/p2p/address.rs | 131 ------------------ .../bitcoin/p2p_address_roundtrip.rs | 10 +- 2 files changed, 1 insertion(+), 140 deletions(-) diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 0a3809bfda..a73a323342 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -138,56 +138,6 @@ pub enum AddrV2 { Unknown(u8, Vec), } -/// Error types for [`AddrV2`] to [`SocketAddr`] conversion. -#[derive(Debug, PartialEq, Eq)] -pub enum AddrV2ToSocketAddrError { - /// A [`AddrV2::TorV3`] address cannot be converted to a [`SocketAddr`]. - TorV3NotSupported, - /// A [`AddrV2::I2p`] address cannot be converted to a [`SocketAddr`]. - I2pNotSupported, - /// A [`AddrV2::Cjdns`] address can be converted to a [`SocketAddr`], - /// but it won't work with a tradicional socket API. - CjdnsNotRecommended, - /// A [`AddrV2::Unknown`] address cannot be converted to a [`SocketAddr`]. - UnknownNotSupported, -} - -impl fmt::Display for AddrV2ToSocketAddrError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::TorV3NotSupported => write!(f, "TorV3 addresses cannot be converted to SocketAddr"), - Self::I2pNotSupported => write!(f, "I2P addresses cannot be converted to SocketAddr"), - Self::CjdnsNotRecommended => write!(f, "CJDNS addresses can be converted to SocketAddr, but won't work with a traditional socket API"), - Self::UnknownNotSupported => write!(f, "Unknown address type cannot be converted to SocketAddr"), - } - } -} - -impl std::error::Error for AddrV2ToSocketAddrError {} - -impl From for AddrV2 { - fn from(addr: SocketAddr) -> Self { - match addr { - SocketAddr::V4(sock) => AddrV2::Ipv4(*sock.ip()), - SocketAddr::V6(sock) => AddrV2::Ipv6(*sock.ip()), - } - } -} - -impl TryFrom for SocketAddr { - type Error = AddrV2ToSocketAddrError; - - fn try_from(addr: AddrV2) -> Result { - match addr { - AddrV2::Ipv4(ip) => Ok(SocketAddr::V4(SocketAddrV4::new(ip, 0))), - AddrV2::Ipv6(ip) => Ok(SocketAddr::V6(SocketAddrV6::new(ip, 0, 0, 0))), - AddrV2::Cjdns(_) => Err(AddrV2ToSocketAddrError::CjdnsNotRecommended), - AddrV2::TorV3(_) => Err(AddrV2ToSocketAddrError::TorV3NotSupported), - AddrV2::I2p(_) => Err(AddrV2ToSocketAddrError::I2pNotSupported), - AddrV2::Unknown(_, _) => Err(AddrV2ToSocketAddrError::UnknownNotSupported), - } - } -} impl TryFrom for IpAddr { type Error = AddrV2ToIpAddrError; @@ -731,87 +681,6 @@ mod test { assert_eq!(serialize(&addresses), raw); } - #[test] - fn socketaddr_to_addrv2_ipv4() { - let socket = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 8333)); - let addr = AddrV2::from(socket); - - assert_eq!(addr, AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1))); - } - - #[test] - fn socketaddr_to_addrv2_ipv6() { - let socket = SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), - 8333, - 0, - 0, - )); - let addr = AddrV2::from(socket); - - assert_eq!(addr, AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1))); - } - - #[test] - fn addrv2_to_socketaddr_ipv4() { - let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)); - let socket = SocketAddr::try_from(addr).unwrap(); - - assert_eq!(socket, SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 0))); - } - - #[test] - fn addrv2_to_socketaddr_ipv6() { - let addr = AddrV2::Ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); - let socket = SocketAddr::try_from(addr).unwrap(); - - assert_eq!( - socket, - SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), - 0, - 0, - 0 - )) - ); - } - - #[test] - fn addrv2_to_socketaddr_cjdns() { - let addr = AddrV2::Cjdns(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 1)); - let result = SocketAddr::try_from(addr); - - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::CjdnsNotRecommended); - } - - #[test] - fn addrv2_to_socketaddr_torv3() { - let addr = AddrV2::TorV3([0; 32]); - let result = SocketAddr::try_from(addr); - - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::TorV3NotSupported); - } - - #[test] - fn addrv2_to_socketaddr_i2p() { - let addr = AddrV2::I2p([0; 32]); - let result = SocketAddr::try_from(addr); - - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::I2pNotSupported); - } - - #[test] - fn addrv2_to_socketaddr_unknown() { - let addr = AddrV2::Unknown(42, vec![1, 2, 3, 4]); - let result = SocketAddr::try_from(addr); - - assert!(result.is_err()); - assert_eq!(result.unwrap_err(), AddrV2ToSocketAddrError::UnknownNotSupported); - } - #[test] fn addrv2_to_ipaddr_ipv4() { let addr = AddrV2::Ipv4(Ipv4Addr::new(192, 168, 1, 1)); diff --git a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs index 669c5ea928..4fa4ffb272 100644 --- a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs +++ b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs @@ -1,5 +1,5 @@ use std::convert::TryFrom; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use bitcoin::consensus::Decodable; use bitcoin::p2p::address::AddrV2; @@ -31,14 +31,6 @@ fn do_test(data: &[u8]) { let round_trip: AddrV2 = AddrV2::from(ip_addr); assert_eq!(addr_v2, round_trip, "AddrV2 -> Ipv6Addr -> AddrV2 should round-trip correctly"); } - - if let Ok(socket_addr) = SocketAddr::try_from(addr_v2.clone()) { - let round_trip: AddrV2 = AddrV2::from(socket_addr); - assert_eq!( - addr_v2, round_trip, - "AddrV2 -> SocketAddr -> AddrV2 should round-trip correctly" - ); - } } fn main() { From 20779bdbc8ebcac2365d122e857c23b3d8e8d1e7 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Tue, 27 May 2025 14:24:18 +0100 Subject: [PATCH 044/857] Move `p2p` encodings out of `encode` All of the `Encodable` implementations are defined within `p2p` with the exception of `p2p` types that are a `Vec`. To fully decouple `p2p` from `encode` we can define these in `p2p` like the others. This is the final step in removing anything `p2p` related from the rest of `bitcoin`. --- bitcoin/src/consensus/encode.rs | 18 --------------- bitcoin/src/p2p/address.rs | 6 ++--- bitcoin/src/p2p/deser.rs | 41 +++++++++++++++++++++++++++++++++ bitcoin/src/p2p/message.rs | 33 +++++++++++++++----------- bitcoin/src/p2p/mod.rs | 2 ++ 5 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 bitcoin/src/p2p/deser.rs diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs index 3620c1867b..4e6cd660f8 100644 --- a/bitcoin/src/consensus/encode.rs +++ b/bitcoin/src/consensus/encode.rs @@ -26,11 +26,6 @@ use crate::bip152::{PrefilledTransaction, ShortId}; use crate::bip158::{FilterHash, FilterHeader}; use crate::block::{self, BlockHash}; use crate::merkle_tree::TxMerkleNode; -#[cfg(feature = "std")] -use crate::p2p::{ - address::{AddrV2Message, Address}, - message_blockdata::Inventory, -}; use crate::prelude::{rc, sync, Box, Cow, String, Vec}; use crate::taproot::TapLeafHash; use crate::transaction::{Transaction, TxIn, TxOut}; @@ -552,13 +547,6 @@ impl_vec!(TapLeafHash); impl_vec!(ShortId); impl_vec!(PrefilledTransaction); -#[cfg(feature = "std")] -impl_vec!(Inventory); -#[cfg(feature = "std")] -impl_vec!((u32, Address)); -#[cfg(feature = "std")] -impl_vec!(AddrV2Message); - pub(crate) fn consensus_encode_with_size( data: &[u8], w: &mut W, @@ -765,8 +753,6 @@ mod tests { use core::mem::discriminant; use super::*; - #[cfg(feature = "std")] - use crate::p2p::{message_blockdata::Inventory, Address}; #[test] fn serialize_int() { @@ -1049,10 +1035,6 @@ mod tests { test_len_is_max_vec::(); test_len_is_max_vec::>(); test_len_is_max_vec::(); - #[cfg(feature = "std")] - test_len_is_max_vec::<(u32, Address)>(); - #[cfg(feature = "std")] - test_len_is_max_vec::(); } fn test_len_is_max_vec() diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 0a3809bfda..927cdcd349 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -493,7 +493,7 @@ mod test { use hex_lit::hex; use super::*; - use crate::consensus::encode::{deserialize, serialize}; + use crate::{consensus::encode::{deserialize, serialize}, p2p::message::AddrV2Payload}; #[test] fn serialize_address() { @@ -706,10 +706,10 @@ mod test { #[test] fn addrv2message() { let raw = hex!("0261bc6649019902abab208d79627683fd4804010409090909208d"); - let addresses: Vec = deserialize(&raw).unwrap(); + let addresses: AddrV2Payload = deserialize(&raw).unwrap(); assert_eq!( - addresses, + addresses.0, vec![ AddrV2Message { services: ServiceFlags::NETWORK, diff --git a/bitcoin/src/p2p/deser.rs b/bitcoin/src/p2p/deser.rs new file mode 100644 index 0000000000..09a18f23b7 --- /dev/null +++ b/bitcoin/src/p2p/deser.rs @@ -0,0 +1,41 @@ +macro_rules! impl_vec_wrapper { + ($wrapper: ident, $type: ty) => { + impl crate::consensus::encode::Encodable for $wrapper { + #[inline] + fn consensus_encode( + &self, + w: &mut W, + ) -> core::result::Result { + let mut len = 0; + len += w.emit_compact_size(self.0.len())?; + for c in self.0.iter() { + len += c.consensus_encode(w)?; + } + Ok(len) + } + } + + impl crate::consensus::encode::Decodable for $wrapper { + #[inline] + fn consensus_decode_from_finite_reader( + r: &mut R, + ) -> core::result::Result<$wrapper, crate::consensus::encode::Error> { + let len = r.read_compact_size()?; + // Do not allocate upfront more items than if the sequence of type + // occupied roughly quarter a block. This should never be the case + // for normal data, but even if that's not true - `push` will just + // reallocate. + // Note: OOM protection relies on reader eventually running out of + // data to feed us. + let max_capacity = crate::consensus::encode::MAX_VEC_SIZE / 4 / core::mem::size_of::<$type>(); + let mut ret = Vec::with_capacity(core::cmp::min(len as usize, max_capacity)); + for _ in 0..len { + ret.push(Decodable::consensus_decode_from_finite_reader(r)?); + } + Ok($wrapper(ret)) + } + } + }; +} + +pub(crate) use impl_vec_wrapper; diff --git a/bitcoin/src/p2p/message.rs b/bitcoin/src/p2p/message.rs index b464623ef3..3bfc8513bc 100644 --- a/bitcoin/src/p2p/message.rs +++ b/bitcoin/src/p2p/message.rs @@ -19,6 +19,7 @@ use crate::p2p::{ Magic, }; use crate::prelude::{Box, Cow, String, ToOwned, Vec}; +use crate::p2p::deser::impl_vec_wrapper; use crate::{block, consensus, transaction}; /// The maximum number of [super::message_blockdata::Inventory] items in an `inv` message. @@ -175,6 +176,10 @@ pub struct AddrPayload(pub Vec<(u32, Address)>); #[derive(Clone, PartialEq, Eq, Debug)] pub struct AddrV2Payload(pub Vec); +impl_vec_wrapper!(InventoryPayload, message_blockdata::Inventory); +impl_vec_wrapper!(AddrPayload, (u32, Address)); +impl_vec_wrapper!(AddrV2Payload, AddrV2Message); + /// A Network message payload. Proper documentation is available on at /// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification) #[derive(Clone, PartialEq, Eq, Debug)] @@ -184,13 +189,13 @@ pub enum NetworkMessage { /// `verack` Verack, /// `addr` - Addr(Vec<(u32, Address)>), + Addr(AddrPayload), /// `inv` - Inv(Vec), + Inv(InventoryPayload), /// `getdata` - GetData(Vec), + GetData(InventoryPayload), /// `notfound` - NotFound(Vec), + NotFound(InventoryPayload), /// `getblocks` GetBlocks(message_blockdata::GetBlocksMessage), /// `getheaders` @@ -248,7 +253,7 @@ pub enum NetworkMessage { /// `wtxidrelay` WtxidRelay, /// `addrv2` - AddrV2(Vec), + AddrV2(AddrV2Payload), /// `sendaddrv2` SendAddrV2, @@ -746,17 +751,17 @@ mod test { let msgs = [ NetworkMessage::Version(version_msg), NetworkMessage::Verack, - NetworkMessage::Addr(vec![( + NetworkMessage::Addr(AddrPayload(vec![( 45, Address::new(&([123, 255, 000, 100], 833).into(), ServiceFlags::NETWORK), - )]), - NetworkMessage::Inv(vec![Inventory::Block(BlockHash::from_byte_array( + )])), + NetworkMessage::Inv(InventoryPayload(vec![Inventory::Block(BlockHash::from_byte_array( hash([8u8; 32]).to_byte_array(), - ))]), - NetworkMessage::GetData(vec![Inventory::Transaction(Txid::from_byte_array( + ))])), + NetworkMessage::GetData(InventoryPayload(vec![Inventory::Transaction(Txid::from_byte_array( hash([45u8; 32]).to_byte_array(), - ))]), - NetworkMessage::NotFound(vec![Inventory::Error([0u8; 32])]), + ))])), + NetworkMessage::NotFound(InventoryPayload(vec![Inventory::Error([0u8; 32])])), NetworkMessage::GetBlocks(GetBlocksMessage::new( vec![ BlockHash::from_byte_array(hash([1u8; 32]).to_byte_array()), @@ -838,12 +843,12 @@ mod test { }), NetworkMessage::FeeFilter(1000), NetworkMessage::WtxidRelay, - NetworkMessage::AddrV2(vec![AddrV2Message { + NetworkMessage::AddrV2(AddrV2Payload(vec![AddrV2Message { addr: AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)), port: 0, services: ServiceFlags::NONE, time: 0, - }]), + }])), NetworkMessage::SendAddrV2, NetworkMessage::CmpctBlock(cmptblock), NetworkMessage::GetBlockTxn(GetBlockTxn { diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs index cb9c1f5a86..31cbdd6ae1 100644 --- a/bitcoin/src/p2p/mod.rs +++ b/bitcoin/src/p2p/mod.rs @@ -19,6 +19,8 @@ pub mod message_compact_blocks; pub mod message_filter; #[cfg(feature = "std")] pub mod message_network; +#[cfg(feature = "std")] +mod deser; use core::str::FromStr; use core::{fmt, ops}; From 028a0d6558129f554de8c4247481bc0ad80f1c27 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Tue, 27 May 2025 11:38:00 +0100 Subject: [PATCH 045/857] Remove conversion impl macro for `Magic`/`Network` Closes #4560 Handle the coversion of new networks directly in the `From` and `TryFrom` implementations, as new networks are added infrequently. --- bitcoin/src/p2p/mod.rs | 52 ++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs index cb9c1f5a86..676a9b563e 100644 --- a/bitcoin/src/p2p/mod.rs +++ b/bitcoin/src/p2p/mod.rs @@ -249,40 +249,32 @@ impl FromStr for Magic { } } -macro_rules! generate_network_magic_conversion { - ($(Network::$network:ident$((TestnetVersion::$testnet_version:ident))? => Magic::$magic:ident,)*) => { - impl From for Magic { - fn from(network: Network) -> Magic { - match network { - $( - Network::$network$((TestnetVersion::$testnet_version))? => Magic::$magic, - )* - } - } +impl From for Magic { + fn from(network: Network) -> Self { + match network { + Network::Bitcoin => Magic::BITCOIN, + Network::Testnet(TestnetVersion::V3) => Magic::TESTNET3, + Network::Testnet(TestnetVersion::V4) => Magic::TESTNET4, + Network::Signet => Magic::SIGNET, + Network::Regtest => Magic::REGTEST, + // Remember to add the `TryFrom` for new networks } + } +} - impl TryFrom for Network { - type Error = UnknownMagicError; +impl TryFrom for Network { + type Error = UnknownMagicError; - fn try_from(magic: Magic) -> Result { - match magic { - $( - Magic::$magic => Ok(Network::$network$((TestnetVersion::$testnet_version))?), - )* - _ => Err(UnknownMagicError(magic)), - } - } + fn try_from(magic: Magic) -> Result { + match magic { + Magic::BITCOIN => Ok(Network::Bitcoin), + Magic::TESTNET3 => Ok(Network::Testnet(TestnetVersion::V3)), + Magic::TESTNET4 => Ok(Network::Testnet(TestnetVersion::V4)), + Magic::SIGNET => Ok(Network::Signet), + Magic::REGTEST => Ok(Network::Regtest), + _ => Err(UnknownMagicError(magic)), } - }; -} -// Generate conversion functions for all known networks. -// `Network -> Magic` and `Magic -> Network` -generate_network_magic_conversion! { - Network::Bitcoin => Magic::BITCOIN, - Network::Testnet(TestnetVersion::V3) => Magic::TESTNET3, - Network::Testnet(TestnetVersion::V4) => Magic::TESTNET4, - Network::Signet => Magic::SIGNET, - Network::Regtest => Magic::REGTEST, + } } impl fmt::Display for Magic { From de320714fbe46e4fda858d5c1c07f5dd1cc842f0 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Tue, 27 May 2025 15:20:01 +0100 Subject: [PATCH 046/857] Introduce empty p2p messages crate Peer to peer messages change on occasion, and we would like to add messages as they are release from Bitcoin Core. Add an empty crate to take the crate name. --- Cargo-minimal.lock | 4 ++++ Cargo-recent.lock | 4 ++++ Cargo.toml | 2 +- p2p/CHANGELOG.md | 3 +++ p2p/Cargo.toml | 21 +++++++++++++++++++++ p2p/README.md | 12 ++++++++++++ p2p/contrib/test_vars.sh | 14 ++++++++++++++ p2p/src/lib.rs | 16 ++++++++++++++++ 8 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 p2p/CHANGELOG.md create mode 100644 p2p/Cargo.toml create mode 100644 p2p/README.md create mode 100644 p2p/contrib/test_vars.sh create mode 100644 p2p/src/lib.rs diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 211aa646ab..1ff3ceaa33 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -106,6 +106,10 @@ dependencies = [ "bitcoin_hashes 0.16.0", ] +[[package]] +name = "bitcoin-p2p-messages" +version = "0.1.0" + [[package]] name = "bitcoin-primitives" version = "0.101.0" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index e886abeca8..edfae1793f 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -105,6 +105,10 @@ dependencies = [ "bitcoin_hashes 0.16.0", ] +[[package]] +name = "bitcoin-p2p-messages" +version = "0.1.0" + [[package]] name = "bitcoin-primitives" version = "0.101.0" diff --git a/Cargo.toml b/Cargo.toml index 7d9a5d5264..d467712956 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["addresses", "base58", "bitcoin", "chacha20_poly1305", "fuzz", "hashes", "internals", "io", "primitives", "units"] +members = ["addresses", "base58", "bitcoin", "chacha20_poly1305", "fuzz", "hashes", "internals", "io", "p2p", "primitives", "units"] resolver = "2" # Keep this patch for hashes because secp256k1 depends on bitcoin-hashes via crates.io diff --git a/p2p/CHANGELOG.md b/p2p/CHANGELOG.md new file mode 100644 index 0000000000..4c310ad4be --- /dev/null +++ b/p2p/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.1.0 - 2025-05-27 + +* Initial release of the `github.com/rust-bitcoin/rust-bitcoin/p2p` crate as `bitcoin-p2p-messages`. diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml new file mode 100644 index 0000000000..37166211c8 --- /dev/null +++ b/p2p/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "bitcoin-p2p-messages" +version = "0.1.0" +authors = ["Andrew Poelstra "] +license = "CC0-1.0" +repository = "https://github.com/rust-bitcoin/rust-bitcoin" +description = "Peer-to-peer messages defined by the Bitcoin protocol" +categories = ["cryptography::cryptocurrencies"] +keywords = ["bitcoin", "peer-to-peer"] +readme = "README.md" +edition = "2021" +rust-version = "1.63.0" +exclude = ["tests", "contrib"] + +[dependencies] + +[dev-dependencies] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/p2p/README.md b/p2p/README.md new file mode 100644 index 0000000000..f4fe096e40 --- /dev/null +++ b/p2p/README.md @@ -0,0 +1,12 @@ +# Rust Bitcoin Peer to Peer Message Types + +This crate provides data types used in the Bitcoin peer-to-peer protocol. + +## Minimum Supported Rust Version (MSRV) + +This library should always compile with any combination of features on **Rust 1.63.0**. + +## Licensing + +The code in this project is licensed under the [Creative Commons CC0 1.0 Universal license](LICENSE). +We use the [SPDX license list](https://spdx.org/licenses/) and [SPDX IDs](https://spdx.dev/ids/). diff --git a/p2p/contrib/test_vars.sh b/p2p/contrib/test_vars.sh new file mode 100644 index 0000000000..88e2d26e18 --- /dev/null +++ b/p2p/contrib/test_vars.sh @@ -0,0 +1,14 @@ +# No shebang, this file should not be executed. +# shellcheck disable=SC2148 +# +# disable verify unused vars, despite the fact that they are used when sourced +# shellcheck disable=SC2034 + +# Test all these features with "std" enabled. +FEATURES_WITH_STD="" + +# Test all these features without "std" enabled. +FEATURES_WITHOUT_STD="" + +# Run these examples. +EXAMPLES="" diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs new file mode 100644 index 0000000000..bb9afc7d9d --- /dev/null +++ b/p2p/src/lib.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! # Rust Bitcoin Peer to Peer Message Types + +// Experimental features we need. +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +// Coding conventions. +#![warn(missing_docs)] +#![warn(deprecated_in_future)] +#![doc(test(attr(warn(unused))))] +// Pedantic lints that we enforce. +#![warn(clippy::return_self_not_must_use)] +// Exclude lints we don't think are valuable. +#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134 +#![allow(clippy::manual_range_contains)] // More readable than clippy's format. +#![allow(clippy::uninlined_format_args)] // Allow `format!("{}", x)`instead of enforcing `format!("{x}")` From 7b52b9c3a3c28afad41d9a246302ce95e4997ee5 Mon Sep 17 00:00:00 2001 From: yancy Date: Wed, 28 May 2025 20:06:31 -0500 Subject: [PATCH 047/857] Fix typo --- units/src/fee_rate/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index b9aa229ca3..672fd3fbb3 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -62,7 +62,7 @@ impl FeeRate { pub fn from_sat_per_vb(sat_vb: u64) -> Option { // 1 vb == 4 wu // 1 sat/vb == 1/4 sat/wu - // sat_vb sat/vb * 1000 / 4 == sat/kwu + // sat/vb * 1000 / 4 == sat/kwu Some(FeeRate::from_sat_per_kwu(sat_vb.checked_mul(1000 / 4)?)) } From cbe04b00c67eab896b7ec0535194771ec36cb68f Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Tue, 27 May 2025 10:23:00 +0100 Subject: [PATCH 048/857] Remove all `p2p` dependency from `network` Motivated by moving the `p2p` module to its own crate. `TryFrom` and `From` are already implement for converting to and from `Network`/`Magic`. The methods related to `Magic` are removed from `Network`, as well as any reference to `p2p` in the documentation, as `bitcoin` would no longer depend on `p2p`. The deser roundtrip test are relocated to `p2p/mod.rs` --- bitcoin/examples/handshake.rs | 6 ++-- bitcoin/src/network/mod.rs | 68 ----------------------------------- bitcoin/src/network/params.rs | 9 +---- bitcoin/src/p2p/mod.rs | 33 +++++++++++++++++ 4 files changed, 37 insertions(+), 79 deletions(-) diff --git a/bitcoin/examples/handshake.rs b/bitcoin/examples/handshake.rs index 4382de02a7..bd941dc0c3 100644 --- a/bitcoin/examples/handshake.rs +++ b/bitcoin/examples/handshake.rs @@ -4,7 +4,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use std::{env, process}; use bitcoin::consensus::{encode, Decodable}; -use bitcoin::p2p::{self, address, message, message_network}; +use bitcoin::p2p::{self, address, message, message_network, Magic}; use bitcoin::secp256k1::rand::Rng; fn main() { @@ -26,7 +26,7 @@ fn main() { let version_message = build_version_message(address); let first_message = - message::RawNetworkMessage::new(bitcoin::Network::Bitcoin.magic(), version_message); + message::RawNetworkMessage::new(Magic::BITCOIN, version_message); if let Ok(mut stream) = TcpStream::connect(address) { // Send the message @@ -44,7 +44,7 @@ fn main() { println!("Received version message: {:?}", reply.payload()); let second_message = message::RawNetworkMessage::new( - bitcoin::Network::Bitcoin.magic(), + Magic::BITCOIN, message::NetworkMessage::Verack, ); diff --git a/bitcoin/src/network/mod.rs b/bitcoin/src/network/mod.rs index 11e0f2e5b2..d3c6dd97c6 100644 --- a/bitcoin/src/network/mod.rs +++ b/bitcoin/src/network/mod.rs @@ -5,18 +5,6 @@ //! The term "network" is overloaded, here [`Network`] refers to the specific //! Bitcoin network we are operating on e.g., signet, regtest. The terms //! "network" and "chain" are often used interchangeably for this concept. -//! -//! # Example: encoding a network's magic bytes -//! -//! ```rust -//! use bitcoin::Network; -//! use bitcoin::consensus::encode::serialize; -//! -//! let network = Network::Bitcoin; -//! let bytes = serialize(&network.magic()); -//! -//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]); -//! ``` pub mod params; @@ -28,7 +16,6 @@ use internals::write_err; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use crate::constants::ChainHash; -use crate::p2p::Magic; use crate::prelude::{String, ToOwned}; #[rustfmt::skip] // Keep public re-exports separate. @@ -124,33 +111,6 @@ impl<'de> Deserialize<'de> for Network { } impl Network { - /// Constructs a new `Network` from the magic bytes. - /// - /// # Examples - /// - /// ```rust - /// use bitcoin::p2p::Magic; - /// use bitcoin::Network; - /// - /// assert_eq!(Ok(Network::Bitcoin), Network::try_from(Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9]))); - /// assert_eq!(None, Network::from_magic(Magic::from_bytes([0xFF, 0xFF, 0xFF, 0xFF]))); - /// ``` - pub fn from_magic(magic: Magic) -> Option { Network::try_from(magic).ok() } - - /// Return the network magic bytes, which should be encoded little-endian - /// at the start of every message - /// - /// # Examples - /// - /// ```rust - /// use bitcoin::p2p::Magic; - /// use bitcoin::Network; - /// - /// let network = Network::Bitcoin; - /// assert_eq!(network.magic(), Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9])); - /// ``` - pub fn magic(self) -> Magic { Magic::from(self) } - /// Converts a `Network` to its equivalent `bitcoind -chain` argument name. /// /// ```bash @@ -363,34 +323,6 @@ impl TryFrom for Network { #[cfg(test)] mod tests { use super::{Network, TestnetVersion}; - use crate::consensus::encode::{deserialize, serialize}; - - #[test] - fn serialize_deserialize() { - assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]); - assert_eq!( - serialize(&Network::Testnet(TestnetVersion::V3).magic()), - &[0x0b, 0x11, 0x09, 0x07] - ); - assert_eq!( - serialize(&Network::Testnet(TestnetVersion::V4).magic()), - &[0x1c, 0x16, 0x3f, 0x28] - ); - assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]); - assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]); - - assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic())); - assert_eq!( - deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), - Some(Network::Testnet(TestnetVersion::V3).magic()) - ); - assert_eq!( - deserialize(&[0x1c, 0x16, 0x3f, 0x28]).ok(), - Some(Network::Testnet(TestnetVersion::V4).magic()) - ); - assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic())); - assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic())); - } #[test] fn string() { diff --git a/bitcoin/src/network/params.rs b/bitcoin/src/network/params.rs index 493354e69c..e9e4adab1a 100644 --- a/bitcoin/src/network/params.rs +++ b/bitcoin/src/network/params.rs @@ -12,14 +12,12 @@ //! //! ``` //! use bitcoin::network::Params; -//! use bitcoin::{p2p, Script, ScriptBuf, Network, Target}; +//! use bitcoin::{Script, ScriptBuf, Network, Target}; //! //! const POW_TARGET_SPACING: u64 = 120; // Two minutes. -//! const MAGIC: [u8; 4] = [1, 2, 3, 4]; //! //! pub struct CustomParams { //! params: Params, -//! magic: [u8; 4], //! challenge_script: ScriptBuf, //! } //! @@ -34,14 +32,10 @@ //! //! Self { //! params, -//! magic: MAGIC, //! challenge_script, //! } //! } //! -//! /// Returns the custom magic bytes. -//! pub fn magic(&self) -> p2p::Magic { p2p::Magic::from_bytes(self.magic) } -//! //! /// Returns the custom signet challenge script. //! pub fn challenge_script(&self) -> &Script { &self.challenge_script } //! } @@ -61,7 +55,6 @@ //! # let _ = target.difficulty(signet); //! # //! # let custom = CustomParams::new(); -//! # let _ = custom.magic(); //! # let _ = custom.challenge_script(); //! # let _ = target.difficulty(custom); //! # } diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs index cb9c1f5a86..9d4f32b163 100644 --- a/bitcoin/src/p2p/mod.rs +++ b/bitcoin/src/p2p/mod.rs @@ -395,6 +395,39 @@ impl std::error::Error for UnknownMagicError { #[cfg(test)] mod tests { use super::*; + use crate::consensus::encode::{deserialize, serialize}; + + #[test] + fn serialize_deserialize() { + assert_eq!(serialize(&Magic::BITCOIN), &[0xf9, 0xbe, 0xb4, 0xd9]); + let magic: Magic = Network::Bitcoin.into(); + assert_eq!(serialize(&magic), &[0xf9, 0xbe, 0xb4, 0xd9]); + assert_eq!(serialize(&Magic::TESTNET3), &[0x0b, 0x11, 0x09, 0x07]); + let magic: Magic = Network::Testnet(TestnetVersion::V3).into(); + assert_eq!(serialize(&magic), &[0x0b, 0x11, 0x09, 0x07]); + assert_eq!(serialize(&Magic::TESTNET4), &[0x1c, 0x16, 0x3f, 0x28]); + let magic: Magic = Network::Testnet(TestnetVersion::V4).into(); + assert_eq!(serialize(&magic), &[0x1c, 0x16, 0x3f, 0x28]); + assert_eq!(serialize(&Magic::SIGNET), &[0x0a, 0x03, 0xcf, 0x40]); + let magic: Magic = Network::Signet.into(); + assert_eq!(serialize(&magic), &[0x0a, 0x03, 0xcf, 0x40]); + assert_eq!(serialize(&Magic::REGTEST), &[0xfa, 0xbf, 0xb5, 0xda]); + let magic: Magic = Network::Regtest.into(); + assert_eq!(serialize(&magic), &[0xfa, 0xbf, 0xb5, 0xda]); + + assert_eq!(deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.into())); + assert_eq!( + deserialize::(&[0x0b, 0x11, 0x09, 0x07]).ok(), + Some(Network::Testnet(TestnetVersion::V3).into()) + ); + assert_eq!( + deserialize::(&[0x1c, 0x16, 0x3f, 0x28]).ok(), + Some(Network::Testnet(TestnetVersion::V4).into()) + ); + assert_eq!(deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.into())); + assert_eq!(deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.into())); + } + #[test] fn service_flags_test() { From 357ae4051ad175c69d6ac3bdcc3b4066d34789d3 Mon Sep 17 00:00:00 2001 From: Fallengirl <155266340+Fallengirl@users.noreply.github.com> Date: Fri, 30 May 2025 11:31:56 +0200 Subject: [PATCH 049/857] fix typo Porallel to Parallel crypto.rs --- hashes/src/ripemd160/crypto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashes/src/ripemd160/crypto.rs b/hashes/src/ripemd160/crypto.rs index 70e92f66d6..b7b733a8e3 100644 --- a/hashes/src/ripemd160/crypto.rs +++ b/hashes/src/ripemd160/crypto.rs @@ -229,7 +229,7 @@ impl HashEngine { round5: h_ordering 2, 3, 4, 0, 1; data_index 15; roll_shift 5; round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 6; - // Porallel Round 1; + // Parallel Round 1; par_round1: h_ordering 0, 1, 2, 3, 4; data_index 5; roll_shift 8; par_round1: h_ordering 4, 0, 1, 2, 3; data_index 14; roll_shift 9; par_round1: h_ordering 3, 4, 0, 1, 2; data_index 7; roll_shift 9; From 64098e4578c93a3c2bbf337abf0fc19f12cf860d Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 05:24:34 +1000 Subject: [PATCH 050/857] Remove encapsulate module from fee rate This module is a PITA to work on, just remove it until the dust settles on fee rate. While we are at it make the rustdocs on the getter more terse. --- units/src/fee_rate/mod.rs | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 672fd3fbb3..dd2cbb0073 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -11,26 +11,12 @@ use core::ops; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; -mod encapsulate { - /// Fee rate. - /// - /// This is an integer newtype representing fee rate in `sat/kwu`. It provides protection - /// against mixing up the types as well as basic formatting features. - #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] - pub struct FeeRate(u64); - - impl FeeRate { - /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. - pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self { FeeRate(sat_kwu) } - - /// Returns raw fee rate. - /// - /// Can be used instead of `into()` to avoid inference issues. - pub const fn to_sat_per_kwu(self) -> u64 { self.0 } - } -} -#[doc(inline)] -pub use encapsulate::FeeRate; +/// Fee rate. +/// +/// This is an integer newtype representing fee rate in `sat/kwu`. It provides protection +/// against mixing up the types as well as basic formatting features. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct FeeRate(u64); impl FeeRate { /// 0 sat/kwu. @@ -54,6 +40,9 @@ impl FeeRate { /// Fee rate used to compute dust amount. pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); + /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. + pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self { FeeRate(sat_kwu) } + /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. /// /// # Errors @@ -75,6 +64,9 @@ impl FeeRate { /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). pub const fn from_sat_per_kvb(sat_kvb: u64) -> Self { FeeRate::from_sat_per_kwu(sat_kvb / 4) } + /// Returns raw fee rate. + pub const fn to_sat_per_kwu(self) -> u64 { self.0 } + /// Converts to sat/vB rounding down. pub const fn to_sat_per_vb_floor(self) -> u64 { self.to_sat_per_kwu() / (1000 / 4) } From b929022d56d1441f842d61d06858255857975093 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 05:29:25 +1000 Subject: [PATCH 051/857] Add floor/ceil versions of to_sat_per_kwu In preparation for changing the inner representation of `FeeRate` add floor and ceil versions of the getter function `to_sat_per_kwu`. For now both functions return the same thing but still call the correct one so that when we change the representation we do not need to re-visit them. --- bitcoin/src/blockdata/script/borrowed.rs | 2 +- bitcoin/src/psbt/mod.rs | 7 ++-- units/src/fee.rs | 7 ++-- units/src/fee_rate/mod.rs | 41 +++++++++++++----------- units/src/fee_rate/serde.rs | 4 +-- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 7cc5fca7d5..41a89e4a76 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -290,7 +290,7 @@ crate::internal_macros::define_extension_trait! { /// /// [`minimal_non_dust`]: Script::minimal_non_dust fn minimal_non_dust_custom(&self, dust_relay_fee: FeeRate) -> Option { - self.minimal_non_dust_internal(dust_relay_fee.to_sat_per_kwu() * 4) + self.minimal_non_dust_internal(dust_relay_fee.to_sat_per_kwu_ceil() * 4) } /// Counts the sigops for this Script using accurate counting. diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 3e5c9c2da0..b8f5188986 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1178,8 +1178,11 @@ impl fmt::Display for ExtractTxError { use ExtractTxError::*; match *self { - AbsurdFeeRate { fee_rate, .. } => - write!(f, "an absurdly high fee rate of {} sat/kwu", fee_rate.to_sat_per_kwu()), + AbsurdFeeRate { fee_rate, .. } => write!( + f, + "an absurdly high fee rate of {} sat/kwu", + fee_rate.to_sat_per_kwu_floor() + ), MissingInputValue { .. } => write!( f, "one of the inputs lacked value information (witness_utxo or non_witness_utxo)" diff --git a/units/src/fee.rs b/units/src/fee.rs index 4dc6c4b562..418db80ce9 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -80,7 +80,7 @@ impl Amount { #[must_use] pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { match self.to_sat().checked_mul(1000) { - Some(amount_msats) => match amount_msats.checked_div(fee_rate.to_sat_per_kwu()) { + Some(amount_msats) => match amount_msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { Some(wu) => Some(Weight::from_wu(wu)), None => None, }, @@ -96,7 +96,8 @@ impl Amount { /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { - let rate = fee_rate.to_sat_per_kwu(); + // Use ceil because result is used as the divisor. + let rate = fee_rate.to_sat_per_kwu_ceil(); match self.to_sat().checked_mul(1000) { Some(amount_msats) => match rate.checked_sub(1) { Some(rate_minus_one) => match amount_msats.checked_add(rate_minus_one) { @@ -151,7 +152,7 @@ impl FeeRate { /// /// Returns [`NumOpResult::Error`] if overflow occurred. pub const fn checked_mul_by_weight(self, weight: Weight) -> NumOpResult { - if let Some(fee) = self.to_sat_per_kwu().checked_mul(weight.to_wu()) { + if let Some(fee) = self.to_sat_per_kwu_floor().checked_mul(weight.to_wu()) { if let Some(round_up) = fee.checked_add(999) { if let Ok(ret) = Amount::from_sat(round_up / 1_000) { return NumOpResult::Valid(ret); diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index dd2cbb0073..31fae382d6 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -64,15 +64,18 @@ impl FeeRate { /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). pub const fn from_sat_per_kvb(sat_kvb: u64) -> Self { FeeRate::from_sat_per_kwu(sat_kvb / 4) } - /// Returns raw fee rate. - pub const fn to_sat_per_kwu(self) -> u64 { self.0 } + /// Converts to sat/kwu rounding down. + pub const fn to_sat_per_kwu_floor(self) -> u64 { self.0 } + + /// Converts to sat/kwu rounding up. + pub const fn to_sat_per_kwu_ceil(self) -> u64 { self.0 } /// Converts to sat/vB rounding down. - pub const fn to_sat_per_vb_floor(self) -> u64 { self.to_sat_per_kwu() / (1000 / 4) } + pub const fn to_sat_per_vb_floor(self) -> u64 { self.to_sat_per_kwu_floor() / (1000 / 4) } /// Converts to sat/vB rounding up. pub const fn to_sat_per_vb_ceil(self) -> u64 { - (self.to_sat_per_kwu() + (1000 / 4 - 1)) / (1000 / 4) + (self.to_sat_per_kwu_floor() + (1000 / 4 - 1)) / (1000 / 4) } /// Checked multiplication. @@ -81,7 +84,7 @@ impl FeeRate { #[must_use] pub const fn checked_mul(self, rhs: u64) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu().checked_mul(rhs) { + match self.to_sat_per_kwu_floor().checked_mul(rhs) { Some(res) => Some(Self::from_sat_per_kwu(res)), None => None, } @@ -93,7 +96,7 @@ impl FeeRate { #[must_use] pub const fn checked_div(self, rhs: u64) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu().checked_div(rhs) { + match self.to_sat_per_kwu_floor().checked_div(rhs) { Some(res) => Some(Self::from_sat_per_kwu(res)), None => None, } @@ -105,7 +108,7 @@ impl FeeRate { #[must_use] pub const fn checked_add(self, rhs: FeeRate) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu().checked_add(rhs.to_sat_per_kwu()) { + match self.to_sat_per_kwu_floor().checked_add(rhs.to_sat_per_kwu_floor()) { Some(res) => Some(Self::from_sat_per_kwu(res)), None => None, } @@ -117,7 +120,7 @@ impl FeeRate { #[must_use] pub const fn checked_sub(self, rhs: FeeRate) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu().checked_sub(rhs.to_sat_per_kwu()) { + match self.to_sat_per_kwu_floor().checked_sub(rhs.to_sat_per_kwu_floor()) { Some(res) => Some(Self::from_sat_per_kwu(res)), None => None, } @@ -128,19 +131,19 @@ crate::internal_macros::impl_op_for_references! { impl ops::Add for FeeRate { type Output = FeeRate; - fn add(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu() + rhs.to_sat_per_kwu()) } + fn add(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu_floor() + rhs.to_sat_per_kwu_floor()) } } impl ops::Sub for FeeRate { type Output = FeeRate; - fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu() - rhs.to_sat_per_kwu()) } + fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu_floor() - rhs.to_sat_per_kwu_floor()) } } impl ops::Div for FeeRate { type Output = FeeRate; - fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_kwu(self.to_sat_per_kwu() / rhs.get()) } + fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_kwu(self.to_sat_per_kwu_floor() / rhs.get()) } } } crate::internal_macros::impl_add_assign!(FeeRate); @@ -151,7 +154,7 @@ impl core::iter::Sum for FeeRate { where I: Iterator, { - FeeRate::from_sat_per_kwu(iter.map(FeeRate::to_sat_per_kwu).sum()) + FeeRate::from_sat_per_kwu(iter.map(FeeRate::to_sat_per_kwu_floor).sum()) } } @@ -160,7 +163,7 @@ impl<'a> core::iter::Sum<&'a FeeRate> for FeeRate { where I: Iterator, { - FeeRate::from_sat_per_kwu(iter.map(|f| FeeRate::to_sat_per_kwu(*f)).sum()) + FeeRate::from_sat_per_kwu(iter.map(|f| FeeRate::to_sat_per_kwu_floor(*f)).sum()) } } @@ -266,11 +269,11 @@ mod tests { #[test] fn fee_rate_const() { - assert_eq!(FeeRate::ZERO.to_sat_per_kwu(), 0); - assert_eq!(FeeRate::MIN.to_sat_per_kwu(), u64::MIN); - assert_eq!(FeeRate::MAX.to_sat_per_kwu(), u64::MAX); - assert_eq!(FeeRate::BROADCAST_MIN.to_sat_per_kwu(), 250); - assert_eq!(FeeRate::DUST.to_sat_per_kwu(), 750); + assert_eq!(FeeRate::ZERO.to_sat_per_kwu_floor(), 0); + assert_eq!(FeeRate::MIN.to_sat_per_kwu_floor(), u64::MIN); + assert_eq!(FeeRate::MAX.to_sat_per_kwu_floor(), u64::MAX); + assert_eq!(FeeRate::BROADCAST_MIN.to_sat_per_kwu_floor(), 250); + assert_eq!(FeeRate::DUST.to_sat_per_kwu_floor(), 750); } #[test] @@ -304,7 +307,7 @@ mod tests { #[test] fn raw_feerate() { let fee_rate = FeeRate::from_sat_per_kwu(749); - assert_eq!(fee_rate.to_sat_per_kwu(), 749); + assert_eq!(fee_rate.to_sat_per_kwu_floor(), 749); assert_eq!(fee_rate.to_sat_per_vb_floor(), 2); assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3); } diff --git a/units/src/fee_rate/serde.rs b/units/src/fee_rate/serde.rs index ae2e2fb8f2..473d1ba15c 100644 --- a/units/src/fee_rate/serde.rs +++ b/units/src/fee_rate/serde.rs @@ -36,7 +36,7 @@ pub mod as_sat_per_kwu { use crate::FeeRate; pub fn serialize(f: &FeeRate, s: S) -> Result { - u64::serialize(&f.to_sat_per_kwu(), s) + u64::serialize(&f.to_sat_per_kwu_floor(), s) } pub fn deserialize<'d, D: Deserializer<'d>>(d: D) -> Result { @@ -57,7 +57,7 @@ pub mod as_sat_per_kwu { #[allow(clippy::ref_option)] // API forced by serde. pub fn serialize(f: &Option, s: S) -> Result { match *f { - Some(f) => s.serialize_some(&f.to_sat_per_kwu()), + Some(f) => s.serialize_some(&f.to_sat_per_kwu_floor()), None => s.serialize_none(), } } From fe0a448e78d77af2e2cdb43f8e116297a0e7311f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 05:46:28 +1000 Subject: [PATCH 052/857] Temporarily remove const from fee calc function Code that works with `const` is annoying to use and hard to reason about. Just remove all the consts for now so we can hack on `FeeRate`. Introduces two lint warnings about manual implementation of `map` but they will go away later. --- units/src/fee.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 418db80ce9..2db3803baf 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -55,7 +55,7 @@ impl Amount { /// # Ok::<_, amount::OutOfRangeError>(()) /// ``` #[must_use] - pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { + pub fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { let wu = weight.to_wu(); // No `?` operator in const context. if let Some(sats) = self.to_sat().checked_mul(1_000) { @@ -78,7 +78,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] - pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { + pub fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { match self.to_sat().checked_mul(1000) { Some(amount_msats) => match amount_msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { Some(wu) => Some(Weight::from_wu(wu)), @@ -95,7 +95,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] - pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { + pub fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { // Use ceil because result is used as the divisor. let rate = fee_rate.to_sat_per_kwu_ceil(); match self.to_sat().checked_mul(1000) { @@ -119,7 +119,7 @@ impl FeeRate { /// [`NumOpResult::Error`] if an overflow occurred. /// /// This is equivalent to `Self::checked_mul_by_weight()`. - pub const fn to_fee(self, weight: Weight) -> NumOpResult { + pub fn to_fee(self, weight: Weight) -> NumOpResult { self.checked_mul_by_weight(weight) } @@ -151,7 +151,7 @@ impl FeeRate { /// enough instead of falling short if rounded down. /// /// Returns [`NumOpResult::Error`] if overflow occurred. - pub const fn checked_mul_by_weight(self, weight: Weight) -> NumOpResult { + pub fn checked_mul_by_weight(self, weight: Weight) -> NumOpResult { if let Some(fee) = self.to_sat_per_kwu_floor().checked_mul(weight.to_wu()) { if let Some(round_up) = fee.checked_add(999) { if let Ok(ret) = Amount::from_sat(round_up / 1_000) { @@ -329,7 +329,7 @@ impl Weight { /// enough instead of falling short if rounded down. /// /// Returns [`None`] if overflow occurred. - pub const fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult { + pub fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult { fee_rate.checked_mul_by_weight(self) } } From 64ac33754f5b961704f25f919d4b93a1ffd243f8 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 May 2025 13:53:10 +1000 Subject: [PATCH 053/857] Add missing argument docs We document the other to arguments already, add the missing one. --- bitcoin/src/blockdata/transaction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 0e64bdd3c2..bea8e5bdca 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -776,6 +776,7 @@ impl Decodable for Transaction { /// /// * `fee_rate` - the fee rate of the transaction being created. /// * `input_weight_prediction` - the predicted input weight. +/// * `value` - The value of the output we are spending. /// /// # Returns /// From d174c06a4ac776fa2cbb4a24a17a6b21c4863b85 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 08:45:31 +1000 Subject: [PATCH 054/857] Saturate to_fee to Amount::MAX The `FeeRate::checked_mul_by_weight` function currently returns a `NumOpResult` but all other `checked_` functions return an `Option`. This is surprising and adds no additional information. Change `checked_mul_by_weight` to return `None` on overflow. But in `to_fee` saturate to `Amount::MAX` because doing so makes a few APIs better without any risk since a fee must be checked anyway so `Amount::MAX` as a fee is equally descriptive in the error case. This leads to removing the `NumOpResult` from `effective_value` also. Note that sadly we remove the very nice docs on `NumOpResult::map` because they no longer work. Fix: #4497 --- bitcoin/src/blockdata/transaction.rs | 16 +++----- units/src/fee.rs | 60 ++++++++++++++-------------- units/src/result.rs | 17 -------- 3 files changed, 36 insertions(+), 57 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index bea8e5bdca..678ac8d210 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -18,7 +18,6 @@ use hashes::sha256d; use internals::{compact_size, write_err, ToU64}; use io::{BufRead, Write}; use primitives::Sequence; -use units::NumOpResult; use super::Weight; use crate::consensus::{self, encode, Decodable, Encodable}; @@ -777,19 +776,15 @@ impl Decodable for Transaction { /// * `fee_rate` - the fee rate of the transaction being created. /// * `input_weight_prediction` - the predicted input weight. /// * `value` - The value of the output we are spending. -/// -/// # Returns -/// -/// This will return [`NumOpResult::Error`] if the fee calculation (fee_rate * weight) overflows. -/// Otherwise, [`NumOpResult::Valid`] will wrap the successful calculation. pub fn effective_value( fee_rate: FeeRate, input_weight_prediction: InputWeightPrediction, value: Amount, -) -> NumOpResult { +) -> SignedAmount { let weight = input_weight_prediction.total_weight(); + let fee = fee_rate.to_fee(weight); - fee_rate.to_fee(weight).map(Amount::to_signed).and_then(|fee| value.to_signed() - fee) // Cannot overflow. + (value.to_signed() - fee.to_signed()).expect("cannot overflow") } /// Predicts the weight of a to-be-constructed transaction. @@ -1693,8 +1688,7 @@ mod tests { fn effective_value_happy_path() { let value = "1 cBTC".parse::().unwrap(); let fee_rate = FeeRate::from_sat_per_kwu(10); - let effective_value = - effective_value(fee_rate, InputWeightPrediction::P2WPKH_MAX, value).unwrap(); + let effective_value = effective_value(fee_rate, InputWeightPrediction::P2WPKH_MAX, value); // 10 sat/kwu * 272 wu = 4 sats (rounding up) let expected_fee = "3 sats".parse::().unwrap(); @@ -1706,7 +1700,7 @@ mod tests { fn effective_value_fee_rate_does_not_overflow() { let eff_value = effective_value(FeeRate::MAX, InputWeightPrediction::P2WPKH_MAX, Amount::ZERO); - assert!(eff_value.is_error()); + assert_eq!(eff_value, SignedAmount::MIN) } #[test] diff --git a/units/src/fee.rs b/units/src/fee.rs index 2db3803baf..596b5f99d0 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -115,12 +115,17 @@ impl Amount { } impl FeeRate { - /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning - /// [`NumOpResult::Error`] if an overflow occurred. + /// Calculates the fee by multiplying this fee rate by weight. /// - /// This is equivalent to `Self::checked_mul_by_weight()`. - pub fn to_fee(self, weight: Weight) -> NumOpResult { - self.checked_mul_by_weight(weight) + /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting + /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is + /// enough instead of falling short if rounded down. + /// + /// If the calculation would overflow we saturate to [`Amount::MAX`]. Since such a fee can never + /// be paid this is meaningful as an error case while still removing the possibility of silently + /// wrapping. + pub fn to_fee(self, weight: Weight) -> Amount { + self.checked_mul_by_weight(weight).unwrap_or(Amount::MAX) } /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`] @@ -129,9 +134,7 @@ impl FeeRate { /// This is equivalent to `Self::checked_mul_by_weight()`. #[must_use] #[deprecated(since = "TBD", note = "use `to_fee()` instead")] - pub fn fee_wu(self, weight: Weight) -> Option { - self.checked_mul_by_weight(weight).ok() - } + pub fn fee_wu(self, weight: Weight) -> Option { self.checked_mul_by_weight(weight) } /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`] /// if an overflow occurred. @@ -140,9 +143,7 @@ impl FeeRate { /// `Self::fee_wu(weight)`. #[must_use] #[deprecated(since = "TBD", note = "use Weight::from_vb and then `to_fee()` instead")] - pub fn fee_vb(self, vb: u64) -> Option { - Weight::from_vb(vb).and_then(|w| self.to_fee(w).ok()) - } + pub fn fee_vb(self, vb: u64) -> Option { Weight::from_vb(vb).map(|w| self.to_fee(w)) } /// Checked weight multiplication. /// @@ -150,16 +151,14 @@ impl FeeRate { /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is /// enough instead of falling short if rounded down. /// - /// Returns [`NumOpResult::Error`] if overflow occurred. - pub fn checked_mul_by_weight(self, weight: Weight) -> NumOpResult { - if let Some(fee) = self.to_sat_per_kwu_floor().checked_mul(weight.to_wu()) { - if let Some(round_up) = fee.checked_add(999) { - if let Ok(ret) = Amount::from_sat(round_up / 1_000) { - return NumOpResult::Valid(ret); - } - } - } - NumOpResult::Error(E::while_doing(MathOp::Mul)) + /// Returns [`None`] if overflow occurred. + pub fn checked_mul_by_weight(self, weight: Weight) -> Option { + let wu = weight.to_wu(); + let fee_kwu = self.to_sat_per_kwu_floor().checked_mul(wu)?; + let bump = fee_kwu.checked_add(999)?; // We do ceil division. + let fee = bump / 1_000; + + Amount::from_sat(fee).ok() } } @@ -167,7 +166,10 @@ crate::internal_macros::impl_op_for_references! { impl ops::Mul for Weight { type Output = NumOpResult; fn mul(self, rhs: FeeRate) -> Self::Output { - rhs.checked_mul_by_weight(self) + match rhs.checked_mul_by_weight(self) { + Some(amount) => R::Valid(amount), + None => R::Error(E::while_doing(MathOp::Mul)), + } } } impl ops::Mul for NumOpResult { @@ -204,7 +206,10 @@ crate::internal_macros::impl_op_for_references! { impl ops::Mul for FeeRate { type Output = NumOpResult; fn mul(self, rhs: Weight) -> Self::Output { - self.checked_mul_by_weight(rhs) + match self.checked_mul_by_weight(rhs) { + Some(amount) => R::Valid(amount), + None => R::Error(E::while_doing(MathOp::Mul)), + } } } impl ops::Mul for NumOpResult { @@ -329,7 +334,7 @@ impl Weight { /// enough instead of falling short if rounded down. /// /// Returns [`None`] if overflow occurred. - pub fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult { + pub fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { fee_rate.checked_mul_by_weight(self) } } @@ -346,12 +351,9 @@ mod tests { #[test] fn fee_wu() { - let operation = FeeRate::from_sat_per_kwu(10).to_fee(Weight::MAX).unwrap_err().operation(); - assert!(operation.is_multiplication()); - let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); let weight = Weight::from_vb(3).unwrap(); - assert_eq!(fee_rate.to_fee(weight).unwrap(), Amount::from_sat_u32(6)); + assert_eq!(fee_rate.to_fee(weight), Amount::from_sat_u32(6)); } #[test] @@ -364,7 +366,7 @@ mod tests { assert_eq!(Amount::from_sat_u32(100), fee); let fee = FeeRate::from_sat_per_kwu(10).checked_mul_by_weight(Weight::MAX); - assert!(fee.is_error()); + assert!(fee.is_none()); let weight = Weight::from_vb(3).unwrap(); let fee_rate = FeeRate::from_sat_per_vb(3).unwrap(); diff --git a/units/src/result.rs b/units/src/result.rs index 7de341f608..c64ab5cbe3 100644 --- a/units/src/result.rs +++ b/units/src/result.rs @@ -90,23 +90,6 @@ pub enum NumOpResult { impl NumOpResult { /// Maps a `NumOpResult` to `NumOpResult` by applying a function to a /// contained [`NumOpResult::Valid`] value, leaving a [`NumOpResult::Error`] value untouched. - /// - /// # Examples - /// - /// ``` - /// use bitcoin_units::{FeeRate, Amount, Weight, SignedAmount}; - /// - /// let fee_rate = FeeRate::from_sat_per_vb(1).unwrap(); - /// let weight = Weight::from_wu(1000); - /// let amount = Amount::from_sat_u32(1_000_000); - /// - /// let amount_after_fee = fee_rate - /// .to_fee(weight) // (1 sat/ 4 wu) * (1000 wu) = 250 sat fee - /// .map(|fee| fee.to_signed()) - /// .and_then(|fee| amount.to_signed() - fee); - /// - /// assert_eq!(amount_after_fee.unwrap(), SignedAmount::from_sat_i32(999_750)) - /// ``` #[inline] pub fn map U>(self, op: F) -> NumOpResult { match self { From 399bca531cbf2003f4ac8d880729408cf3969b13 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 08:57:15 +1000 Subject: [PATCH 055/857] Reduce the FeeRate::MAX value In preparation for changing the internal representation of `FeeRate` to use MvB reduce the max value by 4_000. Done separately to make the change explicit. --- bitcoin/src/blockdata/transaction.rs | 3 ++- units/src/fee_rate/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 678ac8d210..2a3da7b469 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1700,7 +1700,8 @@ mod tests { fn effective_value_fee_rate_does_not_overflow() { let eff_value = effective_value(FeeRate::MAX, InputWeightPrediction::P2WPKH_MAX, Amount::ZERO); - assert_eq!(eff_value, SignedAmount::MIN) + let want = SignedAmount::from_sat(-1254378597012250).unwrap(); // U64::MAX / 4_000 because of FeeRate::MAX + assert_eq!(eff_value, want) } #[test] diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 31fae382d6..84e8d9f864 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -30,7 +30,7 @@ impl FeeRate { pub const MIN: FeeRate = FeeRate::ZERO; /// Maximum possible value. - pub const MAX: FeeRate = FeeRate::from_sat_per_kwu(u64::MAX); + pub const MAX: FeeRate = FeeRate::from_sat_per_kwu(u64::MAX / 4_000); /// Minimum fee rate required to broadcast a transaction. /// @@ -271,7 +271,7 @@ mod tests { fn fee_rate_const() { assert_eq!(FeeRate::ZERO.to_sat_per_kwu_floor(), 0); assert_eq!(FeeRate::MIN.to_sat_per_kwu_floor(), u64::MIN); - assert_eq!(FeeRate::MAX.to_sat_per_kwu_floor(), u64::MAX); + assert_eq!(FeeRate::MAX.to_sat_per_kwu_floor(), u64::MAX / 4_000); assert_eq!(FeeRate::BROADCAST_MIN.to_sat_per_kwu_floor(), 250); assert_eq!(FeeRate::DUST.to_sat_per_kwu_floor(), 750); } From 2e0b88ba76ebb5543c49d4184badaa1fe46fff39 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 11:09:06 +1000 Subject: [PATCH 056/857] bitcoin: Fix dust 'fee' identifiers Currently we get the fee_rate per kwu then multiply it by 4. Instead lets add a per_kvb function to `FeeRate`. We are about to change the internal representation of `FeeRate` to use MvB so for now just panic on ovelflow. Also these are fee _rates_ - we already have suboptimal names from Core in the consts in `policy`, no need to let them infect other identifiers. --- bitcoin/src/blockdata/script/borrowed.rs | 8 ++++---- units/src/fee_rate/mod.rs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 41a89e4a76..97c294b33e 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -289,8 +289,8 @@ crate::internal_macros::define_extension_trait! { /// To use the default Bitcoin Core value, use [`minimal_non_dust`]. /// /// [`minimal_non_dust`]: Script::minimal_non_dust - fn minimal_non_dust_custom(&self, dust_relay_fee: FeeRate) -> Option { - self.minimal_non_dust_internal(dust_relay_fee.to_sat_per_kwu_ceil() * 4) + fn minimal_non_dust_custom(&self, dust_relay: FeeRate) -> Option { + self.minimal_non_dust_internal(dust_relay.to_sat_per_kvb()) } /// Counts the sigops for this Script using accurate counting. @@ -407,10 +407,10 @@ mod sealed { crate::internal_macros::define_extension_trait! { pub(crate) trait ScriptExtPriv impl for Script { - fn minimal_non_dust_internal(&self, dust_relay_fee: u64) -> Option { + fn minimal_non_dust_internal(&self, dust_relay_fee_rate_per_kvb: u64) -> Option { // This must never be lower than Bitcoin Core's GetDustThreshold() (as of v0.21) as it may // otherwise allow users to create transactions which likely can never be broadcast/confirmed. - let sats = dust_relay_fee + let sats = dust_relay_fee_rate_per_kvb .checked_mul(if self.is_op_return() { 0 } else if self.is_witness_program() { diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 84e8d9f864..f2f73e162a 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -78,6 +78,9 @@ impl FeeRate { (self.to_sat_per_kwu_floor() + (1000 / 4 - 1)) / (1000 / 4) } + /// Converts to sat/kvb. + pub const fn to_sat_per_kvb(self) -> u64 { self.to_sat_per_kwu_floor() * 4 } + /// Checked multiplication. /// /// Computes `self * rhs` returning [`None`] if overflow occurred. From b27d8e581933aab5d7af5b034f9a422bc41c9bb5 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 11:18:15 +1000 Subject: [PATCH 057/857] Change the internal representation of FeeRate To get more precision use sats per million virtual bytes. To make review easier keep most calls in tests using `FeeRate::from_sats_per_kwu` and just unwrap. These can likely be cleaned up later on if we want to. For `serde` just change the module to `_floor` and leave it at that. The serde stuff likely needs re-visiting before release anyways. --- bitcoin/src/blockdata/script/borrowed.rs | 2 +- bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/psbt/mod.rs | 14 +- .../bitcoin/deserialize_script.rs | 2 +- units/src/amount/tests.rs | 16 +- units/src/fee.rs | 46 +++-- units/src/fee_rate/mod.rs | 178 +++++++++++------- units/src/fee_rate/serde.rs | 7 +- units/tests/serde.rs | 4 +- 9 files changed, 154 insertions(+), 117 deletions(-) diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 97c294b33e..a6b36b1988 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -290,7 +290,7 @@ crate::internal_macros::define_extension_trait! { /// /// [`minimal_non_dust`]: Script::minimal_non_dust fn minimal_non_dust_custom(&self, dust_relay: FeeRate) -> Option { - self.minimal_non_dust_internal(dust_relay.to_sat_per_kvb()) + self.minimal_non_dust_internal(dust_relay.to_sat_per_kvb_ceil()) } /// Counts the sigops for this Script using accurate counting. diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 2a3da7b469..4fcff528cd 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1687,7 +1687,7 @@ mod tests { #[test] fn effective_value_happy_path() { let value = "1 cBTC".parse::().unwrap(); - let fee_rate = FeeRate::from_sat_per_kwu(10); + let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap(); let effective_value = effective_value(fee_rate, InputWeightPrediction::P2WPKH_MAX, value); // 10 sat/kwu * 272 wu = 4 sats (rounding up) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index b8f5188986..07b2d8f41d 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1356,9 +1356,15 @@ mod tests { use crate::Sequence; /// Fee rate in sat/kwu for a high-fee PSBT with an input=5_000_000_000_000, output=1000 - const ABSURD_FEE_RATE: FeeRate = FeeRate::from_sat_per_kwu(15_060_240_960_843); - /// Fee rate which is just below absurd threshold (1 sat/kwu less) - const JUST_BELOW_ABSURD_FEE_RATE: FeeRate = FeeRate::from_sat_per_kwu(15_060_240_960_842); + const ABSURD_FEE_RATE: FeeRate = match FeeRate::from_sat_per_kwu(15_060_240_960_843) { + Some(fee_rate) => fee_rate, + None => panic!("unreachable - no unwrap in Rust 1.63 in const"), + }; + const JUST_BELOW_ABSURD_FEE_RATE: FeeRate = match FeeRate::from_sat_per_kwu(15_060_240_960_842) + { + Some(fee_rate) => fee_rate, + None => panic!("unreachable - no unwrap in Rust 1.63 in const"), + }; #[track_caller] pub fn hex_psbt(s: &str) -> Result { @@ -1475,7 +1481,7 @@ mod tests { ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, _ => panic!(""), }), - Err(FeeRate::from_sat_per_kwu(6250003)) // 6250000 is 25k sat/vbyte + Err(FeeRate::from_sat_per_kwu(6250003).unwrap()) // 6250000 is 25k sat/vbyte ); // Lowering the input satoshis by 1 lowers the sat/kwu by 3 diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs index 41ef804933..c227c59b41 100644 --- a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs +++ b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs @@ -17,7 +17,7 @@ fn do_test(data: &[u8]) { let _ = script.count_sigops_legacy(); let _ = script.minimal_non_dust(); - let fee_rate = FeeRate::from_sat_per_kwu(consume_u64(&mut new_data)); + let fee_rate = FeeRate::from_sat_per_kwu(consume_u64(&mut new_data)).unwrap(); let _ = script.minimal_non_dust_custom(fee_rate); let mut b = script::Builder::new(); diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index ebff58af59..021fa13bc1 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -270,13 +270,13 @@ fn amount_checked_div_by_weight_ceil() { let weight = Weight::from_kwu(1).unwrap(); let fee_rate = sat(1).checked_div_by_weight_ceil(weight).unwrap(); // 1 sats / 1,000 wu = 1 sats/kwu - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); let weight = Weight::from_wu(381); let fee_rate = sat(329).checked_div_by_weight_ceil(weight).unwrap(); // 329 sats / 381 wu = 863.5 sats/kwu // round up to 864 - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864).unwrap()); let fee_rate = Amount::ONE_SAT.checked_div_by_weight_ceil(Weight::ZERO); assert!(fee_rate.is_none()); @@ -288,13 +288,13 @@ fn amount_checked_div_by_weight_floor() { let weight = Weight::from_kwu(1).unwrap(); let fee_rate = sat(1).checked_div_by_weight_floor(weight).unwrap(); // 1 sats / 1,000 wu = 1 sats/kwu - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); let weight = Weight::from_wu(381); let fee_rate = sat(329).checked_div_by_weight_floor(weight).unwrap(); // 329 sats / 381 wu = 863.5 sats/kwu // round down to 863 - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863).unwrap()); let fee_rate = Amount::ONE_SAT.checked_div_by_weight_floor(Weight::ZERO); assert!(fee_rate.is_none()); @@ -304,7 +304,7 @@ fn amount_checked_div_by_weight_floor() { #[test] fn amount_checked_div_by_fee_rate() { let amount = sat(1000); - let fee_rate = FeeRate::from_sat_per_kwu(2); + let fee_rate = FeeRate::from_sat_per_kwu(2).unwrap(); // Test floor division let weight = amount.checked_div_by_fee_rate_floor(fee_rate).unwrap(); @@ -317,20 +317,20 @@ fn amount_checked_div_by_fee_rate() { // Test truncation behavior let amount = sat(1000); - let fee_rate = FeeRate::from_sat_per_kwu(3); + let fee_rate = FeeRate::from_sat_per_kwu(3).unwrap(); let floor_weight = amount.checked_div_by_fee_rate_floor(fee_rate).unwrap(); let ceil_weight = amount.checked_div_by_fee_rate_ceil(fee_rate).unwrap(); assert_eq!(floor_weight, Weight::from_wu(333_333)); assert_eq!(ceil_weight, Weight::from_wu(333_334)); // Test division by zero - let zero_fee_rate = FeeRate::from_sat_per_kwu(0); + let zero_fee_rate = FeeRate::from_sat_per_kwu(0).unwrap(); assert!(amount.checked_div_by_fee_rate_floor(zero_fee_rate).is_none()); assert!(amount.checked_div_by_fee_rate_ceil(zero_fee_rate).is_none()); // Test with maximum amount let max_amount = Amount::MAX; - let small_fee_rate = FeeRate::from_sat_per_kwu(1); + let small_fee_rate = FeeRate::from_sat_per_kwu(1).unwrap(); let weight = max_amount.checked_div_by_fee_rate_floor(small_fee_rate).unwrap(); // 21_000_000_0000_0000 sats / (1 sat/kwu) = 2_100_000_000_000_000_000 wu assert_eq!(weight, Weight::from_wu(2_100_000_000_000_000_000)); diff --git a/units/src/fee.rs b/units/src/fee.rs index 596b5f99d0..73b4919aa9 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -26,14 +26,15 @@ impl Amount { /// Returns [`None`] if overflow occurred. #[must_use] pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option { - // No `?` operator in const context. - match self.to_sat().checked_mul(1_000) { - Some(res) => match res.checked_div(weight.to_wu()) { - Some(fee_rate) => Some(FeeRate::from_sat_per_kwu(fee_rate)), - None => None, - }, - None => None, + let wu = weight.to_wu(); + if wu == 0 { + return None; } + + let sats = self.to_sat() * 1_000; // Because we use per/kwu. + let fee_rate = sats / wu; + + FeeRate::from_sat_per_kwu(fee_rate) } /// Checked weight ceiling division. @@ -51,23 +52,20 @@ impl Amount { /// let amount = Amount::from_sat(10)?; /// let weight = Weight::from_wu(300); /// let fee_rate = amount.checked_div_by_weight_ceil(weight); - /// assert_eq!(fee_rate, Some(FeeRate::from_sat_per_kwu(34))); + /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34)); /// # Ok::<_, amount::OutOfRangeError>(()) /// ``` #[must_use] pub fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { let wu = weight.to_wu(); - // No `?` operator in const context. - if let Some(sats) = self.to_sat().checked_mul(1_000) { - if let Some(wu_minus_one) = wu.checked_sub(1) { - if let Some(sats_plus_wu_minus_one) = sats.checked_add(wu_minus_one) { - if let Some(fee_rate) = sats_plus_wu_minus_one.checked_div(wu) { - return Some(FeeRate::from_sat_per_kwu(fee_rate)); - } - } - } + if wu == 0 { + return None; } - None + + let sats = self.to_sat() * 1_000; // Because we use per/kwu. + let fee_rate = (sats + wu - 1) / wu; + + FeeRate::from_sat_per_kwu(fee_rate) } /// Checked fee rate floor division. @@ -346,7 +344,7 @@ mod tests { #[test] fn fee_rate_div_by_weight() { let fee_rate = (Amount::from_sat_u32(329) / Weight::from_wu(381)).unwrap(); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863).unwrap()); } #[test] @@ -365,7 +363,7 @@ mod tests { .expect("expected Amount"); assert_eq!(Amount::from_sat_u32(100), fee); - let fee = FeeRate::from_sat_per_kwu(10).checked_mul_by_weight(Weight::MAX); + let fee = FeeRate::from_sat_per_kwu(10).unwrap().checked_mul_by_weight(Weight::MAX); assert!(fee.is_none()); let weight = Weight::from_vb(3).unwrap(); @@ -374,7 +372,7 @@ mod tests { assert_eq!(Amount::from_sat_u32(9), fee); let weight = Weight::from_wu(381); - let fee_rate = FeeRate::from_sat_per_kwu(864); + let fee_rate = FeeRate::from_sat_per_kwu(864).unwrap(); let fee = weight.checked_mul_by_fee_rate(fee_rate).unwrap(); // 381 * 0.864 yields 329.18. // The result is then rounded up to 330. @@ -401,7 +399,7 @@ mod tests { fn amount_div_by_fee_rate() { // Test exact division let amount = Amount::from_sat_u32(1000); - let fee_rate = FeeRate::from_sat_per_kwu(2); + let fee_rate = FeeRate::from_sat_per_kwu(2).unwrap(); let weight = (amount / fee_rate).unwrap(); assert_eq!(weight, Weight::from_wu(500_000)); @@ -415,7 +413,7 @@ mod tests { // Test truncation behavior let amount = Amount::from_sat_u32(1000); - let fee_rate = FeeRate::from_sat_per_kwu(3); + let fee_rate = FeeRate::from_sat_per_kwu(3).unwrap(); let weight = (amount / fee_rate).unwrap(); // 1000 * 1000 = 1,000,000 msats // 1,000,000 / 3 = 333,333.33... wu @@ -427,7 +425,7 @@ mod tests { assert_eq!(ceil_weight, Weight::from_wu(333_334)); // Test that division by zero returns None - let zero_rate = FeeRate::from_sat_per_kwu(0); + let zero_rate = FeeRate::from_sat_per_kwu(0).unwrap(); assert!(amount.checked_div_by_fee_rate_floor(zero_rate).is_none()); assert!(amount.checked_div_by_fee_rate_ceil(zero_rate).is_none()); } diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index f2f73e162a..87e89c50bd 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -22,7 +22,7 @@ impl FeeRate { /// 0 sat/kwu. /// /// Equivalent to [`MIN`](Self::MIN), may better express intent in some contexts. - pub const ZERO: FeeRate = FeeRate::from_sat_per_kwu(0); + pub const ZERO: FeeRate = FeeRate::from_sat_per_mvb(0); /// Minimum possible value (0 sat/kwu). /// @@ -30,7 +30,7 @@ impl FeeRate { pub const MIN: FeeRate = FeeRate::ZERO; /// Maximum possible value. - pub const MAX: FeeRate = FeeRate::from_sat_per_kwu(u64::MAX / 4_000); + pub const MAX: FeeRate = FeeRate::from_sat_per_mvb(u64::MAX); /// Minimum fee rate required to broadcast a transaction. /// @@ -40,46 +40,66 @@ impl FeeRate { /// Fee rate used to compute dust amount. pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); + /// Constructs a new [`FeeRate`] from satoshis per 1,000,000 virtual bytes. + pub(crate) const fn from_sat_per_mvb(sat_mvb: u64) -> Self { Self(sat_mvb) } + /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. - pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self { FeeRate(sat_kwu) } + pub const fn from_sat_per_kwu(sat_kwu: u64) -> Option { + // No `map()` in const context. + match sat_kwu.checked_mul(4_000) { + Some(fee_rate) => Some(FeeRate::from_sat_per_mvb(fee_rate)), + None => None, + } + } /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. /// /// # Errors /// /// Returns [`None`] on arithmetic overflow. - pub fn from_sat_per_vb(sat_vb: u64) -> Option { - // 1 vb == 4 wu - // 1 sat/vb == 1/4 sat/wu - // sat/vb * 1000 / 4 == sat/kwu - Some(FeeRate::from_sat_per_kwu(sat_vb.checked_mul(1000 / 4)?)) + pub const fn from_sat_per_vb(sat_vb: u64) -> Option { + // No `map()` in const context. + match sat_vb.checked_mul(1_000_000) { + Some(fee_rate) => Some(FeeRate::from_sat_per_mvb(fee_rate)), + None => None, + } } /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. pub const fn from_sat_per_vb_u32(sat_vb: u32) -> Self { let sat_vb = sat_vb as u64; // No `Into` in const context. - FeeRate::from_sat_per_kwu(sat_vb * (1000 / 4)) + FeeRate::from_sat_per_mvb(sat_vb * 1_000_000) } /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). - pub const fn from_sat_per_kvb(sat_kvb: u64) -> Self { FeeRate::from_sat_per_kwu(sat_kvb / 4) } + pub const fn from_sat_per_kvb(sat_kvb: u64) -> Option { + // No `map()` in const context. + match sat_kvb.checked_mul(1_000) { + Some(fee_rate) => Some(FeeRate::from_sat_per_mvb(fee_rate)), + None => None, + } + } + + /// Converts to sat/MvB. + pub(crate) const fn to_sat_per_mvb(self) -> u64 { self.0 } /// Converts to sat/kwu rounding down. - pub const fn to_sat_per_kwu_floor(self) -> u64 { self.0 } + pub const fn to_sat_per_kwu_floor(self) -> u64 { self.to_sat_per_mvb() / 4_000 } /// Converts to sat/kwu rounding up. - pub const fn to_sat_per_kwu_ceil(self) -> u64 { self.0 } + pub const fn to_sat_per_kwu_ceil(self) -> u64 { (self.to_sat_per_mvb() + 3_999) / 4_000 } /// Converts to sat/vB rounding down. - pub const fn to_sat_per_vb_floor(self) -> u64 { self.to_sat_per_kwu_floor() / (1000 / 4) } + pub const fn to_sat_per_vb_floor(self) -> u64 { self.to_sat_per_mvb() / 1_000_000 } /// Converts to sat/vB rounding up. - pub const fn to_sat_per_vb_ceil(self) -> u64 { - (self.to_sat_per_kwu_floor() + (1000 / 4 - 1)) / (1000 / 4) - } + pub const fn to_sat_per_vb_ceil(self) -> u64 { (self.to_sat_per_mvb() + 999_999) / 1_000_000 } - /// Converts to sat/kvb. - pub const fn to_sat_per_kvb(self) -> u64 { self.to_sat_per_kwu_floor() * 4 } + /// Converts to sat/kvb rounding down. + pub const fn to_sat_per_kvb_floor(self) -> u64 { self.to_sat_per_mvb() / 1_000 } + + /// Converts to sat/kvb rounding up. + pub const fn to_sat_per_kvb_ceil(self) -> u64 { (self.to_sat_per_mvb() + 999) / 1_000 } /// Checked multiplication. /// @@ -87,8 +107,8 @@ impl FeeRate { #[must_use] pub const fn checked_mul(self, rhs: u64) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu_floor().checked_mul(rhs) { - Some(res) => Some(Self::from_sat_per_kwu(res)), + match self.to_sat_per_mvb().checked_mul(rhs) { + Some(res) => Some(Self::from_sat_per_mvb(res)), None => None, } } @@ -99,8 +119,8 @@ impl FeeRate { #[must_use] pub const fn checked_div(self, rhs: u64) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu_floor().checked_div(rhs) { - Some(res) => Some(Self::from_sat_per_kwu(res)), + match self.to_sat_per_mvb().checked_div(rhs) { + Some(res) => Some(Self::from_sat_per_mvb(res)), None => None, } } @@ -111,8 +131,8 @@ impl FeeRate { #[must_use] pub const fn checked_add(self, rhs: FeeRate) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu_floor().checked_add(rhs.to_sat_per_kwu_floor()) { - Some(res) => Some(Self::from_sat_per_kwu(res)), + match self.to_sat_per_mvb().checked_add(rhs.to_sat_per_mvb()) { + Some(res) => Some(Self::from_sat_per_mvb(res)), None => None, } } @@ -123,8 +143,8 @@ impl FeeRate { #[must_use] pub const fn checked_sub(self, rhs: FeeRate) -> Option { // No `map()` in const context. - match self.to_sat_per_kwu_floor().checked_sub(rhs.to_sat_per_kwu_floor()) { - Some(res) => Some(Self::from_sat_per_kwu(res)), + match self.to_sat_per_mvb().checked_sub(rhs.to_sat_per_mvb()) { + Some(res) => Some(Self::from_sat_per_mvb(res)), None => None, } } @@ -134,19 +154,19 @@ crate::internal_macros::impl_op_for_references! { impl ops::Add for FeeRate { type Output = FeeRate; - fn add(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu_floor() + rhs.to_sat_per_kwu_floor()) } + fn add(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_mvb(self.to_sat_per_mvb() + rhs.to_sat_per_mvb()) } } impl ops::Sub for FeeRate { type Output = FeeRate; - fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_kwu(self.to_sat_per_kwu_floor() - rhs.to_sat_per_kwu_floor()) } + fn sub(self, rhs: FeeRate) -> Self::Output { FeeRate::from_sat_per_mvb(self.to_sat_per_mvb() - rhs.to_sat_per_mvb()) } } impl ops::Div for FeeRate { type Output = FeeRate; - fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_kwu(self.to_sat_per_kwu_floor() / rhs.get()) } + fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_sat_per_mvb(self.to_sat_per_mvb() / rhs.get()) } } } crate::internal_macros::impl_add_assign!(FeeRate); @@ -157,7 +177,7 @@ impl core::iter::Sum for FeeRate { where I: Iterator, { - FeeRate::from_sat_per_kwu(iter.map(FeeRate::to_sat_per_kwu_floor).sum()) + FeeRate::from_sat_per_mvb(iter.map(FeeRate::to_sat_per_mvb).sum()) } } @@ -166,7 +186,7 @@ impl<'a> core::iter::Sum<&'a FeeRate> for FeeRate { where I: Iterator, { - FeeRate::from_sat_per_kwu(iter.map(|f| FeeRate::to_sat_per_kwu_floor(*f)).sum()) + FeeRate::from_sat_per_mvb(iter.map(|f| FeeRate::to_sat_per_mvb(*f)).sum()) } } @@ -179,7 +199,7 @@ impl<'a> Arbitrary<'a> for FeeRate { 1 => Ok(FeeRate::BROADCAST_MIN), 2 => Ok(FeeRate::DUST), 3 => Ok(FeeRate::MAX), - _ => Ok(FeeRate::from_sat_per_kwu(u64::arbitrary(u)?)), + _ => Ok(FeeRate::from_sat_per_mvb(u64::arbitrary(u)?)), } } } @@ -193,18 +213,18 @@ mod tests { #[test] #[allow(clippy::op_ref)] fn feerate_div_nonzero() { - let rate = FeeRate::from_sat_per_kwu(200); + let rate = FeeRate::from_sat_per_kwu(200).unwrap(); let divisor = NonZeroU64::new(2).unwrap(); - assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100)); - assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100)); + assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100).unwrap()); + assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100).unwrap()); } #[test] #[allow(clippy::op_ref)] fn addition() { - let one = FeeRate::from_sat_per_kwu(1); - let two = FeeRate::from_sat_per_kwu(2); - let three = FeeRate::from_sat_per_kwu(3); + let one = FeeRate::from_sat_per_kwu(1).unwrap(); + let two = FeeRate::from_sat_per_kwu(2).unwrap(); + let three = FeeRate::from_sat_per_kwu(3).unwrap(); assert!(one + two == three); assert!(&one + two == three); @@ -215,9 +235,9 @@ mod tests { #[test] #[allow(clippy::op_ref)] fn subtract() { - let three = FeeRate::from_sat_per_kwu(3); - let seven = FeeRate::from_sat_per_kwu(7); - let ten = FeeRate::from_sat_per_kwu(10); + let three = FeeRate::from_sat_per_kwu(3).unwrap(); + let seven = FeeRate::from_sat_per_kwu(7).unwrap(); + let ten = FeeRate::from_sat_per_kwu(10).unwrap(); assert_eq!(ten - seven, three); assert_eq!(&ten - seven, three); @@ -227,43 +247,44 @@ mod tests { #[test] fn add_assign() { - let mut f = FeeRate::from_sat_per_kwu(1); - f += FeeRate::from_sat_per_kwu(2); - assert_eq!(f, FeeRate::from_sat_per_kwu(3)); + let mut f = FeeRate::from_sat_per_kwu(1).unwrap(); + f += FeeRate::from_sat_per_kwu(2).unwrap(); + assert_eq!(f, FeeRate::from_sat_per_kwu(3).unwrap()); - let mut f = FeeRate::from_sat_per_kwu(1); - f += &FeeRate::from_sat_per_kwu(2); - assert_eq!(f, FeeRate::from_sat_per_kwu(3)); + let mut f = FeeRate::from_sat_per_kwu(1).unwrap(); + f += &FeeRate::from_sat_per_kwu(2).unwrap(); + assert_eq!(f, FeeRate::from_sat_per_kwu(3).unwrap()); } #[test] fn sub_assign() { - let mut f = FeeRate::from_sat_per_kwu(3); - f -= FeeRate::from_sat_per_kwu(2); - assert_eq!(f, FeeRate::from_sat_per_kwu(1)); + let mut f = FeeRate::from_sat_per_kwu(3).unwrap(); + f -= FeeRate::from_sat_per_kwu(2).unwrap(); + assert_eq!(f, FeeRate::from_sat_per_kwu(1).unwrap()); - let mut f = FeeRate::from_sat_per_kwu(3); - f -= &FeeRate::from_sat_per_kwu(2); - assert_eq!(f, FeeRate::from_sat_per_kwu(1)); + let mut f = FeeRate::from_sat_per_kwu(3).unwrap(); + f -= &FeeRate::from_sat_per_kwu(2).unwrap(); + assert_eq!(f, FeeRate::from_sat_per_kwu(1).unwrap()); } #[test] fn checked_add() { - let one = FeeRate::from_sat_per_kwu(1); - let two = FeeRate::from_sat_per_kwu(2); - let three = FeeRate::from_sat_per_kwu(3); + let one = FeeRate::from_sat_per_kwu(1).unwrap(); + let two = FeeRate::from_sat_per_kwu(2).unwrap(); + let three = FeeRate::from_sat_per_kwu(3).unwrap(); assert_eq!(one.checked_add(two).unwrap(), three); - let fee_rate = FeeRate::from_sat_per_kwu(u64::MAX).checked_add(one); + assert!(FeeRate::from_sat_per_kvb(u64::MAX).is_none()); // sanity check. + let fee_rate = FeeRate::from_sat_per_mvb(u64::MAX).checked_add(one); assert!(fee_rate.is_none()); } #[test] fn checked_sub() { - let one = FeeRate::from_sat_per_kwu(1); - let two = FeeRate::from_sat_per_kwu(2); - let three = FeeRate::from_sat_per_kwu(3); + let one = FeeRate::from_sat_per_kwu(1).unwrap(); + let two = FeeRate::from_sat_per_kwu(2).unwrap(); + let three = FeeRate::from_sat_per_kwu(3).unwrap(); assert_eq!(three.checked_sub(two).unwrap(), one); let fee_rate = FeeRate::ZERO.checked_sub(one); @@ -282,13 +303,13 @@ mod tests { #[test] fn fee_rate_from_sat_per_vb() { let fee_rate = FeeRate::from_sat_per_vb(10).expect("expected feerate in sat/kwu"); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500).unwrap()); } #[test] fn fee_rate_from_sat_per_kvb() { - let fee_rate = FeeRate::from_sat_per_kvb(11); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2)); + let fee_rate = FeeRate::from_sat_per_kvb(11).unwrap(); + assert_eq!(fee_rate, FeeRate::from_sat_per_mvb(11_000)); } #[test] @@ -300,7 +321,7 @@ mod tests { #[test] fn from_sat_per_vb_u32() { let fee_rate = FeeRate::from_sat_per_vb_u32(10); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500).unwrap()); } #[test] @@ -309,7 +330,7 @@ mod tests { #[test] fn raw_feerate() { - let fee_rate = FeeRate::from_sat_per_kwu(749); + let fee_rate = FeeRate::from_sat_per_kwu(749).unwrap(); assert_eq!(fee_rate.to_sat_per_kwu_floor(), 749); assert_eq!(fee_rate.to_sat_per_vb_floor(), 2); assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3); @@ -317,21 +338,32 @@ mod tests { #[test] fn checked_mul() { - let fee_rate = - FeeRate::from_sat_per_kwu(10).checked_mul(10).expect("expected feerate in sat/kwu"); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100)); + let fee_rate = FeeRate::from_sat_per_kwu(10) + .unwrap() + .checked_mul(10) + .expect("expected feerate in sat/kwu"); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100).unwrap()); - let fee_rate = FeeRate::from_sat_per_kwu(10).checked_mul(u64::MAX); + let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap().checked_mul(u64::MAX); assert!(fee_rate.is_none()); } #[test] fn checked_div() { - let fee_rate = - FeeRate::from_sat_per_kwu(10).checked_div(10).expect("expected feerate in sat/kwu"); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); + let fee_rate = FeeRate::from_sat_per_kwu(10) + .unwrap() + .checked_div(10) + .expect("expected feerate in sat/kwu"); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); - let fee_rate = FeeRate::from_sat_per_kwu(10).checked_div(0); + let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap().checked_div(0); assert!(fee_rate.is_none()); } + + #[test] + fn mvb() { + let fee_rate = FeeRate::from_sat_per_mvb(1_234_567); + let got = fee_rate.to_sat_per_mvb(); + assert_eq!(got, 1_234_567); + } } diff --git a/units/src/fee_rate/serde.rs b/units/src/fee_rate/serde.rs index 473d1ba15c..27750dce6c 100644 --- a/units/src/fee_rate/serde.rs +++ b/units/src/fee_rate/serde.rs @@ -18,7 +18,7 @@ //! //! #[derive(Serialize, Deserialize)] //! pub struct Foo { -//! #[serde(with = "fee_rate::serde::as_sat_per_kwu")] +//! #[serde(with = "fee_rate::serde::as_sat_per_kwu_floor")] //! pub fee_rate: FeeRate, //! } //! ``` @@ -26,7 +26,7 @@ use core::convert::Infallible; use core::fmt; -pub mod as_sat_per_kwu { +pub mod as_sat_per_kwu_floor { //! Serialize and deserialize [`FeeRate`] denominated in satoshis per 1000 weight units. //! //! Use with `#[serde(with = "fee_rate::serde::as_sat_per_kwu")]`. @@ -40,7 +40,8 @@ pub mod as_sat_per_kwu { } pub fn deserialize<'d, D: Deserializer<'d>>(d: D) -> Result { - Ok(FeeRate::from_sat_per_kwu(u64::deserialize(d)?)) + FeeRate::from_sat_per_kwu(u64::deserialize(d)?) + .ok_or_else(|| serde::de::Error::custom("overflowed sats/kwu")) } pub mod opt { diff --git a/units/tests/serde.rs b/units/tests/serde.rs index 4c93da1f0d..ca3b88e89d 100644 --- a/units/tests/serde.rs +++ b/units/tests/serde.rs @@ -37,13 +37,13 @@ struct Serde { vb_floor: FeeRate, #[serde(with = "fee_rate::serde::as_sat_per_vb_ceil")] vb_ceil: FeeRate, - #[serde(with = "fee_rate::serde::as_sat_per_kwu")] + #[serde(with = "fee_rate::serde::as_sat_per_kwu_floor")] kwu: FeeRate, #[serde(with = "fee_rate::serde::as_sat_per_vb_floor::opt")] opt_vb_floor: Option, #[serde(with = "fee_rate::serde::as_sat_per_vb_ceil::opt")] opt_vb_ceil: Option, - #[serde(with = "fee_rate::serde::as_sat_per_kwu::opt")] + #[serde(with = "fee_rate::serde::as_sat_per_kwu_floor::opt")] opt_kwu: Option, a: BlockHeight, From 1bd1e89458fe5ddca8c5c199bd3859a09640c636 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 21 May 2025 11:23:48 +1000 Subject: [PATCH 058/857] Re-introduce FeeRate encapsulate module Now we have the `fee_rate` module clened up re-introduce the `encapsulate` module using MvB. --- units/src/fee_rate/mod.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 87e89c50bd..ceaf239f46 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -11,12 +11,24 @@ use core::ops; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; -/// Fee rate. -/// -/// This is an integer newtype representing fee rate in `sat/kwu`. It provides protection -/// against mixing up the types as well as basic formatting features. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct FeeRate(u64); +mod encapsulate { + /// Fee rate. + /// + /// This is an integer newtype representing fee rate. It provides protection + /// against mixing up the types, conversion functions, and basic formatting. + #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct FeeRate(u64); + + impl FeeRate { + /// Constructs a new [`FeeRate`] from satoshis per 1,000,000 virtual bytes. + pub(crate) const fn from_sat_per_mvb(sat_mvb: u64) -> Self { Self(sat_mvb) } + + /// Converts to sat/MvB. + pub(crate) const fn to_sat_per_mvb(self) -> u64 { self.0 } + } +} +#[doc(inline)] +pub use encapsulate::FeeRate; impl FeeRate { /// 0 sat/kwu. @@ -40,9 +52,6 @@ impl FeeRate { /// Fee rate used to compute dust amount. pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); - /// Constructs a new [`FeeRate`] from satoshis per 1,000,000 virtual bytes. - pub(crate) const fn from_sat_per_mvb(sat_mvb: u64) -> Self { Self(sat_mvb) } - /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. pub const fn from_sat_per_kwu(sat_kwu: u64) -> Option { // No `map()` in const context. @@ -80,9 +89,6 @@ impl FeeRate { } } - /// Converts to sat/MvB. - pub(crate) const fn to_sat_per_mvb(self) -> u64 { self.0 } - /// Converts to sat/kwu rounding down. pub const fn to_sat_per_kwu_floor(self) -> u64 { self.to_sat_per_mvb() / 4_000 } From 9b2fc021b21c44828e362b99fedf5654b2eeb785 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 May 2025 14:49:58 +1000 Subject: [PATCH 059/857] Improve rustdocs on FeeRate Remove the unit from associated consts and then make all the rustdocs on the various consts use 'The'. --- units/src/fee_rate/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index ceaf239f46..c2ee6f4b91 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -31,25 +31,25 @@ mod encapsulate { pub use encapsulate::FeeRate; impl FeeRate { - /// 0 sat/kwu. + /// The zero fee rate. /// /// Equivalent to [`MIN`](Self::MIN), may better express intent in some contexts. pub const ZERO: FeeRate = FeeRate::from_sat_per_mvb(0); - /// Minimum possible value (0 sat/kwu). + /// The minimum possible value. /// /// Equivalent to [`ZERO`](Self::ZERO), may better express intent in some contexts. pub const MIN: FeeRate = FeeRate::ZERO; - /// Maximum possible value. + /// The maximum possible value. pub const MAX: FeeRate = FeeRate::from_sat_per_mvb(u64::MAX); - /// Minimum fee rate required to broadcast a transaction. + /// The minimum fee rate required to broadcast a transaction. /// /// The value matches the default Bitcoin Core policy at the time of library release. pub const BROADCAST_MIN: FeeRate = FeeRate::from_sat_per_vb_u32(1); - /// Fee rate used to compute dust amount. + /// The fee rate used to compute dust amount. pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. From b65860067f7da1f4e665eb14d77adc6db9a3ba59 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 May 2025 15:23:44 +1000 Subject: [PATCH 060/857] Make fee functions const We temporarily removed `const` in the `fee` module to make patching and reviewing easier. Now add it back in. --- units/src/fee.rs | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 73b4919aa9..f8a6933513 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -56,16 +56,21 @@ impl Amount { /// # Ok::<_, amount::OutOfRangeError>(()) /// ``` #[must_use] - pub fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { + pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { let wu = weight.to_wu(); if wu == 0 { return None; } - let sats = self.to_sat() * 1_000; // Because we use per/kwu. - let fee_rate = (sats + wu - 1) / wu; - - FeeRate::from_sat_per_kwu(fee_rate) + // Mul by 1,000 because we use per/kwu. + if let Some(sats) = self.to_sat().checked_mul(1_000) { + // No need to used checked arithmetic because wu is non-zero. + if let Some(bump) = sats.checked_add(wu - 1) { + let fee_rate = bump / wu; + return FeeRate::from_sat_per_kwu(fee_rate); + } + } + None } /// Checked fee rate floor division. @@ -76,7 +81,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] - pub fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { + pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { match self.to_sat().checked_mul(1000) { Some(amount_msats) => match amount_msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { Some(wu) => Some(Weight::from_wu(wu)), @@ -93,7 +98,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] - pub fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { + pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { // Use ceil because result is used as the divisor. let rate = fee_rate.to_sat_per_kwu_ceil(); match self.to_sat().checked_mul(1000) { @@ -122,8 +127,12 @@ impl FeeRate { /// If the calculation would overflow we saturate to [`Amount::MAX`]. Since such a fee can never /// be paid this is meaningful as an error case while still removing the possibility of silently /// wrapping. - pub fn to_fee(self, weight: Weight) -> Amount { - self.checked_mul_by_weight(weight).unwrap_or(Amount::MAX) + pub const fn to_fee(self, weight: Weight) -> Amount { + // No `unwrap_or()` in const context. + match self.checked_mul_by_weight(weight) { + Some(fee) => fee, + None => Amount::MAX, + } } /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`] @@ -150,13 +159,18 @@ impl FeeRate { /// enough instead of falling short if rounded down. /// /// Returns [`None`] if overflow occurred. - pub fn checked_mul_by_weight(self, weight: Weight) -> Option { + pub const fn checked_mul_by_weight(self, weight: Weight) -> Option { let wu = weight.to_wu(); - let fee_kwu = self.to_sat_per_kwu_floor().checked_mul(wu)?; - let bump = fee_kwu.checked_add(999)?; // We do ceil division. - let fee = bump / 1_000; - - Amount::from_sat(fee).ok() + if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { + // Bump by 999 to do ceil division using kwu. + if let Some(bump) = fee_kwu.checked_add(999) { + let fee = bump / 1_000; + if let Ok(fee_amount) = Amount::from_sat(fee) { + return Some(fee_amount); + } + } + } + None } } @@ -332,7 +346,7 @@ impl Weight { /// enough instead of falling short if rounded down. /// /// Returns [`None`] if overflow occurred. - pub fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { + pub const fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { fee_rate.checked_mul_by_weight(self) } } From bf0776e3dd8f457ec5c4b368d05ffb09d2cda20d Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 May 2025 07:37:51 +0100 Subject: [PATCH 061/857] Remove panic using checked arithmetic During dev I introduced a pancic, remove it. --- units/src/fee.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index f8a6933513..63a75cbfb2 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -31,10 +31,14 @@ impl Amount { return None; } - let sats = self.to_sat() * 1_000; // Because we use per/kwu. - let fee_rate = sats / wu; - - FeeRate::from_sat_per_kwu(fee_rate) + // Mul by 1,000 because we use per/kwu. + match self.to_sat().checked_mul(1_000) { + Some(sats) => { + let fee_rate = sats / wu; + FeeRate::from_sat_per_kwu(fee_rate) + } + None => None, + } } /// Checked weight ceiling division. From 7c186e6081fbc6af1b7907cc06e769e3b174be69 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 May 2025 07:45:20 +0100 Subject: [PATCH 062/857] Refactor fee functions The `fee` functions are a bit convoluted because of the usage of `const`. Refactor a couple of them to be easier to read. Internal change only. --- units/src/fee.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 63a75cbfb2..09bccb7414 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -86,13 +86,12 @@ impl Amount { /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { - match self.to_sat().checked_mul(1000) { - Some(amount_msats) => match amount_msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { - Some(wu) => Some(Weight::from_wu(wu)), - None => None, - }, - None => None, + if let Some(msats) = self.to_sat().checked_mul(1000) { + if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { + return Some(Weight::from_wu(wu)); + } } + None } /// Checked fee rate ceiling division. @@ -105,19 +104,18 @@ impl Amount { pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { // Use ceil because result is used as the divisor. let rate = fee_rate.to_sat_per_kwu_ceil(); - match self.to_sat().checked_mul(1000) { - Some(amount_msats) => match rate.checked_sub(1) { - Some(rate_minus_one) => match amount_msats.checked_add(rate_minus_one) { - Some(rounded_msats) => match rounded_msats.checked_div(rate) { - Some(wu) => Some(Weight::from_wu(wu)), - None => None, - }, - None => None, - }, - None => None, - }, - None => None, + if rate == 0 { + return None; } + + if let Some(msats) = self.to_sat().checked_mul(1000) { + // No need to used checked arithmetic because rate is non-zero. + if let Some(bump) = msats.checked_add(rate - 1) { + let wu = bump / rate; + return Some(Weight::from_wu(wu)); + } + } + None } } From 8cf1dc39b59cc6a6e98fdd50029e1b721536b66d Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 May 2025 15:30:54 +1000 Subject: [PATCH 063/857] Fix incorrect code comment --- bitcoin/src/blockdata/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 4fcff528cd..fc88001b1b 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1690,7 +1690,7 @@ mod tests { let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap(); let effective_value = effective_value(fee_rate, InputWeightPrediction::P2WPKH_MAX, value); - // 10 sat/kwu * 272 wu = 4 sats (rounding up) + // 10 sat/kwu * 272 wu = 3 sats (rounding up) let expected_fee = "3 sats".parse::().unwrap(); let expected_effective_value = (value.to_signed() - expected_fee).unwrap(); assert_eq!(effective_value, expected_effective_value); From 56516757ad8874d8121dba468946546bb8fd7d4e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 29 May 2025 05:08:34 +0100 Subject: [PATCH 064/857] Add code comment to amount calculation Its not immediately obvious that x - y cannot overflow. Add a code comment to explain it. --- bitcoin/src/blockdata/transaction.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index fc88001b1b..6182308f59 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -784,6 +784,8 @@ pub fn effective_value( let weight = input_weight_prediction.total_weight(); let fee = fee_rate.to_fee(weight); + // Cannot overflow because after conversion to signed Amount::MIN - Amount::MAX + // still fits in SignedAmount::MAX (0 - MAX = -MAX). (value.to_signed() - fee.to_signed()).expect("cannot overflow") } From 200c27631521ad139e2070a04c1cf223791a1277 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 15 May 2025 09:34:52 +1000 Subject: [PATCH 065/857] bitcoin: Make test code spacing uniform Make test code use uniform spacing - twitch averted. Whitespace only, no logic change. --- bitcoin/tests/serde.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index a0842e2b89..3d2b4a28ac 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -47,6 +47,7 @@ fn serde_regression_block() { "data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw" ); let block: Block = deserialize(segwit).unwrap(); + let got = serialize(&block).unwrap(); let want = include_bytes!("data/serde/block_bincode"); assert_eq!(got, want) @@ -55,6 +56,7 @@ fn serde_regression_block() { #[test] fn serde_regression_absolute_lock_time_height() { let t = absolute::LockTime::from_height(741521).expect("valid height"); + let got = serialize(&t).unwrap(); let want = include_bytes!("data/serde/absolute_lock_time_blocks_bincode") as &[_]; assert_eq!(got, want); @@ -64,8 +66,8 @@ fn serde_regression_absolute_lock_time_height() { fn serde_regression_absolute_lock_time_time() { let seconds: u32 = 1653195600; // May 22nd, 5am UTC. let t = absolute::LockTime::from_mtp(seconds).expect("valid time"); - let got = serialize(&t).unwrap(); + let got = serialize(&t).unwrap(); let want = include_bytes!("data/serde/absolute_lock_time_seconds_bincode") as &[_]; assert_eq!(got, want); } @@ -73,8 +75,8 @@ fn serde_regression_absolute_lock_time_time() { #[test] fn serde_regression_relative_lock_time_height() { let t = relative::LockTime::from(relative::Height::from(0xCAFE_u16)); - let got = serialize(&t).unwrap(); + let got = serialize(&t).unwrap(); let want = include_bytes!("data/serde/relative_lock_time_blocks_bincode") as &[_]; assert_eq!(got, want); } @@ -82,8 +84,8 @@ fn serde_regression_relative_lock_time_height() { #[test] fn serde_regression_relative_lock_time_time() { let t = relative::LockTime::from(relative::Time::from_512_second_intervals(0xFACE_u16)); - let got = serialize(&t).unwrap(); + let got = serialize(&t).unwrap(); let want = include_bytes!("data/serde/relative_lock_time_seconds_bincode") as &[_]; assert_eq!(got, want); } @@ -91,6 +93,7 @@ fn serde_regression_relative_lock_time_time() { #[test] fn serde_regression_script() { let script = ScriptBuf::from(vec![0u8, 1u8, 2u8]); + let got = serialize(&script).unwrap(); let want = include_bytes!("data/serde/script_bincode") as &[_]; assert_eq!(got, want) @@ -109,6 +112,7 @@ fn serde_regression_txin() { #[test] fn serde_regression_txout() { let txout = TxOut { value: Amount::MAX, script_pubkey: ScriptBuf::from(vec![0u8, 1u8, 2u8]) }; + let got = serialize(&txout).unwrap(); let want = include_bytes!("data/serde/txout_bincode") as &[_]; assert_eq!(got, want) @@ -118,6 +122,7 @@ fn serde_regression_txout() { fn serde_regression_transaction() { let ser = include_bytes!("data/serde/transaction_ser"); let tx: Transaction = deserialize(ser).unwrap(); + let got = serialize(&tx).unwrap(); let want = include_bytes!("data/serde/transaction_bincode") as &[_]; assert_eq!(got, want) @@ -151,6 +156,7 @@ fn serde_regression_address() { fn serde_regression_extended_priv_key() { let s = include_str!("data/serde/extended_priv_key"); let key = s.trim().parse::().unwrap(); + let got = serialize(&key).unwrap(); let want = include_bytes!("data/serde/extended_priv_key_bincode") as &[_]; assert_eq!(got, want) @@ -160,6 +166,7 @@ fn serde_regression_extended_priv_key() { fn serde_regression_extended_pub_key() { let s = include_str!("data/serde/extended_pub_key"); let key = s.trim().parse::().unwrap(); + let got = serialize(&key).unwrap(); let want = include_bytes!("data/serde/extended_pub_key_bincode") as &[_]; assert_eq!(got, want) @@ -182,8 +189,8 @@ fn serde_regression_ecdsa_sig() { fn serde_regression_control_block() { let s = include_str!("data/serde/control_block_hex"); let block = ControlBlock::decode(&Vec::::from_hex(s.trim()).unwrap()).unwrap(); - let got = serialize(&block).unwrap(); + let got = serialize(&block).unwrap(); let want = include_bytes!("data/serde/control_block_bincode") as &[_]; assert_eq!(got, want) } @@ -191,6 +198,7 @@ fn serde_regression_control_block() { #[test] fn serde_regression_child_number() { let num = ChildNumber::Normal { index: 0xDEADBEEF }; + let got = serialize(&num).unwrap(); let want = include_bytes!("data/serde/child_number_bincode") as &[_]; assert_eq!(got, want) @@ -199,6 +207,7 @@ fn serde_regression_child_number() { #[test] fn serde_regression_private_key() { let sk = PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap(); + let got = serialize(&sk).unwrap(); let want = include_bytes!("data/serde/private_key_bincode") as &[_]; assert_eq!(got, want) @@ -208,6 +217,7 @@ fn serde_regression_private_key() { fn serde_regression_public_key() { let s = include_str!("data/serde/public_key_hex"); let pk = s.trim().parse::().unwrap(); + let got = serialize(&pk).unwrap(); let want = include_bytes!("data/serde/public_key_bincode") as &[_]; assert_eq!(got, want) @@ -368,6 +378,7 @@ fn le_bytes() -> [u8; 32] { #[test] fn serde_regression_work() { let work = Work::from_le_bytes(le_bytes()); + let got = serialize(&work).unwrap(); let want = include_bytes!("data/serde/u256_bincode") as &[_]; assert_eq!(got, want) @@ -376,6 +387,7 @@ fn serde_regression_work() { #[test] fn serde_regression_target() { let target = Target::from_le_bytes(le_bytes()); + let got = serialize(&target).unwrap(); let want = include_bytes!("data/serde/u256_bincode") as &[_]; assert_eq!(got, want) From 4621d2bde14d71b3d6ef0b14258a7479c049ba3b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 15 May 2025 09:40:15 +1000 Subject: [PATCH 066/857] Modify locktime serde implemenations The `units::locktime` types are used for two things: - They are the inner types of `primitives` `LockTime`s - They are used ephemerally for checking satisfaction Neither of these use cases requires `serde` impls for the `units` types. Since we are trying to release 1.0 with minimal amounts of code we should remove them. For `LockTime`s that need to be stored on disk or go over the wire we can manually implement the `serde` traits. For `absolute::LockTime` this is done already and there is no reason the `relative::LockTime` impl cannot be the same [0]. This differs from the current `serde` trait impls but we have already decided that in 0.33 we are going to accept breakage and direct users to use 0.32 to handle it. - Remove `serde` stuff from `units::locktime` - Manually implement `serde` traits on `relative::LockTime` - Fix the regression test to use the new format While we are at it use a uniform terse call in `serialize`. [0] This is because there is an unambiguous encoding for the whole set of locktimes - consensus encoding. --- .../serde/relative_lock_time_blocks_bincode | Bin 6 -> 4 bytes .../serde/relative_lock_time_seconds_bincode | Bin 6 -> 4 bytes primitives/src/locktime/absolute.rs | 23 +------ primitives/src/locktime/relative.rs | 22 +++++- units/src/locktime/absolute.rs | 60 ---------------- units/src/locktime/relative.rs | 65 ------------------ units/tests/data/serde_bincode | Bin 147 -> 135 bytes units/tests/serde.rs | 17 +---- 8 files changed, 26 insertions(+), 161 deletions(-) diff --git a/bitcoin/tests/data/serde/relative_lock_time_blocks_bincode b/bitcoin/tests/data/serde/relative_lock_time_blocks_bincode index 4eb84bb45911c09de9bdc6e7ff57f8fa89090a80..167e25d50c5f161edba7ac04d8bdedd9a8f61a27 100644 GIT binary patch literal 4 Lcmex&ih%(D23i5h literal 6 NcmZQzU|{%n3IGDk0m%RW diff --git a/bitcoin/tests/data/serde/relative_lock_time_seconds_bincode b/bitcoin/tests/data/serde/relative_lock_time_seconds_bincode index b6ed9a62a79422b1e6555e84e8d0a8830abcccae..53442e8bb233bb74ea6fd91e7e5e509de6864ef3 100644 GIT binary patch literal 4 LcmX^2%Ygv^2C4!H literal 6 NcmZQ%U|=}+3jhM50m=XX diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs index 808ff6c634..53225df3e7 100644 --- a/primitives/src/locktime/absolute.rs +++ b/primitives/src/locktime/absolute.rs @@ -413,7 +413,7 @@ impl serde::Serialize for LockTime { where S: serde::Serializer, { - serializer.serialize_u32(self.to_consensus_u32()) + self.to_consensus_u32().serialize(serializer) } } @@ -423,26 +423,7 @@ impl<'de> serde::Deserialize<'de> for LockTime { where D: serde::Deserializer<'de>, { - struct Visitor; - impl serde::de::Visitor<'_> for Visitor { - type Value = u32; - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("a u32") } - // We cannot just implement visit_u32 because JSON (among other things) always - // calls visit_u64, even when called from Deserializer::deserialize_u32. The - // other visit_u*s have default implementations that forward to visit_u64. - fn visit_u64(self, v: u64) -> Result { - v.try_into().map_err(|_| { - E::invalid_value(serde::de::Unexpected::Unsigned(v), &"a 32-bit number") - }) - } - // Also do the signed version, just for good measure. - fn visit_i64(self, v: i64) -> Result { - v.try_into().map_err(|_| { - E::invalid_value(serde::de::Unexpected::Signed(v), &"a 32-bit number") - }) - } - } - deserializer.deserialize_u32(Visitor).map(LockTime::from_consensus) + u32::deserialize(deserializer).map(Self::from_consensus) } } diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index fd58ff1db2..5bb2dc1ab9 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -42,7 +42,6 @@ pub type Time = NumberOf512Seconds; /// * [BIP 68 Relative lock-time using consensus-enforced sequence numbers](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) /// * [BIP 112 CHECKSEQUENCEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum LockTime { /// A block height lock time value. Blocks(NumberOfBlocks), @@ -372,6 +371,27 @@ impl From for Sequence { fn from(lt: LockTime) -> Sequence { lt.to_sequence() } } +#[cfg(feature = "serde")] +impl serde::Serialize for LockTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_consensus_u32().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for LockTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + u32::deserialize(deserializer) + .and_then(|n| Self::from_consensus(n).map_err(serde::de::Error::custom)) + } +} + /// Error returned when a sequence number is parsed as a lock time, but its /// "disable" flag is set. #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index c0e2b84171..1787ea089f 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -122,27 +122,6 @@ impl From for ParseHeightError { fn from(value: ParseError) -> Self { Self(value) } } -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Height { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let u = u32::deserialize(deserializer)?; - Height::from_u32(u).map_err(serde::de::Error::custom) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Height { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.to_u32().serialize(serializer) - } -} - #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")] #[doc(hidden)] pub type Time = MedianTimePast; @@ -248,27 +227,6 @@ impl fmt::Display for MedianTimePast { crate::impl_parse_str!(MedianTimePast, ParseTimeError, parser(MedianTimePast::from_u32)); -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for MedianTimePast { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let u = u32::deserialize(deserializer)?; - MedianTimePast::from_u32(u).map_err(serde::de::Error::custom) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for MedianTimePast { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.to_u32().serialize(serializer) - } -} - /// Error returned when parsing block time fails. #[derive(Debug, Clone, Eq, PartialEq)] pub struct ParseTimeError(ParseError); @@ -500,9 +458,6 @@ impl<'a> Arbitrary<'a> for MedianTimePast { #[cfg(test)] mod tests { - #[cfg(feature = "serde")] - use internals::serde_round_trip; - use super::*; #[test] @@ -554,21 +509,6 @@ mod tests { assert!(is_block_time(500_000_000)); } - #[test] - #[cfg(feature = "serde")] - pub fn encode_decode_height() { - serde_round_trip!(Height::ZERO); - serde_round_trip!(Height::MIN); - serde_round_trip!(Height::MAX); - } - - #[test] - #[cfg(feature = "serde")] - pub fn encode_decode_time() { - serde_round_trip!(MedianTimePast::MIN); - serde_round_trip!(MedianTimePast::MAX); - } - #[test] #[cfg(feature = "alloc")] fn locktime_unit_display() { diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 8aa218db9f..f3dfba28a8 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -7,8 +7,6 @@ use core::fmt; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] #[doc(hidden)] @@ -89,28 +87,6 @@ impl fmt::Display for NumberOfBlocks { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } -#[cfg(feature = "serde")] -impl Serialize for NumberOfBlocks { - #[inline] - fn serialize(&self, s: S) -> Result - where - S: Serializer, - { - u16::serialize(&self.to_height(), s) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for NumberOfBlocks { - #[inline] - fn deserialize(d: D) -> Result - where - D: Deserializer<'de>, - { - Ok(Self::from_height(u16::deserialize(d)?)) - } -} - #[deprecated(since = "TBD", note = "use `NumberOf512Seconds` instead")] #[doc(hidden)] pub type Time = NumberOf512Seconds; @@ -227,28 +203,6 @@ impl fmt::Display for NumberOf512Seconds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } -#[cfg(feature = "serde")] -impl Serialize for NumberOf512Seconds { - #[inline] - fn serialize(&self, s: S) -> Result - where - S: Serializer, - { - u16::serialize(&self.to_512_second_intervals(), s) - } -} - -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for NumberOf512Seconds { - #[inline] - fn deserialize(d: D) -> Result - where - D: Deserializer<'de>, - { - Ok(Self::from_512_second_intervals(u16::deserialize(d)?)) - } -} - /// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval. #[derive(Debug, Clone, PartialEq, Eq)] pub struct TimeOverflowError { @@ -348,9 +302,6 @@ impl<'a> Arbitrary<'a> for NumberOf512Seconds { #[cfg(test)] mod tests { - #[cfg(feature = "serde")] - use internals::serde_round_trip; - use super::*; use crate::BlockTime; @@ -416,22 +367,6 @@ mod tests { assert!(result.is_err()); } - #[test] - #[cfg(feature = "serde")] - pub fn encode_decode_height() { - serde_round_trip!(NumberOfBlocks::ZERO); - serde_round_trip!(NumberOfBlocks::MIN); - serde_round_trip!(NumberOfBlocks::MAX); - } - - #[test] - #[cfg(feature = "serde")] - pub fn encode_decode_time() { - serde_round_trip!(NumberOf512Seconds::ZERO); - serde_round_trip!(NumberOf512Seconds::MIN); - serde_round_trip!(NumberOf512Seconds::MAX); - } - fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] { let mut timestamps = [BlockTime::from_u32(0); 11]; for (i, ts) in timestamps.iter_mut().enumerate() { diff --git a/units/tests/data/serde_bincode b/units/tests/data/serde_bincode index 51d7dc1d09ea388238a66e571ba6b609e2685997..556b15cd794bd56e1ef82aa1bd0f4bf3642fd607 100644 GIT binary patch delta 14 RcmbQt*v>eif&D)O001<=2`vBs delta 26 UcmZo?oXj|(K{(~C?0+->0MlO+egFUf diff --git a/units/tests/serde.rs b/units/tests/serde.rs index 4c93da1f0d..dd894aeaaa 100644 --- a/units/tests/serde.rs +++ b/units/tests/serde.rs @@ -6,10 +6,7 @@ #![cfg(feature = "serde")] use bincode::serialize; -use bitcoin_units::locktime::{absolute, relative}; -use bitcoin_units::{ - amount, fee_rate, Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight, -}; +use bitcoin_units::{amount, fee_rate, Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight}; use serde::{Deserialize, Serialize}; /// A struct that includes all the types that implement or support `serde` traits. @@ -48,11 +45,7 @@ struct Serde { a: BlockHeight, b: BlockInterval, - c: absolute::Height, - d: absolute::MedianTimePast, - e: relative::Height, - f: relative::Time, - g: Weight, + c: Weight, } impl Serde { @@ -81,11 +74,7 @@ impl Serde { a: BlockHeight::MAX, b: BlockInterval::MAX, - c: absolute::Height::MAX, - d: absolute::MedianTimePast::MAX, - e: relative::Height::MAX, - f: relative::Time::MAX, - g: Weight::MAX, + c: Weight::MAX, } } } From 76dd6100a27c2fcc4d0ae94d689eb6bf06a9ad61 Mon Sep 17 00:00:00 2001 From: jamillambert Date: Tue, 3 Jun 2025 10:58:54 +0100 Subject: [PATCH 067/857] Split derivation path test into valid and invalid Make the tests separate to make tests smaller and easier to read. There are no logic changes. --- bitcoin/src/bip32.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 22ed79d7a0..8854e28d55 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1098,7 +1098,7 @@ mod tests { use super::*; #[test] - fn parse_derivation_path() { + fn parse_derivation_path_invalid() { assert!(matches!( "n/0'/0".parse::(), Err(ParseChildNumberError::ParseInt(..)), @@ -1119,7 +1119,10 @@ mod tests { "2147483648".parse::(), Err(ParseChildNumberError::IndexOutOfRange(IndexOutOfRangeError { index: 2147483648 })), ); + } + #[test] + fn parse_derivation_path_valid() { assert_eq!(DerivationPath::master(), "".parse::().unwrap()); assert_eq!(DerivationPath::master(), DerivationPath::default()); From 015fb1be3b74c406ed7b7ff158634f4e6fa6dcef Mon Sep 17 00:00:00 2001 From: jamillambert Date: Tue, 3 Jun 2025 11:11:29 +0100 Subject: [PATCH 068/857] Split invalid derivation path test The test tests two sperate things. Split the test into invalid path and out of range. --- bitcoin/src/bip32.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 8854e28d55..316419ed34 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1098,7 +1098,7 @@ mod tests { use super::*; #[test] - fn parse_derivation_path_invalid() { + fn parse_derivation_path_invalid_format() { assert!(matches!( "n/0'/0".parse::(), Err(ParseChildNumberError::ParseInt(..)), @@ -1115,6 +1115,10 @@ mod tests { "0h/0x".parse::(), Err(ParseChildNumberError::ParseInt(..)), )); + } + + #[test] + fn parse_derivation_path_out_of_range() { assert_eq!( "2147483648".parse::(), Err(ParseChildNumberError::IndexOutOfRange(IndexOutOfRangeError { index: 2147483648 })), From ed36a980f8270db77fd8226037889328a74e1eae Mon Sep 17 00:00:00 2001 From: jamillambert Date: Tue, 3 Jun 2025 11:13:53 +0100 Subject: [PATCH 069/857] Refactor invalid derivation path tests Refactor the tests to have the invalid paths in a list, or string. --- bitcoin/src/bip32.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 316419ed34..61aacbd3e2 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1099,28 +1099,25 @@ mod tests { #[test] fn parse_derivation_path_invalid_format() { - assert!(matches!( - "n/0'/0".parse::(), - Err(ParseChildNumberError::ParseInt(..)), - )); - assert!(matches!( - "4/m/5".parse::(), - Err(ParseChildNumberError::ParseInt(..)), - )); - assert!(matches!( - "//3/0'".parse::(), - Err(ParseChildNumberError::ParseInt(..)), - )); - assert!(matches!( - "0h/0x".parse::(), - Err(ParseChildNumberError::ParseInt(..)), - )); + let invalid_paths = [ + "n/0'/0", + "4/m/5", + "//3/0'", + "0h/0x", + ]; + for path in &invalid_paths { + assert!(matches!( + path.parse::(), + Err(ParseChildNumberError::ParseInt(..)), + )); + } } #[test] fn parse_derivation_path_out_of_range() { + let invalid_path = "2147483648"; assert_eq!( - "2147483648".parse::(), + invalid_path.parse::(), Err(ParseChildNumberError::IndexOutOfRange(IndexOutOfRangeError { index: 2147483648 })), ); } From 3e7fdad5fd542a8c959039d36a6b09d541982d89 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 3 Jun 2025 11:36:01 +0100 Subject: [PATCH 070/857] Split empty master test out The valid derivation test is doing a whole bunch of things. Split out the empty master path assertions into a separate test. --- bitcoin/src/bip32.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 61aacbd3e2..75d460edc6 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1123,15 +1123,20 @@ mod tests { } #[test] - fn parse_derivation_path_valid() { + fn parse_derivation_path_valid_empty_master() { + // Sanity checks. + assert_eq!(DerivationPath::master(), DerivationPath(vec![])); assert_eq!(DerivationPath::master(), "".parse::().unwrap()); assert_eq!(DerivationPath::master(), DerivationPath::default()); - // Acceptable forms for a master path. + // Empty is the same as with an `m`. + assert_eq!("".parse::().unwrap(), DerivationPath(vec![])); assert_eq!("m".parse::().unwrap(), DerivationPath(vec![])); assert_eq!("m/".parse::().unwrap(), DerivationPath(vec![])); - assert_eq!("".parse::().unwrap(), DerivationPath(vec![])); + } + #[test] + fn parse_derivation_path_valid() { assert_eq!("0'".parse::(), Ok(vec![ChildNumber::ZERO_HARDENED].into())); assert_eq!( "0'/1".parse::(), From c5073f4c513636d4feff217986853d6b296524d4 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 3 Jun 2025 11:51:48 +0100 Subject: [PATCH 071/857] Refactor simple valid path tests into a loop The test is still doing a bunch of stuff. Pull the simple test cases into a loop. --- bitcoin/src/bip32.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 75d460edc6..e5e1af62a1 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1137,30 +1137,25 @@ mod tests { #[test] fn parse_derivation_path_valid() { - assert_eq!("0'".parse::(), Ok(vec![ChildNumber::ZERO_HARDENED].into())); - assert_eq!( - "0'/1".parse::(), - Ok(vec![ChildNumber::ZERO_HARDENED, ChildNumber::ONE_NORMAL].into()) - ); - assert_eq!( - "0h/1/2'".parse::(), - Ok(vec![ + let valid_paths = [ + ("0'", vec![ChildNumber::ZERO_HARDENED]), + ("0'/1", vec![ChildNumber::ZERO_HARDENED, ChildNumber::ONE_NORMAL]), + ("0h/1/2'", vec![ ChildNumber::ZERO_HARDENED, ChildNumber::ONE_NORMAL, ChildNumber::from_hardened_idx(2).unwrap(), - ] - .into()) - ); - assert_eq!( - "0'/1/2h/2".parse::(), - Ok(vec![ + ]), + ("0'/1/2h/2", vec![ ChildNumber::ZERO_HARDENED, ChildNumber::ONE_NORMAL, ChildNumber::from_hardened_idx(2).unwrap(), ChildNumber::from_normal_idx(2).unwrap(), - ] - .into()) - ); + ]), + ]; + for (path, expected) in valid_paths { + assert_eq!(path.parse::().unwrap(), expected.into()); + } + let want = DerivationPath::from(vec![ ChildNumber::ZERO_HARDENED, ChildNumber::ONE_NORMAL, From 0c9dd31f53fe1b695bcd8322b2fee67cd3bff61f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 3 Jun 2025 11:55:14 +0100 Subject: [PATCH 072/857] Test with m prefix We have a single test case that tests for the m prefix while all the others do not. Move one test case into the loop and then test on each iteration the path with m prefix added. --- bitcoin/src/bip32.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index e5e1af62a1..cce4c999fc 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1151,21 +1151,22 @@ mod tests { ChildNumber::from_hardened_idx(2).unwrap(), ChildNumber::from_normal_idx(2).unwrap(), ]), + ("0'/1/2'/2/1000000000", vec![ + ChildNumber::ZERO_HARDENED, + ChildNumber::ONE_NORMAL, + ChildNumber::from_hardened_idx(2).unwrap(), + ChildNumber::from_normal_idx(2).unwrap(), + ChildNumber::from_normal_idx(1000000000).unwrap(), + ]), ]; for (path, expected) in valid_paths { - assert_eq!(path.parse::().unwrap(), expected.into()); + // Access the inner private field so we don't have to clone expected. + assert_eq!(path.parse::().unwrap().0, expected); + // Test with the leading `m` for good measure. + let prefixed = format!("m/{}", path); + assert_eq!(prefixed.parse::().unwrap().0, expected); } - let want = DerivationPath::from(vec![ - ChildNumber::ZERO_HARDENED, - ChildNumber::ONE_NORMAL, - ChildNumber::from_hardened_idx(2).unwrap(), - ChildNumber::from_normal_idx(2).unwrap(), - ChildNumber::from_normal_idx(1000000000).unwrap(), - ]); - assert_eq!("0'/1/2'/2/1000000000".parse::().unwrap(), want); - assert_eq!("m/0'/1/2'/2/1000000000".parse::().unwrap(), want); - let s = "0'/50/3'/5/545456"; assert_eq!(s.parse::(), s.into_derivation_path()); assert_eq!(s.parse::(), s.to_string().into_derivation_path()); From dd3f3e44bc3329830aacacb252162c57858b0029 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 3 Jun 2025 12:05:03 +0100 Subject: [PATCH 073/857] Split into_derivation_path tests out The test _still_ tests multiple things. Move the `into_derivation_path` calls into a separate test. --- bitcoin/src/bip32.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index cce4c999fc..3e7aae74a5 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1166,7 +1166,10 @@ mod tests { let prefixed = format!("m/{}", path); assert_eq!(prefixed.parse::().unwrap().0, expected); } + } + #[test] + fn parse_derivation_path_same_as_into_derivation_path() { let s = "0'/50/3'/5/545456"; assert_eq!(s.parse::(), s.into_derivation_path()); assert_eq!(s.parse::(), s.to_string().into_derivation_path()); From a1e8fabbbe26cbe62e1a966cc0c760407bfb063f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 Jun 2025 07:36:52 +0100 Subject: [PATCH 074/857] Remove unnecessary closure We can just pass the function directly. Found by clippy bizarrely after running `rustfmt` (in bot-created PR #4586). Internal change only, no logic change. --- bitcoin/src/psbt/serialize.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 270f8a75e5..01b5dc9580 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -187,9 +187,7 @@ impl Serialize for Vec { impl Deserialize for Vec { fn deserialize(bytes: &[u8]) -> Result { bytes.chunks(secp256k1::constants::PUBLIC_KEY_SIZE) - .map(|pubkey_bytes| { - secp256k1::PublicKey::deserialize(pubkey_bytes) - }) + .map(secp256k1::PublicKey::deserialize) .collect() } } From 3dd538d04bad6e07b04cd8c2b3fb14d09625389f Mon Sep 17 00:00:00 2001 From: findmyhappy Date: Wed, 4 Jun 2025 11:58:46 +0800 Subject: [PATCH 075/857] chore: add missing backticks Signed-off-by: findmyhappy --- primitives/tests/api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/tests/api.rs b/primitives/tests/api.rs index b03a7611b1..f020acf27c 100644 --- a/primitives/tests/api.rs +++ b/primitives/tests/api.rs @@ -63,7 +63,7 @@ static SCRIPT: ScriptBuf = ScriptBuf::new(); static BYTES: [u8; 32] = [0x00; 32]; /// Public structs that derive common traits. -// C-COMMON-TRAITS excluding `Debug, Default, Display, Ord, PartialOrd, Hash`. +// C-COMMON-TRAITS excluding `Debug`, `Default`, `Display`, `Ord`, `PartialOrd, `Hash`. #[derive(Clone, PartialEq, Eq)] struct CommonTraits { a: block::Block, @@ -120,7 +120,7 @@ struct Clone<'a> { } /// Public structs that derive common traits. -// C-COMMON-TRAITS excluding `Clone`, `Debug, `Default`, and `Display` +// C-COMMON-TRAITS excluding `Clone`, `Debug`, `Default`, and `Display` #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] struct Ord { // a: block::Block, From e9f7ae4b74a4d2728b4b64bbb8fc2db92fefec3a Mon Sep 17 00:00:00 2001 From: David Klank <155117116+davidjsonn@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:09:34 +0300 Subject: [PATCH 076/857] Correct hash algorithm name in RIPEMD160 documentation --- hashes/src/ripemd160/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashes/src/ripemd160/mod.rs b/hashes/src/ripemd160/mod.rs index 36f2b24169..2617838763 100644 --- a/hashes/src/ripemd160/mod.rs +++ b/hashes/src/ripemd160/mod.rs @@ -62,7 +62,7 @@ pub struct HashEngine { } impl HashEngine { - /// Constructs a new SHA256 hash engine. + /// Constructs a new RIPEMD160 hash engine. pub const fn new() -> Self { Self { h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], From 2fa5c062d5e07580bdb7ea5e4c58e4607c716ecc Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Wed, 4 Jun 2025 17:34:15 +0100 Subject: [PATCH 077/857] Add is_satisfied_by locktime tests Weekly mutation testing found new mutants in both height and median time past `is_satisfied_by` functions. Test these two functions and kill the mutants. --- units/src/locktime/absolute.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index c0e2b84171..0c202c915c 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -607,4 +607,34 @@ mod tests { timestamps.reverse(); assert_eq!(MedianTimePast::new(timestamps).unwrap().to_u32(), 500_000_005); } + + #[test] + fn height_is_satisfied_by() { + let chain_tip = Height::from_u32(100).unwrap(); + + // lock is satisfied if transaction can go in the next block (height <= chain_tip + 1). + let locktime = Height::from_u32(100).unwrap(); + assert!(locktime.is_satisfied_by(chain_tip)); + let locktime = Height::from_u32(101).unwrap(); + assert!(locktime.is_satisfied_by(chain_tip)); + + // It is not satisfied if the lock height is after the next block. + let locktime = Height::from_u32(102).unwrap(); + assert!(!locktime.is_satisfied_by(chain_tip)); + } + + #[test] + fn median_time_past_is_satisfied_by() { + let mtp = MedianTimePast::from_u32(500_000_001).unwrap(); + + // lock is satisfied if transaction can go in the next block (locktime <= mtp). + let locktime = MedianTimePast::from_u32(500_000_000).unwrap(); + assert!(locktime.is_satisfied_by(mtp)); + let locktime = MedianTimePast::from_u32(500_000_001).unwrap(); + assert!(locktime.is_satisfied_by(mtp)); + + // It is not satisfied if the lock time is after the median time past. + let locktime = MedianTimePast::from_u32(500_000_002).unwrap(); + assert!(!locktime.is_satisfied_by(mtp)); + } } From ebb9861c58419c1f2e3cce2ef4ecdfa1dee144e0 Mon Sep 17 00:00:00 2001 From: yancy Date: Mon, 2 Jun 2025 08:00:40 -0500 Subject: [PATCH 078/857] Add backticks around OPCodes Item in documentation is missing backticks --- bitcoin/src/blockdata/opcodes.rs | 168 +++++++++++++++---------------- primitives/src/opcodes.rs | 168 +++++++++++++++---------------- 2 files changed, 168 insertions(+), 168 deletions(-) diff --git a/bitcoin/src/blockdata/opcodes.rs b/bitcoin/src/blockdata/opcodes.rs index 5da0295d39..8e74c96309 100644 --- a/bitcoin/src/blockdata/opcodes.rs +++ b/bitcoin/src/blockdata/opcodes.rs @@ -153,7 +153,7 @@ all_opcodes! { OP_PUSHDATA2 => 0x4d, "Read the next 2 bytes as N; push the next N bytes as an array onto the stack."; OP_PUSHDATA4 => 0x4e, "Read the next 4 bytes as N; push the next N bytes as an array onto the stack."; OP_PUSHNUM_NEG1 => 0x4f, "Push the array `0x81` onto the stack."; - OP_RESERVED => 0x50, "Synonym for OP_RETURN."; + OP_RESERVED => 0x50, "Synonym for `OP_RETURN`."; OP_PUSHNUM_1 => 0x51, "Push the array `0x01` onto the stack."; OP_PUSHNUM_2 => 0x52, "Push the array `0x02` onto the stack."; OP_PUSHNUM_3 => 0x53, "Push the array `0x03` onto the stack."; @@ -171,35 +171,35 @@ all_opcodes! { OP_PUSHNUM_15 => 0x5f, "Push the array `0x0f` onto the stack."; OP_PUSHNUM_16 => 0x60, "Push the array `0x10` onto the stack."; OP_NOP => 0x61, "Does nothing."; - OP_VER => 0x62, "Synonym for OP_RETURN."; + OP_VER => 0x62, "Synonym for `OP_RETURN`."; OP_IF => 0x63, "Pop and execute the next statements if a nonzero element was popped."; OP_NOTIF => 0x64, "Pop and execute the next statements if a zero element was popped."; OP_VERIF => 0x65, "Fail the script unconditionally, does not even need to be executed."; OP_VERNOTIF => 0x66, "Fail the script unconditionally, does not even need to be executed."; - OP_ELSE => 0x67, "Execute statements if those after the previous OP_IF were not, and vice-versa. \ - If there is no previous OP_IF, this acts as a RETURN."; + OP_ELSE => 0x67, "Execute statements if those after the previous `OP_IF` were not, and vice-versa. \ + If there is no previous `OP_IF`, this acts as a RETURN."; OP_ENDIF => 0x68, "Pop and execute the next statements if a zero element was popped."; OP_VERIFY => 0x69, "If the top value is zero or the stack is empty, fail; otherwise, pop the stack."; OP_RETURN => 0x6a, "Fail the script immediately. (Must be executed.)."; OP_TOALTSTACK => 0x6b, "Pop one element from the main stack onto the alt stack."; OP_FROMALTSTACK => 0x6c, "Pop one element from the alt stack onto the main stack."; OP_2DROP => 0x6d, "Drops the top two stack items."; - OP_2DUP => 0x6e, "Duplicates the top two stack items as AB -> ABAB."; - OP_3DUP => 0x6f, "Duplicates the two three stack items as ABC -> ABCABC."; - OP_2OVER => 0x70, "Copies the two stack items of items two spaces back to the front, as xxAB -> ABxxAB."; - OP_2ROT => 0x71, "Moves the two stack items four spaces back to the front, as xxxxAB -> ABxxxx."; - OP_2SWAP => 0x72, "Swaps the top two pairs, as ABCD -> CDAB."; + OP_2DUP => 0x6e, "Duplicates the top two stack items as `AB` -> `ABAB`."; + OP_3DUP => 0x6f, "Duplicates the two three stack items as `ABC` -> `ABCABC`."; + OP_2OVER => 0x70, "Copies the two stack items of items two spaces back to the front, as `xxAB` -> `ABxxAB`."; + OP_2ROT => 0x71, "Moves the two stack items four spaces back to the front, as `xxxxAB` -> `ABxxxx`."; + OP_2SWAP => 0x72, "Swaps the top two pairs, as `ABCD` -> `CDAB`."; OP_IFDUP => 0x73, "Duplicate the top stack element unless it is zero."; OP_DEPTH => 0x74, "Push the current number of stack items onto the stack."; OP_DROP => 0x75, "Drops the top stack item."; OP_DUP => 0x76, "Duplicates the top stack item."; OP_NIP => 0x77, "Drops the second-to-top stack item."; - OP_OVER => 0x78, "Copies the second-to-top stack item, as xA -> AxA."; + OP_OVER => 0x78, "Copies the second-to-top stack item, as `xA` -> `AxA`."; OP_PICK => 0x79, "Pop the top stack element as N. Copy the Nth stack element to the top."; OP_ROLL => 0x7a, "Pop the top stack element as N. Move the Nth stack element to the top."; - OP_ROT => 0x7b, "Rotate the top three stack items, as [top next1 next2] -> [next2 top next1]."; + OP_ROT => 0x7b, "Rotate the top three stack items, as `[top next1 next2]` -> `[next2 top next1]`."; OP_SWAP => 0x7c, "Swap the top two stack items."; - OP_TUCK => 0x7d, "Copy the top stack item to before the second item, as [top next] -> [top next top]."; + OP_TUCK => 0x7d, "Copy the top stack item to before the second item, as `[top next]` -> `[top next top]`."; OP_CAT => 0x7e, "Fail the script unconditionally, does not even need to be executed."; OP_SUBSTR => 0x7f, "Fail the script unconditionally, does not even need to be executed."; OP_LEFT => 0x80, "Fail the script unconditionally, does not even need to be executed."; @@ -211,8 +211,8 @@ all_opcodes! { OP_XOR => 0x86, "Fail the script unconditionally, does not even need to be executed."; OP_EQUAL => 0x87, "Pushes 1 if the inputs are exactly equal, 0 otherwise."; OP_EQUALVERIFY => 0x88, "Returns success if the inputs are exactly equal, failure otherwise."; - OP_RESERVED1 => 0x89, "Synonym for OP_RETURN."; - OP_RESERVED2 => 0x8a, "Synonym for OP_RETURN."; + OP_RESERVED1 => 0x89, "Synonym for `OP_RETURN`."; + OP_RESERVED2 => 0x8a, "Synonym for `OP_RETURN`."; OP_1ADD => 0x8b, "Increment the top stack element in place."; OP_1SUB => 0x8c, "Decrement the top stack element in place."; OP_2MUL => 0x8d, "Fail the script unconditionally, does not even need to be executed."; @@ -262,76 +262,76 @@ all_opcodes! { OP_NOP9 => 0xb8, "Does nothing."; OP_NOP10 => 0xb9, "Does nothing."; // Every other opcode acts as OP_RETURN - OP_CHECKSIGADD => 0xba, "OP_CHECKSIGADD post tapscript."; - OP_RETURN_187 => 0xbb, "Synonym for OP_RETURN."; - OP_RETURN_188 => 0xbc, "Synonym for OP_RETURN."; - OP_RETURN_189 => 0xbd, "Synonym for OP_RETURN."; - OP_RETURN_190 => 0xbe, "Synonym for OP_RETURN."; - OP_RETURN_191 => 0xbf, "Synonym for OP_RETURN."; - OP_RETURN_192 => 0xc0, "Synonym for OP_RETURN."; - OP_RETURN_193 => 0xc1, "Synonym for OP_RETURN."; - OP_RETURN_194 => 0xc2, "Synonym for OP_RETURN."; - OP_RETURN_195 => 0xc3, "Synonym for OP_RETURN."; - OP_RETURN_196 => 0xc4, "Synonym for OP_RETURN."; - OP_RETURN_197 => 0xc5, "Synonym for OP_RETURN."; - OP_RETURN_198 => 0xc6, "Synonym for OP_RETURN."; - OP_RETURN_199 => 0xc7, "Synonym for OP_RETURN."; - OP_RETURN_200 => 0xc8, "Synonym for OP_RETURN."; - OP_RETURN_201 => 0xc9, "Synonym for OP_RETURN."; - OP_RETURN_202 => 0xca, "Synonym for OP_RETURN."; - OP_RETURN_203 => 0xcb, "Synonym for OP_RETURN."; - OP_RETURN_204 => 0xcc, "Synonym for OP_RETURN."; - OP_RETURN_205 => 0xcd, "Synonym for OP_RETURN."; - OP_RETURN_206 => 0xce, "Synonym for OP_RETURN."; - OP_RETURN_207 => 0xcf, "Synonym for OP_RETURN."; - OP_RETURN_208 => 0xd0, "Synonym for OP_RETURN."; - OP_RETURN_209 => 0xd1, "Synonym for OP_RETURN."; - OP_RETURN_210 => 0xd2, "Synonym for OP_RETURN."; - OP_RETURN_211 => 0xd3, "Synonym for OP_RETURN."; - OP_RETURN_212 => 0xd4, "Synonym for OP_RETURN."; - OP_RETURN_213 => 0xd5, "Synonym for OP_RETURN."; - OP_RETURN_214 => 0xd6, "Synonym for OP_RETURN."; - OP_RETURN_215 => 0xd7, "Synonym for OP_RETURN."; - OP_RETURN_216 => 0xd8, "Synonym for OP_RETURN."; - OP_RETURN_217 => 0xd9, "Synonym for OP_RETURN."; - OP_RETURN_218 => 0xda, "Synonym for OP_RETURN."; - OP_RETURN_219 => 0xdb, "Synonym for OP_RETURN."; - OP_RETURN_220 => 0xdc, "Synonym for OP_RETURN."; - OP_RETURN_221 => 0xdd, "Synonym for OP_RETURN."; - OP_RETURN_222 => 0xde, "Synonym for OP_RETURN."; - OP_RETURN_223 => 0xdf, "Synonym for OP_RETURN."; - OP_RETURN_224 => 0xe0, "Synonym for OP_RETURN."; - OP_RETURN_225 => 0xe1, "Synonym for OP_RETURN."; - OP_RETURN_226 => 0xe2, "Synonym for OP_RETURN."; - OP_RETURN_227 => 0xe3, "Synonym for OP_RETURN."; - OP_RETURN_228 => 0xe4, "Synonym for OP_RETURN."; - OP_RETURN_229 => 0xe5, "Synonym for OP_RETURN."; - OP_RETURN_230 => 0xe6, "Synonym for OP_RETURN."; - OP_RETURN_231 => 0xe7, "Synonym for OP_RETURN."; - OP_RETURN_232 => 0xe8, "Synonym for OP_RETURN."; - OP_RETURN_233 => 0xe9, "Synonym for OP_RETURN."; - OP_RETURN_234 => 0xea, "Synonym for OP_RETURN."; - OP_RETURN_235 => 0xeb, "Synonym for OP_RETURN."; - OP_RETURN_236 => 0xec, "Synonym for OP_RETURN."; - OP_RETURN_237 => 0xed, "Synonym for OP_RETURN."; - OP_RETURN_238 => 0xee, "Synonym for OP_RETURN."; - OP_RETURN_239 => 0xef, "Synonym for OP_RETURN."; - OP_RETURN_240 => 0xf0, "Synonym for OP_RETURN."; - OP_RETURN_241 => 0xf1, "Synonym for OP_RETURN."; - OP_RETURN_242 => 0xf2, "Synonym for OP_RETURN."; - OP_RETURN_243 => 0xf3, "Synonym for OP_RETURN."; - OP_RETURN_244 => 0xf4, "Synonym for OP_RETURN."; - OP_RETURN_245 => 0xf5, "Synonym for OP_RETURN."; - OP_RETURN_246 => 0xf6, "Synonym for OP_RETURN."; - OP_RETURN_247 => 0xf7, "Synonym for OP_RETURN."; - OP_RETURN_248 => 0xf8, "Synonym for OP_RETURN."; - OP_RETURN_249 => 0xf9, "Synonym for OP_RETURN."; - OP_RETURN_250 => 0xfa, "Synonym for OP_RETURN."; - OP_RETURN_251 => 0xfb, "Synonym for OP_RETURN."; - OP_RETURN_252 => 0xfc, "Synonym for OP_RETURN."; - OP_RETURN_253 => 0xfd, "Synonym for OP_RETURN."; - OP_RETURN_254 => 0xfe, "Synonym for OP_RETURN."; - OP_INVALIDOPCODE => 0xff, "Synonym for OP_RETURN." + OP_CHECKSIGADD => 0xba, "`OP_CHECKSIGADD` post tapscript."; + OP_RETURN_187 => 0xbb, "Synonym for `OP_RETURN`."; + OP_RETURN_188 => 0xbc, "Synonym for `OP_RETURN`."; + OP_RETURN_189 => 0xbd, "Synonym for `OP_RETURN`."; + OP_RETURN_190 => 0xbe, "Synonym for `OP_RETURN`."; + OP_RETURN_191 => 0xbf, "Synonym for `OP_RETURN`."; + OP_RETURN_192 => 0xc0, "Synonym for `OP_RETURN`."; + OP_RETURN_193 => 0xc1, "Synonym for `OP_RETURN`."; + OP_RETURN_194 => 0xc2, "Synonym for `OP_RETURN`."; + OP_RETURN_195 => 0xc3, "Synonym for `OP_RETURN`."; + OP_RETURN_196 => 0xc4, "Synonym for `OP_RETURN`."; + OP_RETURN_197 => 0xc5, "Synonym for `OP_RETURN`."; + OP_RETURN_198 => 0xc6, "Synonym for `OP_RETURN`."; + OP_RETURN_199 => 0xc7, "Synonym for `OP_RETURN`."; + OP_RETURN_200 => 0xc8, "Synonym for `OP_RETURN`."; + OP_RETURN_201 => 0xc9, "Synonym for `OP_RETURN`."; + OP_RETURN_202 => 0xca, "Synonym for `OP_RETURN`."; + OP_RETURN_203 => 0xcb, "Synonym for `OP_RETURN`."; + OP_RETURN_204 => 0xcc, "Synonym for `OP_RETURN`."; + OP_RETURN_205 => 0xcd, "Synonym for `OP_RETURN`."; + OP_RETURN_206 => 0xce, "Synonym for `OP_RETURN`."; + OP_RETURN_207 => 0xcf, "Synonym for `OP_RETURN`."; + OP_RETURN_208 => 0xd0, "Synonym for `OP_RETURN`."; + OP_RETURN_209 => 0xd1, "Synonym for `OP_RETURN`."; + OP_RETURN_210 => 0xd2, "Synonym for `OP_RETURN`."; + OP_RETURN_211 => 0xd3, "Synonym for `OP_RETURN`."; + OP_RETURN_212 => 0xd4, "Synonym for `OP_RETURN`."; + OP_RETURN_213 => 0xd5, "Synonym for `OP_RETURN`."; + OP_RETURN_214 => 0xd6, "Synonym for `OP_RETURN`."; + OP_RETURN_215 => 0xd7, "Synonym for `OP_RETURN`."; + OP_RETURN_216 => 0xd8, "Synonym for `OP_RETURN`."; + OP_RETURN_217 => 0xd9, "Synonym for `OP_RETURN`."; + OP_RETURN_218 => 0xda, "Synonym for `OP_RETURN`."; + OP_RETURN_219 => 0xdb, "Synonym for `OP_RETURN`."; + OP_RETURN_220 => 0xdc, "Synonym for `OP_RETURN`."; + OP_RETURN_221 => 0xdd, "Synonym for `OP_RETURN`."; + OP_RETURN_222 => 0xde, "Synonym for `OP_RETURN`."; + OP_RETURN_223 => 0xdf, "Synonym for `OP_RETURN`."; + OP_RETURN_224 => 0xe0, "Synonym for `OP_RETURN`."; + OP_RETURN_225 => 0xe1, "Synonym for `OP_RETURN`."; + OP_RETURN_226 => 0xe2, "Synonym for `OP_RETURN`."; + OP_RETURN_227 => 0xe3, "Synonym for `OP_RETURN`."; + OP_RETURN_228 => 0xe4, "Synonym for `OP_RETURN`."; + OP_RETURN_229 => 0xe5, "Synonym for `OP_RETURN`."; + OP_RETURN_230 => 0xe6, "Synonym for `OP_RETURN`."; + OP_RETURN_231 => 0xe7, "Synonym for `OP_RETURN`."; + OP_RETURN_232 => 0xe8, "Synonym for `OP_RETURN`."; + OP_RETURN_233 => 0xe9, "Synonym for `OP_RETURN`."; + OP_RETURN_234 => 0xea, "Synonym for `OP_RETURN`."; + OP_RETURN_235 => 0xeb, "Synonym for `OP_RETURN`."; + OP_RETURN_236 => 0xec, "Synonym for `OP_RETURN`."; + OP_RETURN_237 => 0xed, "Synonym for `OP_RETURN`."; + OP_RETURN_238 => 0xee, "Synonym for `OP_RETURN`."; + OP_RETURN_239 => 0xef, "Synonym for `OP_RETURN`."; + OP_RETURN_240 => 0xf0, "Synonym for `OP_RETURN`."; + OP_RETURN_241 => 0xf1, "Synonym for `OP_RETURN`."; + OP_RETURN_242 => 0xf2, "Synonym for `OP_RETURN`."; + OP_RETURN_243 => 0xf3, "Synonym for `OP_RETURN`."; + OP_RETURN_244 => 0xf4, "Synonym for `OP_RETURN`."; + OP_RETURN_245 => 0xf5, "Synonym for `OP_RETURN`."; + OP_RETURN_246 => 0xf6, "Synonym for `OP_RETURN`."; + OP_RETURN_247 => 0xf7, "Synonym for `OP_RETURN`."; + OP_RETURN_248 => 0xf8, "Synonym for `OP_RETURN`."; + OP_RETURN_249 => 0xf9, "Synonym for `OP_RETURN`."; + OP_RETURN_250 => 0xfa, "Synonym for `OP_RETURN`."; + OP_RETURN_251 => 0xfb, "Synonym for `OP_RETURN`."; + OP_RETURN_252 => 0xfc, "Synonym for `OP_RETURN`."; + OP_RETURN_253 => 0xfd, "Synonym for `OP_RETURN`."; + OP_RETURN_254 => 0xfe, "Synonym for `OP_RETURN`."; + OP_INVALIDOPCODE => 0xff, "Synonym for `OP_RETURN`." } /// Classification context for the opcode. diff --git a/primitives/src/opcodes.rs b/primitives/src/opcodes.rs index 8438445569..933629e5e8 100644 --- a/primitives/src/opcodes.rs +++ b/primitives/src/opcodes.rs @@ -155,7 +155,7 @@ all_opcodes! { OP_PUSHDATA2 => 0x4d, "Read the next 2 bytes as N; push the next N bytes as an array onto the stack."; OP_PUSHDATA4 => 0x4e, "Read the next 4 bytes as N; push the next N bytes as an array onto the stack."; OP_PUSHNUM_NEG1 => 0x4f, "Push the array `0x81` onto the stack."; - OP_RESERVED => 0x50, "Synonym for OP_RETURN."; + OP_RESERVED => 0x50, "Synonym for `OP_RETURN`."; OP_PUSHNUM_1 => 0x51, "Push the array `0x01` onto the stack."; OP_PUSHNUM_2 => 0x52, "Push the array `0x02` onto the stack."; OP_PUSHNUM_3 => 0x53, "Push the array `0x03` onto the stack."; @@ -173,35 +173,35 @@ all_opcodes! { OP_PUSHNUM_15 => 0x5f, "Push the array `0x0f` onto the stack."; OP_PUSHNUM_16 => 0x60, "Push the array `0x10` onto the stack."; OP_NOP => 0x61, "Does nothing."; - OP_VER => 0x62, "Synonym for OP_RETURN."; + OP_VER => 0x62, "Synonym for `OP_RETURN`."; OP_IF => 0x63, "Pop and execute the next statements if a nonzero element was popped."; OP_NOTIF => 0x64, "Pop and execute the next statements if a zero element was popped."; OP_VERIF => 0x65, "Fail the script unconditionally, does not even need to be executed."; OP_VERNOTIF => 0x66, "Fail the script unconditionally, does not even need to be executed."; - OP_ELSE => 0x67, "Execute statements if those after the previous OP_IF were not, and vice-versa. \ - If there is no previous OP_IF, this acts as a RETURN."; + OP_ELSE => 0x67, "Execute statements if those after the previous `OP_IF` were not, and vice-versa. \ + If there is no previous `OP_IF`, this acts as a RETURN."; OP_ENDIF => 0x68, "Pop and execute the next statements if a zero element was popped."; OP_VERIFY => 0x69, "If the top value is zero or the stack is empty, fail; otherwise, pop the stack."; OP_RETURN => 0x6a, "Fail the script immediately. (Must be executed.)."; OP_TOALTSTACK => 0x6b, "Pop one element from the main stack onto the alt stack."; OP_FROMALTSTACK => 0x6c, "Pop one element from the alt stack onto the main stack."; OP_2DROP => 0x6d, "Drops the top two stack items."; - OP_2DUP => 0x6e, "Duplicates the top two stack items as AB -> ABAB."; - OP_3DUP => 0x6f, "Duplicates the two three stack items as ABC -> ABCABC."; - OP_2OVER => 0x70, "Copies the two stack items of items two spaces back to the front, as xxAB -> ABxxAB."; - OP_2ROT => 0x71, "Moves the two stack items four spaces back to the front, as xxxxAB -> ABxxxx."; - OP_2SWAP => 0x72, "Swaps the top two pairs, as ABCD -> CDAB."; + OP_2DUP => 0x6e, "Duplicates the top two stack items as `AB` -> `ABAB`."; + OP_3DUP => 0x6f, "Duplicates the two three stack items as `ABC` -> `ABCABC`."; + OP_2OVER => 0x70, "Copies the two stack items of items two spaces back to the front, as `xxAB` -> `ABxxAB`."; + OP_2ROT => 0x71, "Moves the two stack items four spaces back to the front, as `xxxxAB` -> `ABxxxx`."; + OP_2SWAP => 0x72, "Swaps the top two pairs, as `ABCD` -> `CDAB`."; OP_IFDUP => 0x73, "Duplicate the top stack element unless it is zero."; OP_DEPTH => 0x74, "Push the current number of stack items onto the stack."; OP_DROP => 0x75, "Drops the top stack item."; OP_DUP => 0x76, "Duplicates the top stack item."; OP_NIP => 0x77, "Drops the second-to-top stack item."; - OP_OVER => 0x78, "Copies the second-to-top stack item, as xA -> AxA."; + OP_OVER => 0x78, "Copies the second-to-top stack item, as `xA` -> `AxA`."; OP_PICK => 0x79, "Pop the top stack element as N. Copy the Nth stack element to the top."; OP_ROLL => 0x7a, "Pop the top stack element as N. Move the Nth stack element to the top."; - OP_ROT => 0x7b, "Rotate the top three stack items, as [top next1 next2] -> [next2 top next1]."; + OP_ROT => 0x7b, "Rotate the top three stack items, as `[top next1 next2]` -> `[next2 top next1]`."; OP_SWAP => 0x7c, "Swap the top two stack items."; - OP_TUCK => 0x7d, "Copy the top stack item to before the second item, as [top next] -> [top next top]."; + OP_TUCK => 0x7d, "Copy the top stack item to before the second item, as `[top next]` -> `[top next top]`."; OP_CAT => 0x7e, "Fail the script unconditionally, does not even need to be executed."; OP_SUBSTR => 0x7f, "Fail the script unconditionally, does not even need to be executed."; OP_LEFT => 0x80, "Fail the script unconditionally, does not even need to be executed."; @@ -213,8 +213,8 @@ all_opcodes! { OP_XOR => 0x86, "Fail the script unconditionally, does not even need to be executed."; OP_EQUAL => 0x87, "Pushes 1 if the inputs are exactly equal, 0 otherwise."; OP_EQUALVERIFY => 0x88, "Returns success if the inputs are exactly equal, failure otherwise."; - OP_RESERVED1 => 0x89, "Synonym for OP_RETURN."; - OP_RESERVED2 => 0x8a, "Synonym for OP_RETURN."; + OP_RESERVED1 => 0x89, "Synonym for `OP_RETURN`."; + OP_RESERVED2 => 0x8a, "Synonym for `OP_RETURN`."; OP_1ADD => 0x8b, "Increment the top stack element in place."; OP_1SUB => 0x8c, "Decrement the top stack element in place."; OP_2MUL => 0x8d, "Fail the script unconditionally, does not even need to be executed."; @@ -264,76 +264,76 @@ all_opcodes! { OP_NOP9 => 0xb8, "Does nothing."; OP_NOP10 => 0xb9, "Does nothing."; // Every other opcode acts as OP_RETURN - OP_CHECKSIGADD => 0xba, "OP_CHECKSIGADD post tapscript."; - OP_RETURN_187 => 0xbb, "Synonym for OP_RETURN."; - OP_RETURN_188 => 0xbc, "Synonym for OP_RETURN."; - OP_RETURN_189 => 0xbd, "Synonym for OP_RETURN."; - OP_RETURN_190 => 0xbe, "Synonym for OP_RETURN."; - OP_RETURN_191 => 0xbf, "Synonym for OP_RETURN."; - OP_RETURN_192 => 0xc0, "Synonym for OP_RETURN."; - OP_RETURN_193 => 0xc1, "Synonym for OP_RETURN."; - OP_RETURN_194 => 0xc2, "Synonym for OP_RETURN."; - OP_RETURN_195 => 0xc3, "Synonym for OP_RETURN."; - OP_RETURN_196 => 0xc4, "Synonym for OP_RETURN."; - OP_RETURN_197 => 0xc5, "Synonym for OP_RETURN."; - OP_RETURN_198 => 0xc6, "Synonym for OP_RETURN."; - OP_RETURN_199 => 0xc7, "Synonym for OP_RETURN."; - OP_RETURN_200 => 0xc8, "Synonym for OP_RETURN."; - OP_RETURN_201 => 0xc9, "Synonym for OP_RETURN."; - OP_RETURN_202 => 0xca, "Synonym for OP_RETURN."; - OP_RETURN_203 => 0xcb, "Synonym for OP_RETURN."; - OP_RETURN_204 => 0xcc, "Synonym for OP_RETURN."; - OP_RETURN_205 => 0xcd, "Synonym for OP_RETURN."; - OP_RETURN_206 => 0xce, "Synonym for OP_RETURN."; - OP_RETURN_207 => 0xcf, "Synonym for OP_RETURN."; - OP_RETURN_208 => 0xd0, "Synonym for OP_RETURN."; - OP_RETURN_209 => 0xd1, "Synonym for OP_RETURN."; - OP_RETURN_210 => 0xd2, "Synonym for OP_RETURN."; - OP_RETURN_211 => 0xd3, "Synonym for OP_RETURN."; - OP_RETURN_212 => 0xd4, "Synonym for OP_RETURN."; - OP_RETURN_213 => 0xd5, "Synonym for OP_RETURN."; - OP_RETURN_214 => 0xd6, "Synonym for OP_RETURN."; - OP_RETURN_215 => 0xd7, "Synonym for OP_RETURN."; - OP_RETURN_216 => 0xd8, "Synonym for OP_RETURN."; - OP_RETURN_217 => 0xd9, "Synonym for OP_RETURN."; - OP_RETURN_218 => 0xda, "Synonym for OP_RETURN."; - OP_RETURN_219 => 0xdb, "Synonym for OP_RETURN."; - OP_RETURN_220 => 0xdc, "Synonym for OP_RETURN."; - OP_RETURN_221 => 0xdd, "Synonym for OP_RETURN."; - OP_RETURN_222 => 0xde, "Synonym for OP_RETURN."; - OP_RETURN_223 => 0xdf, "Synonym for OP_RETURN."; - OP_RETURN_224 => 0xe0, "Synonym for OP_RETURN."; - OP_RETURN_225 => 0xe1, "Synonym for OP_RETURN."; - OP_RETURN_226 => 0xe2, "Synonym for OP_RETURN."; - OP_RETURN_227 => 0xe3, "Synonym for OP_RETURN."; - OP_RETURN_228 => 0xe4, "Synonym for OP_RETURN."; - OP_RETURN_229 => 0xe5, "Synonym for OP_RETURN."; - OP_RETURN_230 => 0xe6, "Synonym for OP_RETURN."; - OP_RETURN_231 => 0xe7, "Synonym for OP_RETURN."; - OP_RETURN_232 => 0xe8, "Synonym for OP_RETURN."; - OP_RETURN_233 => 0xe9, "Synonym for OP_RETURN."; - OP_RETURN_234 => 0xea, "Synonym for OP_RETURN."; - OP_RETURN_235 => 0xeb, "Synonym for OP_RETURN."; - OP_RETURN_236 => 0xec, "Synonym for OP_RETURN."; - OP_RETURN_237 => 0xed, "Synonym for OP_RETURN."; - OP_RETURN_238 => 0xee, "Synonym for OP_RETURN."; - OP_RETURN_239 => 0xef, "Synonym for OP_RETURN."; - OP_RETURN_240 => 0xf0, "Synonym for OP_RETURN."; - OP_RETURN_241 => 0xf1, "Synonym for OP_RETURN."; - OP_RETURN_242 => 0xf2, "Synonym for OP_RETURN."; - OP_RETURN_243 => 0xf3, "Synonym for OP_RETURN."; - OP_RETURN_244 => 0xf4, "Synonym for OP_RETURN."; - OP_RETURN_245 => 0xf5, "Synonym for OP_RETURN."; - OP_RETURN_246 => 0xf6, "Synonym for OP_RETURN."; - OP_RETURN_247 => 0xf7, "Synonym for OP_RETURN."; - OP_RETURN_248 => 0xf8, "Synonym for OP_RETURN."; - OP_RETURN_249 => 0xf9, "Synonym for OP_RETURN."; - OP_RETURN_250 => 0xfa, "Synonym for OP_RETURN."; - OP_RETURN_251 => 0xfb, "Synonym for OP_RETURN."; - OP_RETURN_252 => 0xfc, "Synonym for OP_RETURN."; - OP_RETURN_253 => 0xfd, "Synonym for OP_RETURN."; - OP_RETURN_254 => 0xfe, "Synonym for OP_RETURN."; - OP_INVALIDOPCODE => 0xff, "Synonym for OP_RETURN." + OP_CHECKSIGADD => 0xba, "`OP_CHECKSIGADD` post tapscript."; + OP_RETURN_187 => 0xbb, "Synonym for `OP_RETURN`."; + OP_RETURN_188 => 0xbc, "Synonym for `OP_RETURN`."; + OP_RETURN_189 => 0xbd, "Synonym for `OP_RETURN`."; + OP_RETURN_190 => 0xbe, "Synonym for `OP_RETURN`."; + OP_RETURN_191 => 0xbf, "Synonym for `OP_RETURN`."; + OP_RETURN_192 => 0xc0, "Synonym for `OP_RETURN`."; + OP_RETURN_193 => 0xc1, "Synonym for `OP_RETURN`."; + OP_RETURN_194 => 0xc2, "Synonym for `OP_RETURN`."; + OP_RETURN_195 => 0xc3, "Synonym for `OP_RETURN`."; + OP_RETURN_196 => 0xc4, "Synonym for `OP_RETURN`."; + OP_RETURN_197 => 0xc5, "Synonym for `OP_RETURN`."; + OP_RETURN_198 => 0xc6, "Synonym for `OP_RETURN`."; + OP_RETURN_199 => 0xc7, "Synonym for `OP_RETURN`."; + OP_RETURN_200 => 0xc8, "Synonym for `OP_RETURN`."; + OP_RETURN_201 => 0xc9, "Synonym for `OP_RETURN`."; + OP_RETURN_202 => 0xca, "Synonym for `OP_RETURN`."; + OP_RETURN_203 => 0xcb, "Synonym for `OP_RETURN`."; + OP_RETURN_204 => 0xcc, "Synonym for `OP_RETURN`."; + OP_RETURN_205 => 0xcd, "Synonym for `OP_RETURN`."; + OP_RETURN_206 => 0xce, "Synonym for `OP_RETURN`."; + OP_RETURN_207 => 0xcf, "Synonym for `OP_RETURN`."; + OP_RETURN_208 => 0xd0, "Synonym for `OP_RETURN`."; + OP_RETURN_209 => 0xd1, "Synonym for `OP_RETURN`."; + OP_RETURN_210 => 0xd2, "Synonym for `OP_RETURN`."; + OP_RETURN_211 => 0xd3, "Synonym for `OP_RETURN`."; + OP_RETURN_212 => 0xd4, "Synonym for `OP_RETURN`."; + OP_RETURN_213 => 0xd5, "Synonym for `OP_RETURN`."; + OP_RETURN_214 => 0xd6, "Synonym for `OP_RETURN`."; + OP_RETURN_215 => 0xd7, "Synonym for `OP_RETURN`."; + OP_RETURN_216 => 0xd8, "Synonym for `OP_RETURN`."; + OP_RETURN_217 => 0xd9, "Synonym for `OP_RETURN`."; + OP_RETURN_218 => 0xda, "Synonym for `OP_RETURN`."; + OP_RETURN_219 => 0xdb, "Synonym for `OP_RETURN`."; + OP_RETURN_220 => 0xdc, "Synonym for `OP_RETURN`."; + OP_RETURN_221 => 0xdd, "Synonym for `OP_RETURN`."; + OP_RETURN_222 => 0xde, "Synonym for `OP_RETURN`."; + OP_RETURN_223 => 0xdf, "Synonym for `OP_RETURN`."; + OP_RETURN_224 => 0xe0, "Synonym for `OP_RETURN`."; + OP_RETURN_225 => 0xe1, "Synonym for `OP_RETURN`."; + OP_RETURN_226 => 0xe2, "Synonym for `OP_RETURN`."; + OP_RETURN_227 => 0xe3, "Synonym for `OP_RETURN`."; + OP_RETURN_228 => 0xe4, "Synonym for `OP_RETURN`."; + OP_RETURN_229 => 0xe5, "Synonym for `OP_RETURN`."; + OP_RETURN_230 => 0xe6, "Synonym for `OP_RETURN`."; + OP_RETURN_231 => 0xe7, "Synonym for `OP_RETURN`."; + OP_RETURN_232 => 0xe8, "Synonym for `OP_RETURN`."; + OP_RETURN_233 => 0xe9, "Synonym for `OP_RETURN`."; + OP_RETURN_234 => 0xea, "Synonym for `OP_RETURN`."; + OP_RETURN_235 => 0xeb, "Synonym for `OP_RETURN`."; + OP_RETURN_236 => 0xec, "Synonym for `OP_RETURN`."; + OP_RETURN_237 => 0xed, "Synonym for `OP_RETURN`."; + OP_RETURN_238 => 0xee, "Synonym for `OP_RETURN`."; + OP_RETURN_239 => 0xef, "Synonym for `OP_RETURN`."; + OP_RETURN_240 => 0xf0, "Synonym for `OP_RETURN`."; + OP_RETURN_241 => 0xf1, "Synonym for `OP_RETURN`."; + OP_RETURN_242 => 0xf2, "Synonym for `OP_RETURN`."; + OP_RETURN_243 => 0xf3, "Synonym for `OP_RETURN`."; + OP_RETURN_244 => 0xf4, "Synonym for `OP_RETURN`."; + OP_RETURN_245 => 0xf5, "Synonym for `OP_RETURN`."; + OP_RETURN_246 => 0xf6, "Synonym for `OP_RETURN`."; + OP_RETURN_247 => 0xf7, "Synonym for `OP_RETURN`."; + OP_RETURN_248 => 0xf8, "Synonym for `OP_RETURN`."; + OP_RETURN_249 => 0xf9, "Synonym for `OP_RETURN`."; + OP_RETURN_250 => 0xfa, "Synonym for `OP_RETURN`."; + OP_RETURN_251 => 0xfb, "Synonym for `OP_RETURN`."; + OP_RETURN_252 => 0xfc, "Synonym for `OP_RETURN`."; + OP_RETURN_253 => 0xfd, "Synonym for `OP_RETURN`."; + OP_RETURN_254 => 0xfe, "Synonym for `OP_RETURN`."; + OP_INVALIDOPCODE => 0xff, "Synonym for `OP_RETURN`." } /// Classification context for the opcode. From 4b5c6dd54748eca214a0e2fce33d9f4a354b394a Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 8 Jun 2025 01:44:53 +0000 Subject: [PATCH 079/857] 2025-06-08 automated rustfmt nightly --- bitcoin/examples/handshake.rs | 3 +- bitcoin/src/bip32.rs | 52 ++++++++++++++++++---------------- bitcoin/src/p2p/address.rs | 4 +-- bitcoin/src/p2p/deser.rs | 3 +- bitcoin/src/p2p/message.rs | 14 ++++----- bitcoin/src/p2p/mod.rs | 20 +++++++++---- bitcoin/src/psbt/mod.rs | 46 +++++++++++++++++++++--------- bitcoin/src/psbt/serialize.rs | 6 ++-- units/src/locktime/absolute.rs | 6 ++-- units/tests/serde.rs | 4 ++- 10 files changed, 95 insertions(+), 63 deletions(-) diff --git a/bitcoin/examples/handshake.rs b/bitcoin/examples/handshake.rs index bd941dc0c3..dbc383dd11 100644 --- a/bitcoin/examples/handshake.rs +++ b/bitcoin/examples/handshake.rs @@ -25,8 +25,7 @@ fn main() { let version_message = build_version_message(address); - let first_message = - message::RawNetworkMessage::new(Magic::BITCOIN, version_message); + let first_message = message::RawNetworkMessage::new(Magic::BITCOIN, version_message); if let Ok(mut stream) = TcpStream::connect(address) { // Send the message diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 3e7aae74a5..e6d9621b1e 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1099,12 +1099,7 @@ mod tests { #[test] fn parse_derivation_path_invalid_format() { - let invalid_paths = [ - "n/0'/0", - "4/m/5", - "//3/0'", - "0h/0x", - ]; + let invalid_paths = ["n/0'/0", "4/m/5", "//3/0'", "0h/0x"]; for path in &invalid_paths { assert!(matches!( path.parse::(), @@ -1140,24 +1135,33 @@ mod tests { let valid_paths = [ ("0'", vec![ChildNumber::ZERO_HARDENED]), ("0'/1", vec![ChildNumber::ZERO_HARDENED, ChildNumber::ONE_NORMAL]), - ("0h/1/2'", vec![ - ChildNumber::ZERO_HARDENED, - ChildNumber::ONE_NORMAL, - ChildNumber::from_hardened_idx(2).unwrap(), - ]), - ("0'/1/2h/2", vec![ - ChildNumber::ZERO_HARDENED, - ChildNumber::ONE_NORMAL, - ChildNumber::from_hardened_idx(2).unwrap(), - ChildNumber::from_normal_idx(2).unwrap(), - ]), - ("0'/1/2'/2/1000000000", vec![ - ChildNumber::ZERO_HARDENED, - ChildNumber::ONE_NORMAL, - ChildNumber::from_hardened_idx(2).unwrap(), - ChildNumber::from_normal_idx(2).unwrap(), - ChildNumber::from_normal_idx(1000000000).unwrap(), - ]), + ( + "0h/1/2'", + vec![ + ChildNumber::ZERO_HARDENED, + ChildNumber::ONE_NORMAL, + ChildNumber::from_hardened_idx(2).unwrap(), + ], + ), + ( + "0'/1/2h/2", + vec![ + ChildNumber::ZERO_HARDENED, + ChildNumber::ONE_NORMAL, + ChildNumber::from_hardened_idx(2).unwrap(), + ChildNumber::from_normal_idx(2).unwrap(), + ], + ), + ( + "0'/1/2'/2/1000000000", + vec![ + ChildNumber::ZERO_HARDENED, + ChildNumber::ONE_NORMAL, + ChildNumber::from_hardened_idx(2).unwrap(), + ChildNumber::from_normal_idx(2).unwrap(), + ChildNumber::from_normal_idx(1000000000).unwrap(), + ], + ), ]; for (path, expected) in valid_paths { // Access the inner private field so we don't have to clone expected. diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs index 34481675a5..7a4af27e4e 100644 --- a/bitcoin/src/p2p/address.rs +++ b/bitcoin/src/p2p/address.rs @@ -138,7 +138,6 @@ pub enum AddrV2 { Unknown(u8, Vec), } - impl TryFrom for IpAddr { type Error = AddrV2ToIpAddrError; @@ -443,7 +442,8 @@ mod test { use hex_lit::hex; use super::*; - use crate::{consensus::encode::{deserialize, serialize}, p2p::message::AddrV2Payload}; + use crate::consensus::encode::{deserialize, serialize}; + use crate::p2p::message::AddrV2Payload; #[test] fn serialize_address() { diff --git a/bitcoin/src/p2p/deser.rs b/bitcoin/src/p2p/deser.rs index 09a18f23b7..cae2906c31 100644 --- a/bitcoin/src/p2p/deser.rs +++ b/bitcoin/src/p2p/deser.rs @@ -27,7 +27,8 @@ macro_rules! impl_vec_wrapper { // reallocate. // Note: OOM protection relies on reader eventually running out of // data to feed us. - let max_capacity = crate::consensus::encode::MAX_VEC_SIZE / 4 / core::mem::size_of::<$type>(); + let max_capacity = + crate::consensus::encode::MAX_VEC_SIZE / 4 / core::mem::size_of::<$type>(); let mut ret = Vec::with_capacity(core::cmp::min(len as usize, max_capacity)); for _ in 0..len { ret.push(Decodable::consensus_decode_from_finite_reader(r)?); diff --git a/bitcoin/src/p2p/message.rs b/bitcoin/src/p2p/message.rs index 3bfc8513bc..14b11f27da 100644 --- a/bitcoin/src/p2p/message.rs +++ b/bitcoin/src/p2p/message.rs @@ -14,12 +14,12 @@ use io::{BufRead, Write}; use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, ReadExt, WriteExt}; use crate::merkle_tree::MerkleBlock; use crate::p2p::address::{AddrV2Message, Address}; +use crate::p2p::deser::impl_vec_wrapper; use crate::p2p::{ message_blockdata, message_bloom, message_compact_blocks, message_filter, message_network, Magic, }; use crate::prelude::{Box, Cow, String, ToOwned, Vec}; -use crate::p2p::deser::impl_vec_wrapper; use crate::{block, consensus, transaction}; /// The maximum number of [super::message_blockdata::Inventory] items in an `inv` message. @@ -755,12 +755,12 @@ mod test { 45, Address::new(&([123, 255, 000, 100], 833).into(), ServiceFlags::NETWORK), )])), - NetworkMessage::Inv(InventoryPayload(vec![Inventory::Block(BlockHash::from_byte_array( - hash([8u8; 32]).to_byte_array(), - ))])), - NetworkMessage::GetData(InventoryPayload(vec![Inventory::Transaction(Txid::from_byte_array( - hash([45u8; 32]).to_byte_array(), - ))])), + NetworkMessage::Inv(InventoryPayload(vec![Inventory::Block( + BlockHash::from_byte_array(hash([8u8; 32]).to_byte_array()), + )])), + NetworkMessage::GetData(InventoryPayload(vec![Inventory::Transaction( + Txid::from_byte_array(hash([45u8; 32]).to_byte_array()), + )])), NetworkMessage::NotFound(InventoryPayload(vec![Inventory::Error([0u8; 32])])), NetworkMessage::GetBlocks(GetBlocksMessage::new( vec![ diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs index 33df5a5b31..0f6b2ccae3 100644 --- a/bitcoin/src/p2p/mod.rs +++ b/bitcoin/src/p2p/mod.rs @@ -8,6 +8,8 @@ #[cfg(feature = "std")] pub mod address; #[cfg(feature = "std")] +mod deser; +#[cfg(feature = "std")] pub mod message; #[cfg(feature = "std")] pub mod message_blockdata; @@ -19,8 +21,6 @@ pub mod message_compact_blocks; pub mod message_filter; #[cfg(feature = "std")] pub mod message_network; -#[cfg(feature = "std")] -mod deser; use core::str::FromStr; use core::{fmt, ops}; @@ -409,7 +409,10 @@ mod tests { let magic: Magic = Network::Regtest.into(); assert_eq!(serialize(&magic), &[0xfa, 0xbf, 0xb5, 0xda]); - assert_eq!(deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.into())); + assert_eq!( + deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), + Some(Network::Bitcoin.into()) + ); assert_eq!( deserialize::(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet(TestnetVersion::V3).into()) @@ -418,11 +421,16 @@ mod tests { deserialize::(&[0x1c, 0x16, 0x3f, 0x28]).ok(), Some(Network::Testnet(TestnetVersion::V4).into()) ); - assert_eq!(deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.into())); - assert_eq!(deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.into())); + assert_eq!( + deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), + Some(Network::Signet.into()) + ); + assert_eq!( + deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), + Some(Network::Regtest.into()) + ); } - #[test] fn service_flags_test() { let all = [ diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 07b2d8f41d..40153c4609 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -898,11 +898,11 @@ impl GetKey for $map { KeyRequest::XOnlyPubkey(xonly) => { let pubkey_even = xonly.public_key(secp256k1::Parity::Even); let key = self.get(&pubkey_even).cloned(); - + if key.is_some() { return Ok(key); } - + let pubkey_odd = xonly.public_key(secp256k1::Parity::Odd); if let Some(priv_key) = self.get(&pubkey_odd).copied() { let negated_priv_key = priv_key.negate(); @@ -935,18 +935,18 @@ impl GetKey for $map { KeyRequest::XOnlyPubkey(xonly) => Ok(self.get(xonly).cloned()), KeyRequest::Pubkey(pk) => { let (xonly, parity) = pk.inner.x_only_public_key(); - + if let Some(mut priv_key) = self.get(&XOnlyPublicKey::from(xonly)).cloned() { let computed_pk = priv_key.public_key(&secp); let (_, computed_parity) = computed_pk.inner.x_only_public_key(); - + if computed_parity != parity { priv_key = priv_key.negate(); } - + return Ok(Some(priv_key)); } - + Ok(None) }, KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported), @@ -1329,6 +1329,8 @@ pub use self::display_from_str::PsbtParseError; #[cfg(test)] mod tests { + use std::str::FromStr; + use hashes::{hash160, ripemd160, sha256}; use hex::FromHex; use hex_lit::hex; @@ -1342,8 +1344,6 @@ mod tests { secp256k1::{All, SecretKey}, }; - use std::str::FromStr; - use super::*; use crate::address::script_pubkey::ScriptExt as _; use crate::bip32::ChildNumber; @@ -2249,17 +2249,35 @@ mod tests { fn serialize_and_deserialize_musig2_participants() { // XXX: Does not cover PSBT_IN_MUSIG2_PUB_NONCE, PSBT_IN_MUSIG2_PARTIAL_SIG (yet) - let expected_in_agg_pk = secp256k1::PublicKey::from_str("021401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e00").unwrap(); + let expected_in_agg_pk = secp256k1::PublicKey::from_str( + "021401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e00", + ) + .unwrap(); let expected_in_pubkeys = vec![ - secp256k1::PublicKey::from_str("02bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a").unwrap(), - secp256k1::PublicKey::from_str("0355212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e2").unwrap(), + secp256k1::PublicKey::from_str( + "02bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a", + ) + .unwrap(), + secp256k1::PublicKey::from_str( + "0355212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e2", + ) + .unwrap(), ]; - let expected_out_agg_pk = secp256k1::PublicKey::from_str("0364934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba5").unwrap(); + let expected_out_agg_pk = secp256k1::PublicKey::from_str( + "0364934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba5", + ) + .unwrap(); let expected_out_pubkeys = vec![ - secp256k1::PublicKey::from_str("02841d69a8b80ae23a8090e6f3765540ea5efd8c287b1307c983a6e2a3a171b525").unwrap(), - secp256k1::PublicKey::from_str("02bad833849a98cdfb0a0749609ddccab16ad54485ecc67f828df4bdc4f2b90d4c").unwrap(), + secp256k1::PublicKey::from_str( + "02841d69a8b80ae23a8090e6f3765540ea5efd8c287b1307c983a6e2a3a171b525", + ) + .unwrap(), + secp256k1::PublicKey::from_str( + "02bad833849a98cdfb0a0749609ddccab16ad54485ecc67f828df4bdc4f2b90d4c", + ) + .unwrap(), ]; const PSBT_HEX: &str = "70736274ff01005e02000000017b42be5ea467afe0d0571dc4a91bef97ff9605a590c0b8d5892323946414d1810000000000ffffffff01f0b9f50500000000225120bc7e18f55e2c7a28d78cadac1bc72c248372375d269bafe6b315bc40505d07e5000000000001012b00e1f50500000000225120de564ebf8ff7bd9bb41bd88264c04b1713ebb9dc8df36319091d2eabb16cda6221161401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e000500eb4cbe62211655212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e20500755abbf92116bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a05002a33dfd90117201401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e00221a021401301810a46a4e3f39e4603ec228ed301d9f2079767fda758dee7224b32e004202bebd7a1cef20283444b96e9ce78137e951ce48705390933896311a9abc75736a0355212dff7b3d7e8126687a62fd0435a3fb4de56d9af9ae23a1c9ca05b349c8e20001052064934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba5210764934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba50500fa4c6afa22080364934a64831bd917a2667b886671650846f021e1c025e4b2bb65e49ab3e7cba54202841d69a8b80ae23a8090e6f3765540ea5efd8c287b1307c983a6e2a3a171b52502bad833849a98cdfb0a0749609ddccab16ad54485ecc67f828df4bdc4f2b90d4c00"; diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 01b5dc9580..542c9798fa 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -174,7 +174,8 @@ impl Deserialize for secp256k1::PublicKey { impl Serialize for Vec { fn serialize(&self) -> Vec { - let mut result: Vec = Vec::with_capacity(secp256k1::constants::PUBLIC_KEY_SIZE * self.len()); + let mut result: Vec = + Vec::with_capacity(secp256k1::constants::PUBLIC_KEY_SIZE * self.len()); for pubkey in self.iter() { result.extend(Serialize::serialize(pubkey)); @@ -186,7 +187,8 @@ impl Serialize for Vec { impl Deserialize for Vec { fn deserialize(bytes: &[u8]) -> Result { - bytes.chunks(secp256k1::constants::PUBLIC_KEY_SIZE) + bytes + .chunks(secp256k1::constants::PUBLIC_KEY_SIZE) .map(secp256k1::PublicKey::deserialize) .collect() } diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index cd42461854..cfbce396b1 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -321,10 +321,8 @@ impl fmt::Display for LockTimeUnit { use LockTimeUnit as L; match *self { - L::Blocks => - write!(f, "expected lock-by-height (must be < {})", LOCK_TIME_THRESHOLD), - L::Seconds => - write!(f, "expected lock-by-time (must be >= {})", LOCK_TIME_THRESHOLD), + L::Blocks => write!(f, "expected lock-by-height (must be < {})", LOCK_TIME_THRESHOLD), + L::Seconds => write!(f, "expected lock-by-time (must be >= {})", LOCK_TIME_THRESHOLD), } } } diff --git a/units/tests/serde.rs b/units/tests/serde.rs index 7a8a59bd47..7a38f046ec 100644 --- a/units/tests/serde.rs +++ b/units/tests/serde.rs @@ -6,7 +6,9 @@ #![cfg(feature = "serde")] use bincode::serialize; -use bitcoin_units::{amount, fee_rate, Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight}; +use bitcoin_units::{ + amount, fee_rate, Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight, +}; use serde::{Deserialize, Serialize}; /// A struct that includes all the types that implement or support `serde` traits. From afc0ce617554303d7fd25e052b039af44b6efc1c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 9 Jun 2025 00:09:46 +1000 Subject: [PATCH 080/857] units: Add must_use to checked arithmetic functions The checked arithmetic functions all consume self so we use `must_use` to help users not miss this point. Most are done, add the missing ones. --- units/src/block.rs | 8 ++++++++ units/src/fee.rs | 2 ++ 2 files changed, 10 insertions(+) diff --git a/units/src/block.rs b/units/src/block.rs index 8eb1932187..c4a02cd9a8 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -88,11 +88,13 @@ impl BlockHeight { pub const fn to_u32(self) -> u32 { self.0 } /// Attempt to subtract two [`BlockHeight`]s, returning `None` in case of overflow. + #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(BlockHeightInterval) } /// Attempt to add an interval to this [`BlockHeight`], returning `None` in case of overflow. + #[must_use] pub fn checked_add(self, other: BlockHeightInterval) -> Option { self.0.checked_add(other.0).map(Self) } @@ -147,9 +149,11 @@ impl BlockHeightInterval { pub const fn to_u32(self) -> u32 { self.0 } /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` in case of overflow. + #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } /// Attempt to add two [`BlockHeightInterval`]s, returning `None` in case of overflow. + #[must_use] pub fn checked_add(self, other: Self) -> Option { self.0.checked_add(other.0).map(Self) } } @@ -217,11 +221,13 @@ impl BlockMtp { } /// Attempt to subtract two [`BlockMtp`]s, returning `None` in case of overflow. + #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(BlockMtpInterval) } /// Attempt to add an interval to this [`BlockMtp`], returning `None` in case of overflow. + #[must_use] pub fn checked_add(self, other: BlockMtpInterval) -> Option { self.0.checked_add(other.0).map(Self) } @@ -308,9 +314,11 @@ impl BlockMtpInterval { } /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` in case of overflow. + #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } /// Attempt to add two [`BlockMtpInterval`]s, returning `None` in case of overflow. + #[must_use] pub fn checked_add(self, other: Self) -> Option { self.0.checked_add(other.0).map(Self) } } diff --git a/units/src/fee.rs b/units/src/fee.rs index 09bccb7414..8248a9957f 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -161,6 +161,7 @@ impl FeeRate { /// enough instead of falling short if rounded down. /// /// Returns [`None`] if overflow occurred. + #[must_use] pub const fn checked_mul_by_weight(self, weight: Weight) -> Option { let wu = weight.to_wu(); if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { @@ -348,6 +349,7 @@ impl Weight { /// enough instead of falling short if rounded down. /// /// Returns [`None`] if overflow occurred. + #[must_use] pub const fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { fee_rate.checked_mul_by_weight(self) } From 6cb4e298c8a7496f4b12b34a6c524db18d56d949 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 9 Jun 2025 00:46:17 +1000 Subject: [PATCH 081/857] Remove _all_ the trailing whitespace Recently we tried to make the rustfmt bot remove trailing whitespace but wrote the `sed` command incorrectly - it only removes a single character. Tested by running the new command on #4600. --- .github/workflows/cron-weekly-rustfmt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cron-weekly-rustfmt.yml b/.github/workflows/cron-weekly-rustfmt.yml index ba11521049..046ba8fe3f 100644 --- a/.github/workflows/cron-weekly-rustfmt.yml +++ b/.github/workflows/cron-weekly-rustfmt.yml @@ -14,7 +14,7 @@ jobs: components: rustfmt - name: Run Nightly rustfmt # Run the formatter and manually remove trailing whitespace. - run: cargo +nightly fmt && find . -type f -name '*.rs' -exec sed -i 's/ $//' {} \; + run: cargo +nightly fmt && git ls-files -- '*.rs' -z | xargs sed -E -i'' -e 's/[[:space:]]+$//' - name: Get the current date run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - name: Create Pull Request From 8e60711265c1db4e68f280b0331b885dabf5b57b Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 9 Jun 2025 09:31:55 +0100 Subject: [PATCH 082/857] Use the anonymous lifetime for paths New clippy lint in rustc nightly "lifetime flowing from input to output with different syntax can be confusing". Apply the suggested fix and use the anonymous lifetime for paths. --- bitcoin/src/bip32.rs | 6 +++--- bitcoin/src/blockdata/script/borrowed.rs | 8 ++++---- bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/taproot/mod.rs | 4 ++-- io/src/lib.rs | 2 +- primitives/src/witness.rs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index e6d9621b1e..c1bff91705 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -416,17 +416,17 @@ impl DerivationPath { /// Get an [Iterator] over the children of this [DerivationPath] /// starting with the given [ChildNumber]. - pub fn children_from(&self, cn: ChildNumber) -> DerivationPathIterator { + pub fn children_from(&self, cn: ChildNumber) -> DerivationPathIterator<'_> { DerivationPathIterator::start_from(self, cn) } /// Get an [Iterator] over the unhardened children of this [DerivationPath]. - pub fn normal_children(&self) -> DerivationPathIterator { + pub fn normal_children(&self) -> DerivationPathIterator<'_> { DerivationPathIterator::start_from(self, ChildNumber::Normal { index: 0 }) } /// Get an [Iterator] over the hardened children of this [DerivationPath]. - pub fn hardened_children(&self) -> DerivationPathIterator { + pub fn hardened_children(&self) -> DerivationPathIterator<'_> { DerivationPathIterator::start_from(self, ChildNumber::Hardened { index: 0 }) } diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index a6b36b1988..6164c0a9c4 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -331,7 +331,7 @@ crate::internal_macros::define_extension_trait! { /// /// To force minimal pushes, use [`instructions_minimal`](Self::instructions_minimal). #[inline] - fn instructions(&self) -> Instructions { + fn instructions(&self) -> Instructions<'_> { Instructions { data: self.as_bytes().iter(), enforce_minimal: false } } @@ -340,7 +340,7 @@ crate::internal_macros::define_extension_trait! { /// This is similar to [`instructions`](Self::instructions) but an error is returned if a push /// is not minimal. #[inline] - fn instructions_minimal(&self) -> Instructions { + fn instructions_minimal(&self) -> Instructions<'_> { Instructions { data: self.as_bytes().iter(), enforce_minimal: true } } @@ -352,7 +352,7 @@ crate::internal_macros::define_extension_trait! { /// /// To force minimal pushes, use [`Self::instruction_indices_minimal`]. #[inline] - fn instruction_indices(&self) -> InstructionIndices { + fn instruction_indices(&self) -> InstructionIndices<'_> { InstructionIndices::from_instructions(self.instructions()) } @@ -361,7 +361,7 @@ crate::internal_macros::define_extension_trait! { /// This is similar to [`instruction_indices`](Self::instruction_indices) but an error is /// returned if a push is not minimal. #[inline] - fn instruction_indices_minimal(&self) -> InstructionIndices { + fn instruction_indices_minimal(&self) -> InstructionIndices<'_> { InstructionIndices::from_instructions(self.instructions_minimal()) } diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 6182308f59..a07a82e995 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -404,7 +404,7 @@ impl TransactionExt for Transaction { fn is_lock_time_enabled(&self) -> bool { self.input.iter().any(|i| i.enables_lock_time()) } - fn script_pubkey_lens(&self) -> TxOutToScriptPubkeyLengthIter { + fn script_pubkey_lens(&self) -> TxOutToScriptPubkeyLengthIter<'_> { TxOutToScriptPubkeyLengthIter { inner: self.output.iter() } } diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index 723f61a87c..f69434d219 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -779,7 +779,7 @@ impl TapTree { /// Returns [`TapTreeIter<'_>`] iterator for a Taproot script tree, operating in DFS order over /// tree [`ScriptLeaf`]s. - pub fn script_leaves(&self) -> ScriptLeaves { ScriptLeaves { leaf_iter: self.0.leaf_nodes() } } + pub fn script_leaves(&self) -> ScriptLeaves<'_> { ScriptLeaves { leaf_iter: self.0.leaf_nodes() } } /// Returns the root [`TapNodeHash`] of this tree. pub fn root_hash(&self) -> TapNodeHash { self.0.hash } @@ -951,7 +951,7 @@ impl NodeInfo { } /// Creates an iterator over all leaves (including hidden leaves) in the tree. - pub fn leaf_nodes(&self) -> LeafNodes { LeafNodes { leaf_iter: self.leaves.iter() } } + pub fn leaf_nodes(&self) -> LeafNodes<'_> { LeafNodes { leaf_iter: self.leaves.iter() } } /// Returns the root [`TapNodeHash`] of this node info. pub fn node_hash(&self) -> TapNodeHash { self.hash } diff --git a/io/src/lib.rs b/io/src/lib.rs index e5bf1e1eb4..7e2bbb4427 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -85,7 +85,7 @@ pub trait Read { /// Constructs a new adapter which will read at most `limit` bytes. #[inline] - fn take(&mut self, limit: u64) -> Take { Take { reader: self, remaining: limit } } + fn take(&mut self, limit: u64) -> Take<'_, Self> { Take { reader: self, remaining: limit } } /// Attempts to read up to limit bytes from the reader, allocating space in `buf` as needed. /// diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs index 78bb13d8d0..02f9c7a78e 100644 --- a/primitives/src/witness.rs +++ b/primitives/src/witness.rs @@ -111,7 +111,7 @@ impl Witness { /// Returns a struct implementing [`Iterator`]. #[must_use = "iterators are lazy and do nothing unless consumed"] #[inline] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_> { Iter { inner: self.content.as_slice(), indices_start: self.indices_start, current_index: 0 } } From 69ce8f448b7f786f16449a261e09e75c918f7dbb Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 9 Jun 2025 09:35:44 +0100 Subject: [PATCH 083/857] Remove unneeded return statement New clipply lint in rustc nightly "unneeded `return` statement". Remove it. --- bitcoin/src/blockdata/transaction.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index a07a82e995..f169f4168a 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -517,11 +517,11 @@ impl TransactionExtPriv for Transaction { 1 } else if witness_program.is_p2wsh() { // Treat the last item of the witness as the witnessScript - return witness + witness .last() .map(Script::from_bytes) .map(|s| s.count_sigops()) - .unwrap_or(0); + .unwrap_or(0) } else { 0 } From 47c07c39fb2af99c348124d45a3cb8f92deb60dd Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Mon, 9 Jun 2025 09:38:36 +0100 Subject: [PATCH 084/857] Manual update to rustc (to nightly-2025-06-06) Automated daily update failed due to the new lints. Update the nightly version now lints are fixed. --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index 0ed7b6b402..e1c42351ed 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-05-23 +nightly-2025-06-06 From b843f1356ddfb2f23e6715708f99d40b82dce17a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 9 Jun 2025 00:29:15 +1000 Subject: [PATCH 085/857] units: Access with getters instead of inner field The `block` module does not follow the `encapsulate` pattern but we can still use the getters instead of accessing the inner field directly. Refactor, no logic change. --- units/src/block.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/units/src/block.rs b/units/src/block.rs index c4a02cd9a8..7d453d6a85 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -90,13 +90,13 @@ impl BlockHeight { /// Attempt to subtract two [`BlockHeight`]s, returning `None` in case of overflow. #[must_use] pub fn checked_sub(self, other: Self) -> Option { - self.0.checked_sub(other.0).map(BlockHeightInterval) + self.to_u32().checked_sub(other.to_u32()).map(BlockHeightInterval) } /// Attempt to add an interval to this [`BlockHeight`], returning `None` in case of overflow. #[must_use] pub fn checked_add(self, other: BlockHeightInterval) -> Option { - self.0.checked_add(other.0).map(Self) + self.to_u32().checked_add(other.to_u32()).map(Self) } } @@ -150,11 +150,15 @@ impl BlockHeightInterval { /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` in case of overflow. #[must_use] - pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } + pub fn checked_sub(self, other: Self) -> Option { + self.to_u32().checked_sub(other.to_u32()).map(Self) + } /// Attempt to add two [`BlockHeightInterval`]s, returning `None` in case of overflow. #[must_use] - pub fn checked_add(self, other: Self) -> Option { self.0.checked_add(other.0).map(Self) } + pub fn checked_add(self, other: Self) -> Option { + self.to_u32().checked_add(other.to_u32()).map(Self) + } } impl From for BlockHeightInterval { @@ -223,13 +227,13 @@ impl BlockMtp { /// Attempt to subtract two [`BlockMtp`]s, returning `None` in case of overflow. #[must_use] pub fn checked_sub(self, other: Self) -> Option { - self.0.checked_sub(other.0).map(BlockMtpInterval) + self.to_u32().checked_sub(other.to_u32()).map(BlockMtpInterval) } /// Attempt to add an interval to this [`BlockMtp`], returning `None` in case of overflow. #[must_use] pub fn checked_add(self, other: BlockMtpInterval) -> Option { - self.0.checked_add(other.0).map(Self) + self.to_u32().checked_add(other.to_u32()).map(Self) } } @@ -315,11 +319,15 @@ impl BlockMtpInterval { /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` in case of overflow. #[must_use] - pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } + pub fn checked_sub(self, other: Self) -> Option { + self.to_u32().checked_sub(other.to_u32()).map(Self) + } /// Attempt to add two [`BlockMtpInterval`]s, returning `None` in case of overflow. #[must_use] - pub fn checked_add(self, other: Self) -> Option { self.0.checked_add(other.0).map(Self) } + pub fn checked_add(self, other: Self) -> Option { + self.to_u32().checked_add(other.to_u32()).map(Self) + } } impl From for BlockMtpInterval { @@ -458,7 +466,7 @@ crate::internal_macros::impl_sub_assign!(BlockMtpInterval); impl core::iter::Sum for BlockHeightInterval { fn sum>(iter: I) -> Self { - let sum = iter.map(|interval| interval.0).sum(); + let sum = iter.map(BlockHeightInterval::to_u32).sum(); BlockHeightInterval::from_u32(sum) } } @@ -468,14 +476,14 @@ impl<'a> core::iter::Sum<&'a BlockHeightInterval> for BlockHeightInterval { where I: Iterator, { - let sum = iter.map(|interval| interval.0).sum(); + let sum = iter.map(|interval| interval.to_u32()).sum(); BlockHeightInterval::from_u32(sum) } } impl core::iter::Sum for BlockMtpInterval { fn sum>(iter: I) -> Self { - let sum = iter.map(|interval| interval.0).sum(); + let sum = iter.map(BlockMtpInterval::to_u32).sum(); BlockMtpInterval::from_u32(sum) } } @@ -485,7 +493,7 @@ impl<'a> core::iter::Sum<&'a BlockMtpInterval> for BlockMtpInterval { where I: Iterator, { - let sum = iter.map(|interval| interval.0).sum(); + let sum = iter.map(|interval| interval.to_u32()).sum(); BlockMtpInterval::from_u32(sum) } } From 02b523a8ada3e1bc9e78d5c011e0fd98603d5028 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 7 Jun 2025 14:44:51 +0100 Subject: [PATCH 086/857] Remove whitespace from encapsulate module Whitespace here is unnecessary. Whitespace only, no logic change. --- units/src/weight.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/units/src/weight.rs b/units/src/weight.rs index 6649b4d641..6b4607eacd 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -16,7 +16,6 @@ use crate::CheckedSum; pub const WITNESS_SCALE_FACTOR: usize = 4; mod encapsulate { - /// The weight of a transaction or block. /// /// This is an integer newtype representing [`Weight`] in `wu`. It provides protection From c87f7292beb65f96413124a611a5b59276ceb1e7 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 7 Jun 2025 14:46:48 +0100 Subject: [PATCH 087/857] Fix rustdocs on Weight There is no point linking to `Weight` in the rustdocs of `Weight`. Also `wu` does not exist in this context, prefer 'weight units'. --- units/src/weight.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/weight.rs b/units/src/weight.rs index 6b4607eacd..c59c183932 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -18,7 +18,7 @@ pub const WITNESS_SCALE_FACTOR: usize = 4; mod encapsulate { /// The weight of a transaction or block. /// - /// This is an integer newtype representing [`Weight`] in `wu`. It provides protection + /// This is an integer newtype representing weight in weight units. It provides protection /// against mixing up types as well as basic formatting features. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Weight(u64); From 153a6a2f3cff89f5545042868b4c804cd19382e3 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 7 Jun 2025 14:58:11 +0100 Subject: [PATCH 088/857] Make Weight docs uniform with FeeRate --- units/src/weight.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/units/src/weight.rs b/units/src/weight.rs index c59c183932..31da7274c7 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -19,7 +19,7 @@ mod encapsulate { /// The weight of a transaction or block. /// /// This is an integer newtype representing weight in weight units. It provides protection - /// against mixing up types as well as basic formatting features. + /// against mixing up the types, conversion functions, and basic formatting. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Weight(u64); @@ -37,7 +37,7 @@ mod encapsulate { pub use encapsulate::Weight; impl Weight { - /// 0 wu. + /// Zero weight units (wu). /// /// Equivalent to [`MIN`](Self::MIN), may better express intent in some contexts. pub const ZERO: Weight = Weight::from_wu(0); From 7fbe07a6e0b3e398aca845d64ec86f3f0068edf4 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 7 Jun 2025 15:36:28 +0100 Subject: [PATCH 089/857] Use uniform docs for overflow Trivial change but make all the docs (rustdocs and code comments) use the same phrase when describing overflow. --- units/src/block.rs | 16 ++++++++-------- units/src/fee_rate/mod.rs | 19 +++++++++---------- units/src/locktime/absolute.rs | 6 +++--- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/units/src/block.rs b/units/src/block.rs index c4a02cd9a8..c7e61ce80b 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -87,13 +87,13 @@ impl BlockHeight { /// Returns block height as a `u32`. pub const fn to_u32(self) -> u32 { self.0 } - /// Attempt to subtract two [`BlockHeight`]s, returning `None` in case of overflow. + /// Attempt to subtract two [`BlockHeight`]s, returning `None` if overflow occurred. #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(BlockHeightInterval) } - /// Attempt to add an interval to this [`BlockHeight`], returning `None` in case of overflow. + /// Attempt to add an interval to this [`BlockHeight`], returning `None` if overflow occurred. #[must_use] pub fn checked_add(self, other: BlockHeightInterval) -> Option { self.0.checked_add(other.0).map(Self) @@ -148,11 +148,11 @@ impl BlockHeightInterval { /// Returns block interval as a `u32`. pub const fn to_u32(self) -> u32 { self.0 } - /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` in case of overflow. + /// Attempt to subtract two [`BlockHeightInterval`]s, returning `None` if overflow occurred. #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } - /// Attempt to add two [`BlockHeightInterval`]s, returning `None` in case of overflow. + /// Attempt to add two [`BlockHeightInterval`]s, returning `None` if overflow occurred. #[must_use] pub fn checked_add(self, other: Self) -> Option { self.0.checked_add(other.0).map(Self) } } @@ -220,13 +220,13 @@ impl BlockMtp { Self::from_u32(u32::from(timestamps[5])) } - /// Attempt to subtract two [`BlockMtp`]s, returning `None` in case of overflow. + /// Attempt to subtract two [`BlockMtp`]s, returning `None` if overflow occurred. #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(BlockMtpInterval) } - /// Attempt to add an interval to this [`BlockMtp`], returning `None` in case of overflow. + /// Attempt to add an interval to this [`BlockMtp`], returning `None` if overflow occurred. #[must_use] pub fn checked_add(self, other: BlockMtpInterval) -> Option { self.0.checked_add(other.0).map(Self) @@ -313,11 +313,11 @@ impl BlockMtpInterval { relative::NumberOf512Seconds::from_seconds_ceil(self.to_u32()) } - /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` in case of overflow. + /// Attempt to subtract two [`BlockMtpInterval`]s, returning `None` if overflow occurred. #[must_use] pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } - /// Attempt to add two [`BlockMtpInterval`]s, returning `None` in case of overflow. + /// Attempt to add two [`BlockMtpInterval`]s, returning `None` if overflow occurred. #[must_use] pub fn checked_add(self, other: Self) -> Option { self.0.checked_add(other.0).map(Self) } } diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index c2ee6f4b91..f0db11cf06 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -52,7 +52,8 @@ impl FeeRate { /// The fee rate used to compute dust amount. pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); - /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. + /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units, + /// returning `None` if overflow occurred. pub const fn from_sat_per_kwu(sat_kwu: u64) -> Option { // No `map()` in const context. match sat_kwu.checked_mul(4_000) { @@ -61,11 +62,8 @@ impl FeeRate { } } - /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. - /// - /// # Errors - /// - /// Returns [`None`] on arithmetic overflow. + /// Constructs a new [`FeeRate`] from satoshis per virtual bytes, + /// returning `None` if overflow occurred. pub const fn from_sat_per_vb(sat_vb: u64) -> Option { // No `map()` in const context. match sat_vb.checked_mul(1_000_000) { @@ -80,7 +78,8 @@ impl FeeRate { FeeRate::from_sat_per_mvb(sat_vb * 1_000_000) } - /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). + /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes), + /// returning `None` if overflow occurred. pub const fn from_sat_per_kvb(sat_kvb: u64) -> Option { // No `map()` in const context. match sat_kvb.checked_mul(1_000) { @@ -109,7 +108,7 @@ impl FeeRate { /// Checked multiplication. /// - /// Computes `self * rhs` returning [`None`] if overflow occurred. + /// Computes `self * rhs`, returning [`None`] if overflow occurred. #[must_use] pub const fn checked_mul(self, rhs: u64) -> Option { // No `map()` in const context. @@ -133,7 +132,7 @@ impl FeeRate { /// Checked addition. /// - /// Computes `self + rhs` returning [`None`] if overflow occurred. + /// Computes `self + rhs` returning [`None`] is case of overflow. #[must_use] pub const fn checked_add(self, rhs: FeeRate) -> Option { // No `map()` in const context. @@ -145,7 +144,7 @@ impl FeeRate { /// Checked subtraction. /// - /// Computes `self - rhs` returning [`None`] if overflow occurred. + /// Computes `self - rhs`, returning [`None`] if overflow occurred. #[must_use] pub const fn checked_sub(self, rhs: FeeRate) -> Option { // No `map()` in const context. diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index cfbce396b1..73102af8d2 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -114,7 +114,7 @@ impl fmt::Display for ParseHeightError { #[cfg(feature = "std")] impl std::error::Error for ParseHeightError { - // To be consistent with `write_err` we need to **not** return source in case of overflow + // To be consistent with `write_err` we need to **not** return source if overflow occurred fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.0.source() } } @@ -239,7 +239,7 @@ impl fmt::Display for ParseTimeError { #[cfg(feature = "std")] impl std::error::Error for ParseTimeError { - // To be consistent with `write_err` we need to **not** return source in case of overflow + // To be consistent with `write_err` we need to **not** return source if overflow occurred fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.0.source() } } @@ -398,7 +398,7 @@ impl ParseError { } } - // To be consistent with `write_err` we need to **not** return source in case of overflow + // To be consistent with `write_err` we need to **not** return source if overflow occurred #[cfg(feature = "std")] fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use core::num::IntErrorKind; From c1a760bf603e49931425a1b6a6ba2b8450c8da11 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 10 Jun 2025 09:30:56 +1000 Subject: [PATCH 090/857] units: Use singular in rustdoc Satoshis per virtual byte is grammatically better than satoshis per virtual bytes - I think. --- units/src/fee_rate/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index f0db11cf06..f2ba948524 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -62,7 +62,7 @@ impl FeeRate { } } - /// Constructs a new [`FeeRate`] from satoshis per virtual bytes, + /// Constructs a new [`FeeRate`] from satoshis per virtual byte, /// returning `None` if overflow occurred. pub const fn from_sat_per_vb(sat_vb: u64) -> Option { // No `map()` in const context. From 6ed3fd6234a6d9e44d2cf187108cc22955471d27 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 10 Jun 2025 09:32:27 +1000 Subject: [PATCH 091/857] Add fee rate constructors that take Amount as arg Some users may find it more ergonomic to pass in an `Amount` when constructing fee rates. Also the strong type adds some semantic meaning as well as imposes the `Amount::MAX` limit. Add an equivalent constructor for each of the existing ones that uses an argument of type `Amount` instead of `u64` sats. --- units/src/fee_rate/mod.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index f2ba948524..75c516ea5b 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -11,6 +11,10 @@ use core::ops; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; +use NumOpResult as R; + +use crate::{Amount,MathOp, NumOpError as E, NumOpResult}; + mod encapsulate { /// Fee rate. /// @@ -62,6 +66,15 @@ impl FeeRate { } } + /// Constructs a new [`FeeRate`] from amount per 1000 weight units. + pub const fn from_per_kwu(rate: Amount) -> NumOpResult { + // No `map()` in const context. + match rate.checked_mul(4_000) { + Some(per_mvb) => R::Valid(FeeRate::from_sat_per_mvb(per_mvb.to_sat())), + None => R::Error(E::while_doing(MathOp::Mul)), + } + } + /// Constructs a new [`FeeRate`] from satoshis per virtual byte, /// returning `None` if overflow occurred. pub const fn from_sat_per_vb(sat_vb: u64) -> Option { @@ -72,6 +85,15 @@ impl FeeRate { } } + /// Constructs a new [`FeeRate`] from amount per virtual byte. + pub const fn from_per_vb(rate: Amount) -> NumOpResult { + // No `map()` in const context. + match rate.checked_mul(1_000_000) { + Some(per_mvb) => R::Valid(FeeRate::from_sat_per_mvb(per_mvb.to_sat())), + None => R::Error(E::while_doing(MathOp::Mul)), + } + } + /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. pub const fn from_sat_per_vb_u32(sat_vb: u32) -> Self { let sat_vb = sat_vb as u64; // No `Into` in const context. @@ -88,6 +110,15 @@ impl FeeRate { } } + /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). + pub const fn from_per_kvb(rate: Amount) -> NumOpResult { + // No `map()` in const context. + match rate.checked_mul(1_000) { + Some(per_mvb) => R::Valid(FeeRate::from_sat_per_mvb(per_mvb.to_sat())), + None => R::Error(E::while_doing(MathOp::Mul)), + } + } + /// Converts to sat/kwu rounding down. pub const fn to_sat_per_kwu_floor(self) -> u64 { self.to_sat_per_mvb() / 4_000 } From c736e73ae020f80a29bf6dce7d6b7741df42e679 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 10:57:03 +1000 Subject: [PATCH 092/857] Add unwrap_or and unwrap_or_else to NumOpResult Two useful combinators, add them. I copied the function signature and docs from stdlib and wrote the functions myself - thereby operating within licensing requirements. --- units/src/result.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/units/src/result.rs b/units/src/result.rs index c64ab5cbe3..a6619ac687 100644 --- a/units/src/result.rs +++ b/units/src/result.rs @@ -142,6 +142,32 @@ impl NumOpResult { } } + /// Returns the contained Some value or a provided default. + /// + /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing the result of a + /// function call, it is recommended to use `unwrap_or_else`, which is lazily evaluated. + #[inline] + #[track_caller] + pub fn unwrap_or(self, default: T) -> T { + match self { + R::Valid(x) => x, + R::Error(_) => default, + } + } + + /// Returns the contained `Some` value or computes it from a closure. + #[inline] + #[track_caller] + pub fn unwrap_or_else(self, f: F) -> T + where + F: FnOnce() -> T, + { + match self { + R::Valid(x) => x, + R::Error(_) => f(), + } + } + /// Converts this `NumOpResult` to an `Option`. #[inline] pub fn ok(self) -> Option { From e7c90c57e7b5ee20a2c523706cc4ea9957594857 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 10:58:50 +1000 Subject: [PATCH 093/857] Remove reachable unreachable call in psbt A bunch of changes have been implemented lately in the fee calculation logic. As a result of this a at once time `unreachable` statement is now reachable - bad rust-bitcoin devs, no biscuit. Saturate to `FeeRate::MAX` when calculating the fee rate, check against the limit arg, and win. Co-developed-by: Andrew Poelstra --- bitcoin/src/psbt/mod.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 40153c4609..20c2c6c04c 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -20,7 +20,6 @@ use std::collections::{HashMap, HashSet}; use internals::write_err; use secp256k1::{Keypair, Message, Secp256k1, Signing, Verification}; -use units::NumOpResult; use crate::bip32::{self, DerivationPath, KeySource, Xpriv, Xpub}; use crate::crypto::key::{PrivateKey, PublicKey}; @@ -206,18 +205,12 @@ impl Psbt { // Note: Move prevents usage of &self from now on. let tx = self.internal_extract_tx(); - // Now that the extracted Transaction is made, decide how to return it. - match fee / tx.weight() { - NumOpResult::Valid(fee_rate) => { - // Prefer to return an AbsurdFeeRate error when both trigger. - if fee_rate > max_fee_rate { - return Err(ExtractTxError::AbsurdFeeRate { fee_rate, tx }); - } - } - NumOpResult::Error(_) => unreachable!("weight() is always non-zero"), + let fee_rate = (fee / tx.weight()).unwrap_or(FeeRate::MAX); + if fee_rate > max_fee_rate { + Err(ExtractTxError::AbsurdFeeRate { fee_rate, tx }) + } else { + Ok(tx) } - - Ok(tx) } /// Combines this [`Psbt`] with `other` PSBT as described by BIP 174. From e17c391a3c385802ba5fb203c68541e23b68e494 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 10:16:29 +1000 Subject: [PATCH 094/857] Inline checked div functions back into unsigned module A while back we move all the 'fee' stuff into a separate module because I thought it would help with clarity - I was wrong. Move the checked div functions back into the `unsigned` module on the main `Amount` impl block. Internal change only - code move. --- units/src/amount/unsigned.rs | 101 ++++++++++++++++++++++++++++++++++ units/src/fee.rs | 102 ----------------------------------- 2 files changed, 101 insertions(+), 102 deletions(-) diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 33c97b4fc3..bbc126f91b 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -15,6 +15,7 @@ use super::{ parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle, OutOfRangeError, ParseAmountError, ParseError, SignedAmount, }; +use crate::{FeeRate, Weight}; mod encapsulate { use super::OutOfRangeError; @@ -402,6 +403,106 @@ impl Amount { SignedAmount::from_sat(self.to_sat() as i64) // Cast ok, signed amount and amount share positive range. .expect("range of Amount is within range of SignedAmount") } + + /// Checked weight floor division. + /// + /// Be aware that integer division loses the remainder if no exact division + /// can be made. See also [`Self::checked_div_by_weight_ceil`]. + /// + /// Returns [`None`] if overflow occurred. + #[must_use] + pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option { + let wu = weight.to_wu(); + if wu == 0 { + return None; + } + + // Mul by 1,000 because we use per/kwu. + match self.to_sat().checked_mul(1_000) { + Some(sats) => { + let fee_rate = sats / wu; + FeeRate::from_sat_per_kwu(fee_rate) + } + None => None, + } + } + + /// Checked weight ceiling division. + /// + /// Be aware that integer division loses the remainder if no exact division + /// can be made. This method rounds up ensuring the transaction fee rate is + /// sufficient. See also [`Self::checked_div_by_weight_floor`]. + /// + /// Returns [`None`] if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::{amount, Amount, FeeRate, Weight}; + /// let amount = Amount::from_sat(10)?; + /// let weight = Weight::from_wu(300); + /// let fee_rate = amount.checked_div_by_weight_ceil(weight); + /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34)); + /// # Ok::<_, amount::OutOfRangeError>(()) + /// ``` + #[must_use] + pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { + let wu = weight.to_wu(); + if wu == 0 { + return None; + } + + // Mul by 1,000 because we use per/kwu. + if let Some(sats) = self.to_sat().checked_mul(1_000) { + // No need to used checked arithmetic because wu is non-zero. + if let Some(bump) = sats.checked_add(wu - 1) { + let fee_rate = bump / wu; + return FeeRate::from_sat_per_kwu(fee_rate); + } + } + None + } + + /// Checked fee rate floor division. + /// + /// Computes the maximum weight that would result in a fee less than or equal to this amount + /// at the given `fee_rate`. Uses floor division to ensure the resulting weight doesn't cause + /// the fee to exceed the amount. + /// + /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. + #[must_use] + pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { + if let Some(msats) = self.to_sat().checked_mul(1000) { + if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { + return Some(Weight::from_wu(wu)); + } + } + None + } + + /// Checked fee rate ceiling division. + /// + /// Computes the minimum weight that would result in a fee greater than or equal to this amount + /// at the given `fee_rate`. Uses ceiling division to ensure the resulting weight is sufficient. + /// + /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. + #[must_use] + pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { + // Use ceil because result is used as the divisor. + let rate = fee_rate.to_sat_per_kwu_ceil(); + if rate == 0 { + return None; + } + + if let Some(msats) = self.to_sat().checked_mul(1000) { + // No need to used checked arithmetic because rate is non-zero. + if let Some(bump) = msats.checked_add(rate - 1) { + let wu = bump / rate; + return Some(Weight::from_wu(wu)); + } + } + None + } } impl default::Default for Amount { diff --git a/units/src/fee.rs b/units/src/fee.rs index 8248a9957f..1354fc8487 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -17,108 +17,6 @@ use NumOpResult as R; use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight}; -impl Amount { - /// Checked weight floor division. - /// - /// Be aware that integer division loses the remainder if no exact division - /// can be made. See also [`Self::checked_div_by_weight_ceil`]. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option { - let wu = weight.to_wu(); - if wu == 0 { - return None; - } - - // Mul by 1,000 because we use per/kwu. - match self.to_sat().checked_mul(1_000) { - Some(sats) => { - let fee_rate = sats / wu; - FeeRate::from_sat_per_kwu(fee_rate) - } - None => None, - } - } - - /// Checked weight ceiling division. - /// - /// Be aware that integer division loses the remainder if no exact division - /// can be made. This method rounds up ensuring the transaction fee rate is - /// sufficient. See also [`Self::checked_div_by_weight_floor`]. - /// - /// Returns [`None`] if overflow occurred. - /// - /// # Examples - /// - /// ``` - /// # use bitcoin_units::{amount, Amount, FeeRate, Weight}; - /// let amount = Amount::from_sat(10)?; - /// let weight = Weight::from_wu(300); - /// let fee_rate = amount.checked_div_by_weight_ceil(weight); - /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34)); - /// # Ok::<_, amount::OutOfRangeError>(()) - /// ``` - #[must_use] - pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { - let wu = weight.to_wu(); - if wu == 0 { - return None; - } - - // Mul by 1,000 because we use per/kwu. - if let Some(sats) = self.to_sat().checked_mul(1_000) { - // No need to used checked arithmetic because wu is non-zero. - if let Some(bump) = sats.checked_add(wu - 1) { - let fee_rate = bump / wu; - return FeeRate::from_sat_per_kwu(fee_rate); - } - } - None - } - - /// Checked fee rate floor division. - /// - /// Computes the maximum weight that would result in a fee less than or equal to this amount - /// at the given `fee_rate`. Uses floor division to ensure the resulting weight doesn't cause - /// the fee to exceed the amount. - /// - /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. - #[must_use] - pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { - if let Some(msats) = self.to_sat().checked_mul(1000) { - if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { - return Some(Weight::from_wu(wu)); - } - } - None - } - - /// Checked fee rate ceiling division. - /// - /// Computes the minimum weight that would result in a fee greater than or equal to this amount - /// at the given `fee_rate`. Uses ceiling division to ensure the resulting weight is sufficient. - /// - /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. - #[must_use] - pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { - // Use ceil because result is used as the divisor. - let rate = fee_rate.to_sat_per_kwu_ceil(); - if rate == 0 { - return None; - } - - if let Some(msats) = self.to_sat().checked_mul(1000) { - // No need to used checked arithmetic because rate is non-zero. - if let Some(bump) = msats.checked_add(rate - 1) { - let wu = bump / rate; - return Some(Weight::from_wu(wu)); - } - } - None - } -} - impl FeeRate { /// Calculates the fee by multiplying this fee rate by weight. /// From a8610a937bb5a2db129c779deacf3ade5bde12ab Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 10:20:05 +1000 Subject: [PATCH 095/857] Inline checked mul / to fee back into fee_rate module A while back we move all the 'fee' stuff into a separate module because I thought it would help with clarity - I was wrong. Move the checked mul and to fee functions back into the `fee_rate` module on the main `FeeRate` impl block. Internal change only - code move. --- units/src/fee.rs | 58 --------------------------------------- units/src/fee_rate/mod.rs | 58 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 59 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 1354fc8487..144ad0fd87 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -17,64 +17,6 @@ use NumOpResult as R; use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight}; -impl FeeRate { - /// Calculates the fee by multiplying this fee rate by weight. - /// - /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting - /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is - /// enough instead of falling short if rounded down. - /// - /// If the calculation would overflow we saturate to [`Amount::MAX`]. Since such a fee can never - /// be paid this is meaningful as an error case while still removing the possibility of silently - /// wrapping. - pub const fn to_fee(self, weight: Weight) -> Amount { - // No `unwrap_or()` in const context. - match self.checked_mul_by_weight(weight) { - Some(fee) => fee, - None => Amount::MAX, - } - } - - /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`] - /// if an overflow occurred. - /// - /// This is equivalent to `Self::checked_mul_by_weight()`. - #[must_use] - #[deprecated(since = "TBD", note = "use `to_fee()` instead")] - pub fn fee_wu(self, weight: Weight) -> Option { self.checked_mul_by_weight(weight) } - - /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`] - /// if an overflow occurred. - /// - /// This is equivalent to converting `vb` to [`Weight`] using [`Weight::from_vb`] and then calling - /// `Self::fee_wu(weight)`. - #[must_use] - #[deprecated(since = "TBD", note = "use Weight::from_vb and then `to_fee()` instead")] - pub fn fee_vb(self, vb: u64) -> Option { Weight::from_vb(vb).map(|w| self.to_fee(w)) } - - /// Checked weight multiplication. - /// - /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting - /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is - /// enough instead of falling short if rounded down. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn checked_mul_by_weight(self, weight: Weight) -> Option { - let wu = weight.to_wu(); - if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { - // Bump by 999 to do ceil division using kwu. - if let Some(bump) = fee_kwu.checked_add(999) { - let fee = bump / 1_000; - if let Ok(fee_amount) = Amount::from_sat(fee) { - return Some(fee_amount); - } - } - } - None - } -} - crate::internal_macros::impl_op_for_references! { impl ops::Mul for Weight { type Output = NumOpResult; diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 75c516ea5b..aec144041c 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -13,7 +13,7 @@ use arbitrary::{Arbitrary, Unstructured}; use NumOpResult as R; -use crate::{Amount,MathOp, NumOpError as E, NumOpResult}; +use crate::{Amount, MathOp, NumOpError as E, NumOpResult, Weight}; mod encapsulate { /// Fee rate. @@ -184,6 +184,62 @@ impl FeeRate { None => None, } } + + /// Calculates the fee by multiplying this fee rate by weight. + /// + /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting + /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is + /// enough instead of falling short if rounded down. + /// + /// If the calculation would overflow we saturate to [`Amount::MAX`]. Since such a fee can never + /// be paid this is meaningful as an error case while still removing the possibility of silently + /// wrapping. + pub const fn to_fee(self, weight: Weight) -> Amount { + // No `unwrap_or()` in const context. + match self.checked_mul_by_weight(weight) { + Some(fee) => fee, + None => Amount::MAX, + } + } + + /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`] + /// if an overflow occurred. + /// + /// This is equivalent to `Self::checked_mul_by_weight()`. + #[must_use] + #[deprecated(since = "TBD", note = "use `to_fee()` instead")] + pub fn fee_wu(self, weight: Weight) -> Option { self.checked_mul_by_weight(weight) } + + /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`] + /// if an overflow occurred. + /// + /// This is equivalent to converting `vb` to [`Weight`] using [`Weight::from_vb`] and then calling + /// `Self::fee_wu(weight)`. + #[must_use] + #[deprecated(since = "TBD", note = "use Weight::from_vb and then `to_fee()` instead")] + pub fn fee_vb(self, vb: u64) -> Option { Weight::from_vb(vb).map(|w| self.to_fee(w)) } + + /// Checked weight multiplication. + /// + /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting + /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is + /// enough instead of falling short if rounded down. + /// + /// Returns [`None`] if overflow occurred. + #[must_use] + pub const fn checked_mul_by_weight(self, weight: Weight) -> Option { + let wu = weight.to_wu(); + if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { + // Bump by 999 to do ceil division using kwu. + if let Some(bump) = fee_kwu.checked_add(999) { + let fee = bump / 1_000; + if let Ok(fee_amount) = Amount::from_sat(fee) { + return Some(fee_amount); + } + } + } + None + } } crate::internal_macros::impl_op_for_references! { From 251e6a85da1610bd3b62d686d51212cfb08a6e2c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 10:25:55 +1000 Subject: [PATCH 096/857] Inline checked mul function back into weight module A while back we move all the 'fee' stuff into a separate module because I thought it would help with clarity - I was wrong. Move the checked mul function back into the `weight` module on the main `Weight` impl block. Internal change only - code move. --- units/src/fee.rs | 14 -------------- units/src/weight.rs | 14 +++++++++++++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 144ad0fd87..76aa553093 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -181,20 +181,6 @@ crate::internal_macros::impl_op_for_references! { } } -impl Weight { - /// Checked fee rate multiplication. - /// - /// Computes the absolute fee amount for a given [`FeeRate`] at this weight. When the resulting - /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is - /// enough instead of falling short if rounded down. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { - fee_rate.checked_mul_by_weight(self) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/units/src/weight.rs b/units/src/weight.rs index 31da7274c7..5bf7004715 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -10,7 +10,7 @@ use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::CheckedSum; +use crate::{Amount, CheckedSum, FeeRate}; /// The factor that non-witness serialization data is multiplied by during weight calculation. pub const WITNESS_SCALE_FACTOR: usize = 4; @@ -162,6 +162,18 @@ impl Weight { None => None, } } + + /// Checked fee rate multiplication. + /// + /// Computes the absolute fee amount for a given [`FeeRate`] at this weight. When the resulting + /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is + /// enough instead of falling short if rounded down. + /// + /// Returns [`None`] if overflow occurred. + #[must_use] + pub const fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { + fee_rate.checked_mul_by_weight(self) + } } /// Alternative will display the unit. From 20c84ce444fe68577bf14842ebaffd796572d91f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 10:31:56 +1000 Subject: [PATCH 097/857] units: Make fee module public The `fee` module is now empty as far as API surface. It still holds the `core::ops` impls for fee calculation. It also does have useful rustdocs which are not currently visible online because module is private. Make the module public. Functionally all this does is provide a place for the module level docs under a discoverable name. Improve the docs by adding a bunch of links to fee related functions. --- units/src/fee.rs | 12 ++++++++++++ units/src/lib.rs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 76aa553093..008fd920b2 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -10,6 +10,18 @@ //! //! We provide `fee.checked_div_by_weight_ceil(weight)` to calculate a minimum threshold fee rate //! required to pay at least `fee` for transaction with `weight`. +//! +//! We support various `core::ops` traits all of which return [`NumOpResult`]. +//! +//! For specific methods see: +//! +//! * [`Amount::checked_div_by_weight_floor`] +//! * [`Amount::checked_div_by_weight_ceil`] +//! * [`Amount::checked_div_by_fee_rate_floor`] +//! * [`Amount::checked_div_by_fee_rate_ceil`] +//! * [`Weight::checked_mul_by_fee_rate`] +//! * [`FeeRate::checked_mul_by_weight`] +//! * [`FeeRate::to_fee`] use core::ops; diff --git a/units/src/lib.rs b/units/src/lib.rs index 6431202231..12c8186502 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -34,7 +34,6 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -mod fee; mod internal_macros; mod result; @@ -48,6 +47,7 @@ pub mod _export { pub mod amount; pub mod block; +pub mod fee; pub mod fee_rate; pub mod locktime; pub mod parse; From 4284deed29114c5e31ef7c29e28e352b860f74e7 Mon Sep 17 00:00:00 2001 From: vicjuma Date: Sat, 14 Jun 2025 01:42:01 +0300 Subject: [PATCH 098/857] DerivationPath: support 'h' in Display output for hardened components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aligns with ChildNumber’s format and improves consistency when debugging or comparing derivation paths. Resolves: #4618 --- bitcoin/src/bip32.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index c1bff91705..08466e3c82 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -482,11 +482,19 @@ impl fmt::Display for DerivationPath { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut iter = self.0.iter(); if let Some(first_element) = iter.next() { - write!(f, "{}", first_element)?; + if f.alternate() { + write!(f, "{:#}", first_element)?; + } else { + write!(f, "{}", first_element)?; + } } for cn in iter { f.write_str("/")?; - write!(f, "{}", cn)?; + if f.alternate() { + write!(f, "{:#}", cn)?; + } else { + write!(f, "{}", cn)?; + } } Ok(()) } @@ -1108,6 +1116,13 @@ mod tests { } } + #[test] + fn test_derivation_path_display() { + let path = DerivationPath::from_str("m/84'/0'/0'/0/0").unwrap(); + assert_eq!(format!("{}", path), "84'/0'/0'/0/0"); + assert_eq!(format!("{:#}", path), "84h/0h/0h/0/0"); + } + #[test] fn parse_derivation_path_out_of_range() { let invalid_path = "2147483648"; From 81dbfae0a8acf77bf7dce155872c7be828540573 Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 15 Jun 2025 01:46:36 +0000 Subject: [PATCH 099/857] 2025-06-15 automated rustfmt nightly --- bitcoin/src/blockdata/transaction.rs | 6 +----- bitcoin/src/psbt/mod.rs | 12 ++++++------ bitcoin/src/taproot/mod.rs | 4 +++- units/src/fee_rate/mod.rs | 1 - 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index f169f4168a..fca4351253 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -517,11 +517,7 @@ impl TransactionExtPriv for Transaction { 1 } else if witness_program.is_p2wsh() { // Treat the last item of the witness as the witnessScript - witness - .last() - .map(Script::from_bytes) - .map(|s| s.count_sigops()) - .unwrap_or(0) + witness.last().map(Script::from_bytes).map(|s| s.count_sigops()).unwrap_or(0) } else { 0 } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 20c2c6c04c..61f6b48415 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -891,11 +891,11 @@ impl GetKey for $map { KeyRequest::XOnlyPubkey(xonly) => { let pubkey_even = xonly.public_key(secp256k1::Parity::Even); let key = self.get(&pubkey_even).cloned(); - + if key.is_some() { return Ok(key); } - + let pubkey_odd = xonly.public_key(secp256k1::Parity::Odd); if let Some(priv_key) = self.get(&pubkey_odd).copied() { let negated_priv_key = priv_key.negate(); @@ -928,18 +928,18 @@ impl GetKey for $map { KeyRequest::XOnlyPubkey(xonly) => Ok(self.get(xonly).cloned()), KeyRequest::Pubkey(pk) => { let (xonly, parity) = pk.inner.x_only_public_key(); - + if let Some(mut priv_key) = self.get(&XOnlyPublicKey::from(xonly)).cloned() { let computed_pk = priv_key.public_key(&secp); let (_, computed_parity) = computed_pk.inner.x_only_public_key(); - + if computed_parity != parity { priv_key = priv_key.negate(); } - + return Ok(Some(priv_key)); } - + Ok(None) }, KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported), diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index f69434d219..5c284ce893 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -779,7 +779,9 @@ impl TapTree { /// Returns [`TapTreeIter<'_>`] iterator for a Taproot script tree, operating in DFS order over /// tree [`ScriptLeaf`]s. - pub fn script_leaves(&self) -> ScriptLeaves<'_> { ScriptLeaves { leaf_iter: self.0.leaf_nodes() } } + pub fn script_leaves(&self) -> ScriptLeaves<'_> { + ScriptLeaves { leaf_iter: self.0.leaf_nodes() } + } /// Returns the root [`TapNodeHash`] of this tree. pub fn root_hash(&self) -> TapNodeHash { self.0.hash } diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index aec144041c..6d9b76d93b 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -10,7 +10,6 @@ use core::ops; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; - use NumOpResult as R; use crate::{Amount, MathOp, NumOpError as E, NumOpResult, Weight}; From 75106e6d82eb8d9be5f30f944eca91f1c4b061ca Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 12 Jun 2025 11:17:32 +1000 Subject: [PATCH 100/857] Remove checked_ prefix from fee functions The `Amount` and `FeeRate` types are not simple int wrappers, as such we do not need to mimic the stdlib too closely. Having the `checked_` prefix to the functions that do fee calcualtions adds no additional meaning. Note that I'm about to change the return type to use `NumOpResult` further justifying this change. Note we leave the 'Checked foo' in the functions docs title because the functions are still checked. --- units/src/amount/tests.rs | 26 ++++++++++++------------ units/src/amount/unsigned.rs | 10 +++++----- units/src/fee.rs | 38 ++++++++++++++++++------------------ units/src/fee_rate/mod.rs | 6 +++--- units/src/weight.rs | 4 ++-- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 021fa13bc1..853370adc0 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -268,17 +268,17 @@ fn positive_sub() { #[test] fn amount_checked_div_by_weight_ceil() { let weight = Weight::from_kwu(1).unwrap(); - let fee_rate = sat(1).checked_div_by_weight_ceil(weight).unwrap(); + let fee_rate = sat(1).div_by_weight_ceil(weight).unwrap(); // 1 sats / 1,000 wu = 1 sats/kwu assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); let weight = Weight::from_wu(381); - let fee_rate = sat(329).checked_div_by_weight_ceil(weight).unwrap(); + let fee_rate = sat(329).div_by_weight_ceil(weight).unwrap(); // 329 sats / 381 wu = 863.5 sats/kwu // round up to 864 assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864).unwrap()); - let fee_rate = Amount::ONE_SAT.checked_div_by_weight_ceil(Weight::ZERO); + let fee_rate = Amount::ONE_SAT.div_by_weight_ceil(Weight::ZERO); assert!(fee_rate.is_none()); } @@ -286,17 +286,17 @@ fn amount_checked_div_by_weight_ceil() { #[test] fn amount_checked_div_by_weight_floor() { let weight = Weight::from_kwu(1).unwrap(); - let fee_rate = sat(1).checked_div_by_weight_floor(weight).unwrap(); + let fee_rate = sat(1).div_by_weight_floor(weight).unwrap(); // 1 sats / 1,000 wu = 1 sats/kwu assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); let weight = Weight::from_wu(381); - let fee_rate = sat(329).checked_div_by_weight_floor(weight).unwrap(); + let fee_rate = sat(329).div_by_weight_floor(weight).unwrap(); // 329 sats / 381 wu = 863.5 sats/kwu // round down to 863 assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863).unwrap()); - let fee_rate = Amount::ONE_SAT.checked_div_by_weight_floor(Weight::ZERO); + let fee_rate = Amount::ONE_SAT.div_by_weight_floor(Weight::ZERO); assert!(fee_rate.is_none()); } @@ -307,31 +307,31 @@ fn amount_checked_div_by_fee_rate() { let fee_rate = FeeRate::from_sat_per_kwu(2).unwrap(); // Test floor division - let weight = amount.checked_div_by_fee_rate_floor(fee_rate).unwrap(); + let weight = amount.div_by_fee_rate_floor(fee_rate).unwrap(); // 1000 sats / (2 sats/kwu) = 500,000 wu assert_eq!(weight, Weight::from_wu(500_000)); // Test ceiling division - let weight = amount.checked_div_by_fee_rate_ceil(fee_rate).unwrap(); + let weight = amount.div_by_fee_rate_ceil(fee_rate).unwrap(); assert_eq!(weight, Weight::from_wu(500_000)); // Same result for exact division // Test truncation behavior let amount = sat(1000); let fee_rate = FeeRate::from_sat_per_kwu(3).unwrap(); - let floor_weight = amount.checked_div_by_fee_rate_floor(fee_rate).unwrap(); - let ceil_weight = amount.checked_div_by_fee_rate_ceil(fee_rate).unwrap(); + let floor_weight = amount.div_by_fee_rate_floor(fee_rate).unwrap(); + let ceil_weight = amount.div_by_fee_rate_ceil(fee_rate).unwrap(); assert_eq!(floor_weight, Weight::from_wu(333_333)); assert_eq!(ceil_weight, Weight::from_wu(333_334)); // Test division by zero let zero_fee_rate = FeeRate::from_sat_per_kwu(0).unwrap(); - assert!(amount.checked_div_by_fee_rate_floor(zero_fee_rate).is_none()); - assert!(amount.checked_div_by_fee_rate_ceil(zero_fee_rate).is_none()); + assert!(amount.div_by_fee_rate_floor(zero_fee_rate).is_none()); + assert!(amount.div_by_fee_rate_ceil(zero_fee_rate).is_none()); // Test with maximum amount let max_amount = Amount::MAX; let small_fee_rate = FeeRate::from_sat_per_kwu(1).unwrap(); - let weight = max_amount.checked_div_by_fee_rate_floor(small_fee_rate).unwrap(); + let weight = max_amount.div_by_fee_rate_floor(small_fee_rate).unwrap(); // 21_000_000_0000_0000 sats / (1 sat/kwu) = 2_100_000_000_000_000_000 wu assert_eq!(weight, Weight::from_wu(2_100_000_000_000_000_000)); } diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index bbc126f91b..2e25eda848 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -411,7 +411,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred. #[must_use] - pub const fn checked_div_by_weight_floor(self, weight: Weight) -> Option { + pub const fn div_by_weight_floor(self, weight: Weight) -> Option { let wu = weight.to_wu(); if wu == 0 { return None; @@ -441,12 +441,12 @@ impl Amount { /// # use bitcoin_units::{amount, Amount, FeeRate, Weight}; /// let amount = Amount::from_sat(10)?; /// let weight = Weight::from_wu(300); - /// let fee_rate = amount.checked_div_by_weight_ceil(weight); + /// let fee_rate = amount.div_by_weight_ceil(weight); /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34)); /// # Ok::<_, amount::OutOfRangeError>(()) /// ``` #[must_use] - pub const fn checked_div_by_weight_ceil(self, weight: Weight) -> Option { + pub const fn div_by_weight_ceil(self, weight: Weight) -> Option { let wu = weight.to_wu(); if wu == 0 { return None; @@ -471,7 +471,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] - pub const fn checked_div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { + pub const fn div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { if let Some(msats) = self.to_sat().checked_mul(1000) { if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { return Some(Weight::from_wu(wu)); @@ -487,7 +487,7 @@ impl Amount { /// /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. #[must_use] - pub const fn checked_div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { + pub const fn div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { // Use ceil because result is used as the divisor. let rate = fee_rate.to_sat_per_kwu_ceil(); if rate == 0 { diff --git a/units/src/fee.rs b/units/src/fee.rs index 008fd920b2..b156cb694f 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -8,19 +8,19 @@ //! Either the weight or fee rate can be calculated if one knows the total fee and either of the //! other values. Note however that such calculations truncate (as for integer division). //! -//! We provide `fee.checked_div_by_weight_ceil(weight)` to calculate a minimum threshold fee rate +//! We provide `fee.div_by_weight_ceil(weight)` to calculate a minimum threshold fee rate //! required to pay at least `fee` for transaction with `weight`. //! //! We support various `core::ops` traits all of which return [`NumOpResult`]. //! //! For specific methods see: //! -//! * [`Amount::checked_div_by_weight_floor`] -//! * [`Amount::checked_div_by_weight_ceil`] -//! * [`Amount::checked_div_by_fee_rate_floor`] -//! * [`Amount::checked_div_by_fee_rate_ceil`] -//! * [`Weight::checked_mul_by_fee_rate`] -//! * [`FeeRate::checked_mul_by_weight`] +//! * [`Amount::div_by_weight_floor`] +//! * [`Amount::div_by_weight_ceil`] +//! * [`Amount::div_by_fee_rate_floor`] +//! * [`Amount::div_by_fee_rate_ceil`] +//! * [`Weight::mul_by_fee_rate`] +//! * [`FeeRate::mul_by_weight`] //! * [`FeeRate::to_fee`] use core::ops; @@ -33,7 +33,7 @@ crate::internal_macros::impl_op_for_references! { impl ops::Mul for Weight { type Output = NumOpResult; fn mul(self, rhs: FeeRate) -> Self::Output { - match rhs.checked_mul_by_weight(self) { + match rhs.mul_by_weight(self) { Some(amount) => R::Valid(amount), None => R::Error(E::while_doing(MathOp::Mul)), } @@ -73,7 +73,7 @@ crate::internal_macros::impl_op_for_references! { impl ops::Mul for FeeRate { type Output = NumOpResult; fn mul(self, rhs: Weight) -> Self::Output { - match self.checked_mul_by_weight(rhs) { + match self.mul_by_weight(rhs) { Some(amount) => R::Valid(amount), None => R::Error(E::while_doing(MathOp::Mul)), } @@ -114,7 +114,7 @@ crate::internal_macros::impl_op_for_references! { type Output = NumOpResult; fn div(self, rhs: Weight) -> Self::Output { - self.checked_div_by_weight_floor(rhs).valid_or_error(MathOp::Div) + self.div_by_weight_floor(rhs).valid_or_error(MathOp::Div) } } impl ops::Div for NumOpResult { @@ -155,7 +155,7 @@ crate::internal_macros::impl_op_for_references! { type Output = NumOpResult; fn div(self, rhs: FeeRate) -> Self::Output { - self.checked_div_by_fee_rate_floor(rhs).valid_or_error(MathOp::Div) + self.div_by_fee_rate_floor(rhs).valid_or_error(MathOp::Div) } } impl ops::Div for NumOpResult { @@ -211,25 +211,25 @@ mod tests { } #[test] - fn checked_weight_mul() { + fn weight_mul() { let weight = Weight::from_vb(10).unwrap(); let fee: Amount = FeeRate::from_sat_per_vb(10) .unwrap() - .checked_mul_by_weight(weight) + .mul_by_weight(weight) .expect("expected Amount"); assert_eq!(Amount::from_sat_u32(100), fee); - let fee = FeeRate::from_sat_per_kwu(10).unwrap().checked_mul_by_weight(Weight::MAX); + let fee = FeeRate::from_sat_per_kwu(10).unwrap().mul_by_weight(Weight::MAX); assert!(fee.is_none()); let weight = Weight::from_vb(3).unwrap(); let fee_rate = FeeRate::from_sat_per_vb(3).unwrap(); - let fee = fee_rate.checked_mul_by_weight(weight).unwrap(); + let fee = fee_rate.mul_by_weight(weight).unwrap(); assert_eq!(Amount::from_sat_u32(9), fee); let weight = Weight::from_wu(381); let fee_rate = FeeRate::from_sat_per_kwu(864).unwrap(); - let fee = weight.checked_mul_by_fee_rate(fee_rate).unwrap(); + let fee = weight.mul_by_fee_rate(fee_rate).unwrap(); // 381 * 0.864 yields 329.18. // The result is then rounded up to 330. assert_eq!(fee, Amount::from_sat_u32(330)); @@ -277,12 +277,12 @@ mod tests { assert_eq!(weight, Weight::from_wu(333_333)); // Verify that ceiling division gives different result - let ceil_weight = amount.checked_div_by_fee_rate_ceil(fee_rate).unwrap(); + let ceil_weight = amount.div_by_fee_rate_ceil(fee_rate).unwrap(); assert_eq!(ceil_weight, Weight::from_wu(333_334)); // Test that division by zero returns None let zero_rate = FeeRate::from_sat_per_kwu(0).unwrap(); - assert!(amount.checked_div_by_fee_rate_floor(zero_rate).is_none()); - assert!(amount.checked_div_by_fee_rate_ceil(zero_rate).is_none()); + assert!(amount.div_by_fee_rate_floor(zero_rate).is_none()); + assert!(amount.div_by_fee_rate_ceil(zero_rate).is_none()); } } diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index aec144041c..70e0e371e3 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -196,7 +196,7 @@ impl FeeRate { /// wrapping. pub const fn to_fee(self, weight: Weight) -> Amount { // No `unwrap_or()` in const context. - match self.checked_mul_by_weight(weight) { + match self.mul_by_weight(weight) { Some(fee) => fee, None => Amount::MAX, } @@ -208,7 +208,7 @@ impl FeeRate { /// This is equivalent to `Self::checked_mul_by_weight()`. #[must_use] #[deprecated(since = "TBD", note = "use `to_fee()` instead")] - pub fn fee_wu(self, weight: Weight) -> Option { self.checked_mul_by_weight(weight) } + pub fn fee_wu(self, weight: Weight) -> Option { self.mul_by_weight(weight) } /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`] /// if an overflow occurred. @@ -227,7 +227,7 @@ impl FeeRate { /// /// Returns [`None`] if overflow occurred. #[must_use] - pub const fn checked_mul_by_weight(self, weight: Weight) -> Option { + pub const fn mul_by_weight(self, weight: Weight) -> Option { let wu = weight.to_wu(); if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { // Bump by 999 to do ceil division using kwu. diff --git a/units/src/weight.rs b/units/src/weight.rs index 5bf7004715..0589cb0f71 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -171,8 +171,8 @@ impl Weight { /// /// Returns [`None`] if overflow occurred. #[must_use] - pub const fn checked_mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { - fee_rate.checked_mul_by_weight(self) + pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { + fee_rate.mul_by_weight(self) } } From 15065b78c782afecc86647283dbb646ddacf217e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 14 Jun 2025 07:32:44 +1000 Subject: [PATCH 101/857] Return NumOpResult when calculating fee on Amount Currently we call the `Amount` fee calculation functions `div_by_foo` and return an `Option` to indicate error. We have the `NumOpResult` type that better indicates the error case. Includes a bunch of changes to the `psbt` tests because extracting the transaction from a PSBT has a bunch of overflow paths that need testing caused by fee calculation. --- bitcoin/src/psbt/mod.rs | 49 ++++++++++----------- units/src/amount/tests.rs | 8 ++-- units/src/amount/unsigned.rs | 82 +++++++++++++++++------------------- units/src/fee.rs | 16 +++---- units/src/fee_rate/mod.rs | 1 - 5 files changed, 75 insertions(+), 81 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 20c2c6c04c..09d7f53538 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1348,17 +1348,6 @@ mod tests { use crate::witness::Witness; use crate::Sequence; - /// Fee rate in sat/kwu for a high-fee PSBT with an input=5_000_000_000_000, output=1000 - const ABSURD_FEE_RATE: FeeRate = match FeeRate::from_sat_per_kwu(15_060_240_960_843) { - Some(fee_rate) => fee_rate, - None => panic!("unreachable - no unwrap in Rust 1.63 in const"), - }; - const JUST_BELOW_ABSURD_FEE_RATE: FeeRate = match FeeRate::from_sat_per_kwu(15_060_240_960_842) - { - Some(fee_rate) => fee_rate, - None => panic!("unreachable - no unwrap in Rust 1.63 in const"), - }; - #[track_caller] pub fn hex_psbt(s: &str) -> Result { let r = Vec::from_hex(s); @@ -1442,31 +1431,43 @@ mod tests { #[test] fn psbt_high_fee_checks() { - let psbt = psbt_with_values(5_000_000_000_000, 1000); + let psbt = psbt_with_values(Amount::MAX.to_sat(), 1000); + + // We cannot create an expected fee rate to test against because `FeeRate::from_sat_per_mvb` is private. + // Large fee rate errors if we pass in 1 sat/vb so just use this to get the error fee rate returned. + let error_fee_rate = psbt + .clone() + .extract_tx_with_fee_rate_limit(FeeRate::from_sat_per_vb_u32(1)) + .map_err(|e| match e { + ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, + _ => panic!(""), + }) + .unwrap_err(); + + // In `internal_extract_tx_with_fee_rate_limit` when we do fee / weight + // we manually saturate to `FeeRate::MAX`. + assert!(psbt.clone().extract_tx_with_fee_rate_limit(FeeRate::MAX).is_ok()); + + // These error because the fee rate is above the limit as expected. assert_eq!( psbt.clone().extract_tx().map_err(|e| match e { ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, _ => panic!(""), }), - Err(ABSURD_FEE_RATE) + Err(error_fee_rate) ); assert_eq!( psbt.clone().extract_tx_fee_rate_limit().map_err(|e| match e { ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, _ => panic!(""), }), - Err(ABSURD_FEE_RATE) - ); - assert_eq!( - psbt.clone().extract_tx_with_fee_rate_limit(JUST_BELOW_ABSURD_FEE_RATE).map_err(|e| { - match e { - ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, - _ => panic!(""), - } - }), - Err(ABSURD_FEE_RATE) + Err(error_fee_rate) ); - assert!(psbt.extract_tx_with_fee_rate_limit(ABSURD_FEE_RATE).is_ok()); + + // No one is using an ~50 BTC fee so if we can handle this + // then the `FeeRate` restrictions are fine for PSBT usage. + let psbt = psbt_with_values(Amount::from_btc_u16(50).to_sat(), 1000); // fee = 50 BTC - 1000 sats + assert!(psbt.extract_tx_with_fee_rate_limit(FeeRate::MAX).is_ok()); // Testing that extract_tx will error at 25k sat/vbyte (6250000 sat/kwu) assert_eq!( diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 853370adc0..a8b4a516f8 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -279,7 +279,7 @@ fn amount_checked_div_by_weight_ceil() { assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864).unwrap()); let fee_rate = Amount::ONE_SAT.div_by_weight_ceil(Weight::ZERO); - assert!(fee_rate.is_none()); + assert!(fee_rate.is_error()); } #[cfg(feature = "alloc")] @@ -297,7 +297,7 @@ fn amount_checked_div_by_weight_floor() { assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863).unwrap()); let fee_rate = Amount::ONE_SAT.div_by_weight_floor(Weight::ZERO); - assert!(fee_rate.is_none()); + assert!(fee_rate.is_error()); } #[cfg(feature = "alloc")] @@ -325,8 +325,8 @@ fn amount_checked_div_by_fee_rate() { // Test division by zero let zero_fee_rate = FeeRate::from_sat_per_kwu(0).unwrap(); - assert!(amount.div_by_fee_rate_floor(zero_fee_rate).is_none()); - assert!(amount.div_by_fee_rate_ceil(zero_fee_rate).is_none()); + assert!(amount.div_by_fee_rate_floor(zero_fee_rate).is_error()); + assert!(amount.div_by_fee_rate_ceil(zero_fee_rate).is_error()); // Test with maximum amount let max_amount = Amount::MAX; diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 2e25eda848..2ebc340317 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -9,13 +9,14 @@ use core::{default, fmt}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; +use NumOpResult as R; use super::error::{ParseAmountErrorInner, ParseErrorInner}; use super::{ parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle, OutOfRangeError, ParseAmountError, ParseError, SignedAmount, }; -use crate::{FeeRate, Weight}; +use crate::{FeeRate, MathOp, NumOpError as E, NumOpResult, Weight}; mod encapsulate { use super::OutOfRangeError; @@ -407,33 +408,29 @@ impl Amount { /// Checked weight floor division. /// /// Be aware that integer division loses the remainder if no exact division - /// can be made. See also [`Self::checked_div_by_weight_ceil`]. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn div_by_weight_floor(self, weight: Weight) -> Option { + /// can be made. See also [`Self::div_by_weight_ceil`]. + pub const fn div_by_weight_floor(self, weight: Weight) -> NumOpResult { let wu = weight.to_wu(); - if wu == 0 { - return None; - } // Mul by 1,000 because we use per/kwu. - match self.to_sat().checked_mul(1_000) { - Some(sats) => { - let fee_rate = sats / wu; - FeeRate::from_sat_per_kwu(fee_rate) + if let Some(sats) = self.to_sat().checked_mul(1_000) { + match sats.checked_div(wu) { + Some(fee_rate) => + if let Ok(amount) = Amount::from_sat(fee_rate) { + return FeeRate::from_per_kwu(amount); + }, + None => return R::Error(E::while_doing(MathOp::Div)), } - None => None, } + // Use `MathOp::Mul` because `Div` implies div by zero. + R::Error(E::while_doing(MathOp::Mul)) } /// Checked weight ceiling division. /// /// Be aware that integer division loses the remainder if no exact division /// can be made. This method rounds up ensuring the transaction fee rate is - /// sufficient. See also [`Self::checked_div_by_weight_floor`]. - /// - /// Returns [`None`] if overflow occurred. + /// sufficient. See also [`Self::div_by_weight_floor`]. /// /// # Examples /// @@ -441,15 +438,14 @@ impl Amount { /// # use bitcoin_units::{amount, Amount, FeeRate, Weight}; /// let amount = Amount::from_sat(10)?; /// let weight = Weight::from_wu(300); - /// let fee_rate = amount.div_by_weight_ceil(weight); - /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34)); + /// let fee_rate = amount.div_by_weight_ceil(weight).expect("valid fee rate"); + /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34).expect("valid fee rate")); /// # Ok::<_, amount::OutOfRangeError>(()) /// ``` - #[must_use] - pub const fn div_by_weight_ceil(self, weight: Weight) -> Option { + pub const fn div_by_weight_ceil(self, weight: Weight) -> NumOpResult { let wu = weight.to_wu(); if wu == 0 { - return None; + return R::Error(E::while_doing(MathOp::Div)); } // Mul by 1,000 because we use per/kwu. @@ -457,10 +453,13 @@ impl Amount { // No need to used checked arithmetic because wu is non-zero. if let Some(bump) = sats.checked_add(wu - 1) { let fee_rate = bump / wu; - return FeeRate::from_sat_per_kwu(fee_rate); + if let Ok(amount) = Amount::from_sat(fee_rate) { + return FeeRate::from_per_kwu(amount); + } } } - None + // Use `MathOp::Mul` because `Div` implies div by zero. + R::Error(E::while_doing(MathOp::Mul)) } /// Checked fee rate floor division. @@ -468,40 +467,37 @@ impl Amount { /// Computes the maximum weight that would result in a fee less than or equal to this amount /// at the given `fee_rate`. Uses floor division to ensure the resulting weight doesn't cause /// the fee to exceed the amount. - /// - /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. - #[must_use] - pub const fn div_by_fee_rate_floor(self, fee_rate: FeeRate) -> Option { - if let Some(msats) = self.to_sat().checked_mul(1000) { - if let Some(wu) = msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { - return Some(Weight::from_wu(wu)); - } + pub const fn div_by_fee_rate_floor(self, fee_rate: FeeRate) -> NumOpResult { + debug_assert!(Amount::MAX.to_sat().checked_mul(1_000).is_some()); + let msats = self.to_sat() * 1_000; + match msats.checked_div(fee_rate.to_sat_per_kwu_ceil()) { + Some(wu) => R::Valid(Weight::from_wu(wu)), + None => R::Error(E::while_doing(MathOp::Div)), } - None } /// Checked fee rate ceiling division. /// /// Computes the minimum weight that would result in a fee greater than or equal to this amount /// at the given `fee_rate`. Uses ceiling division to ensure the resulting weight is sufficient. - /// - /// Returns [`None`] if overflow occurred or if `fee_rate` is zero. - #[must_use] - pub const fn div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> Option { + pub const fn div_by_fee_rate_ceil(self, fee_rate: FeeRate) -> NumOpResult { // Use ceil because result is used as the divisor. let rate = fee_rate.to_sat_per_kwu_ceil(); + // Early return so we do not have to use checked arithmetic below. if rate == 0 { - return None; + return R::Error(E::while_doing(MathOp::Div)); } - if let Some(msats) = self.to_sat().checked_mul(1000) { - // No need to used checked arithmetic because rate is non-zero. - if let Some(bump) = msats.checked_add(rate - 1) { + debug_assert!(Amount::MAX.to_sat().checked_mul(1_000).is_some()); + let msats = self.to_sat() * 1_000; + match msats.checked_add(rate - 1) { + Some(bump) => { let wu = bump / rate; - return Some(Weight::from_wu(wu)); + NumOpResult::Valid(Weight::from_wu(wu)) } + // Use `MathOp::Add` because `Div` implies div by zero. + None => R::Error(E::while_doing(MathOp::Add)), } - None } } diff --git a/units/src/fee.rs b/units/src/fee.rs index b156cb694f..43bad6231f 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -27,7 +27,7 @@ use core::ops; use NumOpResult as R; -use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, OptionExt, Weight}; +use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, Weight}; crate::internal_macros::impl_op_for_references! { impl ops::Mul for Weight { @@ -114,7 +114,7 @@ crate::internal_macros::impl_op_for_references! { type Output = NumOpResult; fn div(self, rhs: Weight) -> Self::Output { - self.div_by_weight_floor(rhs).valid_or_error(MathOp::Div) + self.div_by_weight_floor(rhs) } } impl ops::Div for NumOpResult { @@ -155,7 +155,7 @@ crate::internal_macros::impl_op_for_references! { type Output = NumOpResult; fn div(self, rhs: FeeRate) -> Self::Output { - self.div_by_fee_rate_floor(rhs).valid_or_error(MathOp::Div) + self.div_by_fee_rate_floor(rhs) } } impl ops::Div for NumOpResult { @@ -213,10 +213,8 @@ mod tests { #[test] fn weight_mul() { let weight = Weight::from_vb(10).unwrap(); - let fee: Amount = FeeRate::from_sat_per_vb(10) - .unwrap() - .mul_by_weight(weight) - .expect("expected Amount"); + let fee: Amount = + FeeRate::from_sat_per_vb(10).unwrap().mul_by_weight(weight).expect("expected Amount"); assert_eq!(Amount::from_sat_u32(100), fee); let fee = FeeRate::from_sat_per_kwu(10).unwrap().mul_by_weight(Weight::MAX); @@ -282,7 +280,7 @@ mod tests { // Test that division by zero returns None let zero_rate = FeeRate::from_sat_per_kwu(0).unwrap(); - assert!(amount.div_by_fee_rate_floor(zero_rate).is_none()); - assert!(amount.div_by_fee_rate_ceil(zero_rate).is_none()); + assert!(amount.div_by_fee_rate_floor(zero_rate).is_error()); + assert!(amount.div_by_fee_rate_ceil(zero_rate).is_error()); } } diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 70e0e371e3..b19157caeb 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -10,7 +10,6 @@ use core::ops; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; - use NumOpResult as R; use crate::{Amount, MathOp, NumOpError as E, NumOpResult, Weight}; From 3b0286bd563f94caae752f1ba6968c9a66b6c85a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 14 Jun 2025 07:44:52 +1000 Subject: [PATCH 102/857] Return NumOpResult for FeeRate and Weight As we did for `Amount` change the fee functions on `FeeRate` and `Weight` to return `NumOpResult`. This change does not add that much value but it does not make things worse and it makes the API more uniform. Also reduces lines of code. --- units/src/fee.rs | 18 ++++-------------- units/src/fee_rate/mod.rs | 15 ++++++--------- units/src/weight.rs | 7 ++----- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/units/src/fee.rs b/units/src/fee.rs index 43bad6231f..16eb0e5df7 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -27,17 +27,12 @@ use core::ops; use NumOpResult as R; -use crate::{Amount, FeeRate, MathOp, NumOpError as E, NumOpResult, Weight}; +use crate::{Amount, FeeRate, NumOpResult, Weight}; crate::internal_macros::impl_op_for_references! { impl ops::Mul for Weight { type Output = NumOpResult; - fn mul(self, rhs: FeeRate) -> Self::Output { - match rhs.mul_by_weight(self) { - Some(amount) => R::Valid(amount), - None => R::Error(E::while_doing(MathOp::Mul)), - } - } + fn mul(self, rhs: FeeRate) -> Self::Output { rhs.mul_by_weight(self) } } impl ops::Mul for NumOpResult { type Output = NumOpResult; @@ -72,12 +67,7 @@ crate::internal_macros::impl_op_for_references! { impl ops::Mul for FeeRate { type Output = NumOpResult; - fn mul(self, rhs: Weight) -> Self::Output { - match self.mul_by_weight(rhs) { - Some(amount) => R::Valid(amount), - None => R::Error(E::while_doing(MathOp::Mul)), - } - } + fn mul(self, rhs: Weight) -> Self::Output { self.mul_by_weight(rhs) } } impl ops::Mul for NumOpResult { type Output = NumOpResult; @@ -218,7 +208,7 @@ mod tests { assert_eq!(Amount::from_sat_u32(100), fee); let fee = FeeRate::from_sat_per_kwu(10).unwrap().mul_by_weight(Weight::MAX); - assert!(fee.is_none()); + assert!(fee.is_error()); let weight = Weight::from_vb(3).unwrap(); let fee_rate = FeeRate::from_sat_per_vb(3).unwrap(); diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index b19157caeb..ddff10fee4 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -196,8 +196,8 @@ impl FeeRate { pub const fn to_fee(self, weight: Weight) -> Amount { // No `unwrap_or()` in const context. match self.mul_by_weight(weight) { - Some(fee) => fee, - None => Amount::MAX, + NumOpResult::Valid(fee) => fee, + NumOpResult::Error(_) => Amount::MAX, } } @@ -207,7 +207,7 @@ impl FeeRate { /// This is equivalent to `Self::checked_mul_by_weight()`. #[must_use] #[deprecated(since = "TBD", note = "use `to_fee()` instead")] - pub fn fee_wu(self, weight: Weight) -> Option { self.mul_by_weight(weight) } + pub fn fee_wu(self, weight: Weight) -> Option { self.mul_by_weight(weight).ok() } /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`] /// if an overflow occurred. @@ -223,21 +223,18 @@ impl FeeRate { /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is /// enough instead of falling short if rounded down. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn mul_by_weight(self, weight: Weight) -> Option { + pub const fn mul_by_weight(self, weight: Weight) -> NumOpResult { let wu = weight.to_wu(); if let Some(fee_kwu) = self.to_sat_per_kwu_floor().checked_mul(wu) { // Bump by 999 to do ceil division using kwu. if let Some(bump) = fee_kwu.checked_add(999) { let fee = bump / 1_000; if let Ok(fee_amount) = Amount::from_sat(fee) { - return Some(fee_amount); + return NumOpResult::Valid(fee_amount); } } } - None + NumOpResult::Error(E::while_doing(MathOp::Mul)) } } diff --git a/units/src/weight.rs b/units/src/weight.rs index 0589cb0f71..b0b93ce5ad 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -10,7 +10,7 @@ use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::{Amount, CheckedSum, FeeRate}; +use crate::{Amount, CheckedSum, FeeRate, NumOpResult}; /// The factor that non-witness serialization data is multiplied by during weight calculation. pub const WITNESS_SCALE_FACTOR: usize = 4; @@ -168,10 +168,7 @@ impl Weight { /// Computes the absolute fee amount for a given [`FeeRate`] at this weight. When the resulting /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is /// enough instead of falling short if rounded down. - /// - /// Returns [`None`] if overflow occurred. - #[must_use] - pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> Option { + pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult { fee_rate.mul_by_weight(self) } } From 0ff8d82193ef562c1aedabe98a6283d09f803c0c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 16 Jun 2025 09:14:47 +1000 Subject: [PATCH 103/857] Make FeeRate from sat constructors infallible We now have constructors that take an arbitrary size fee rate (`Amount`). The `from_sat_per_foo` constructors can be made infallible by taking a `u32` instead of `u64`. This makes the API more ergonomic but limits the fee rate to just under 42 BTC which is plenty. Note we just delete the `from_sat_per_vb_u32` function because it is unreleased, in the past we had `from_sat_per_vb_unchecked` so we could put that back in if we wanted to be a bit more kind to downstream. Can be done later, we likely want to go over the public API before release and add a few things back in that we forgot to deprecate or could not for some reason during dev. Fuzz with a new function that consumes a `u32`. --- bitcoin/src/blockdata/script/tests.rs | 4 +- bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/psbt/mod.rs | 6 +- .../bitcoin/deserialize_script.rs | 4 +- fuzz/src/fuzz_utils.rs | 13 ++ units/src/amount/tests.rs | 16 +- units/src/amount/unsigned.rs | 2 +- units/src/fee.rs | 28 ++-- units/src/fee_rate/mod.rs | 137 +++++++----------- units/src/fee_rate/serde.rs | 34 +++-- units/src/result.rs | 2 +- 11 files changed, 120 insertions(+), 128 deletions(-) diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs index 590d233d36..0268d850ef 100644 --- a/bitcoin/src/blockdata/script/tests.rs +++ b/bitcoin/src/blockdata/script/tests.rs @@ -751,7 +751,7 @@ fn default_dust_value() { assert!(script_p2wpkh.is_p2wpkh()); assert_eq!(script_p2wpkh.minimal_non_dust(), Amount::from_sat_u32(294)); assert_eq!( - script_p2wpkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_u32(6)), + script_p2wpkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb(6)), Some(Amount::from_sat_u32(588)) ); @@ -765,7 +765,7 @@ fn default_dust_value() { assert!(script_p2pkh.is_p2pkh()); assert_eq!(script_p2pkh.minimal_non_dust(), Amount::from_sat_u32(546)); assert_eq!( - script_p2pkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_u32(6)), + script_p2pkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb(6)), Some(Amount::from_sat_u32(1092)) ); } diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index f169f4168a..98369280e6 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1689,7 +1689,7 @@ mod tests { #[test] fn effective_value_happy_path() { let value = "1 cBTC".parse::().unwrap(); - let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(10); let effective_value = effective_value(fee_rate, InputWeightPrediction::P2WPKH_MAX, value); // 10 sat/kwu * 272 wu = 3 sats (rounding up) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 09d7f53538..ea1ae2d3a5 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -127,7 +127,7 @@ impl Psbt { /// 1000 sats/vByte. 25k sats/vByte is obviously a mistake at this point. /// /// [`extract_tx`]: Psbt::extract_tx - pub const DEFAULT_MAX_FEE_RATE: FeeRate = FeeRate::from_sat_per_vb_u32(25_000); + pub const DEFAULT_MAX_FEE_RATE: FeeRate = FeeRate::from_sat_per_vb(25_000); /// An alias for [`extract_tx_fee_rate_limit`]. /// @@ -1437,7 +1437,7 @@ mod tests { // Large fee rate errors if we pass in 1 sat/vb so just use this to get the error fee rate returned. let error_fee_rate = psbt .clone() - .extract_tx_with_fee_rate_limit(FeeRate::from_sat_per_vb_u32(1)) + .extract_tx_with_fee_rate_limit(FeeRate::from_sat_per_vb(1)) .map_err(|e| match e { ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, _ => panic!(""), @@ -1475,7 +1475,7 @@ mod tests { ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate, _ => panic!(""), }), - Err(FeeRate::from_sat_per_kwu(6250003).unwrap()) // 6250000 is 25k sat/vbyte + Err(FeeRate::from_sat_per_kwu(6250003)) // 6250000 is 25k sat/vbyte ); // Lowering the input satoshis by 1 lowers the sat/kwu by 3 diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs index c227c59b41..276da5022e 100644 --- a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs +++ b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs @@ -2,7 +2,7 @@ use bitcoin::address::Address; use bitcoin::consensus::encode; use bitcoin::script::{self, ScriptExt as _}; use bitcoin::{FeeRate, Network}; -use bitcoin_fuzz::fuzz_utils::{consume_random_bytes, consume_u64}; +use bitcoin_fuzz::fuzz_utils::{consume_random_bytes, consume_u32}; use honggfuzz::fuzz; fn do_test(data: &[u8]) { @@ -17,7 +17,7 @@ fn do_test(data: &[u8]) { let _ = script.count_sigops_legacy(); let _ = script.minimal_non_dust(); - let fee_rate = FeeRate::from_sat_per_kwu(consume_u64(&mut new_data)).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(consume_u32(&mut new_data)); let _ = script.minimal_non_dust_custom(fee_rate); let mut b = script::Builder::new(); diff --git a/fuzz/src/fuzz_utils.rs b/fuzz/src/fuzz_utils.rs index 8a072db98b..883729c3cd 100644 --- a/fuzz/src/fuzz_utils.rs +++ b/fuzz/src/fuzz_utils.rs @@ -35,3 +35,16 @@ pub fn consume_u64(data: &mut &[u8]) -> u64 { u64_bytes[7], ]) } + +#[allow(dead_code)] +pub fn consume_u32(data: &mut &[u8]) -> u32 { + // We need at least 4 bytes to read a u32 + if data.len() < 4 { + return 0; + } + + let (u32_bytes, rest) = data.split_at(4); + *data = rest; + + u32::from_le_bytes([u32_bytes[0], u32_bytes[1], u32_bytes[2], u32_bytes[3]]) +} diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index a8b4a516f8..1eebfe6f49 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -270,13 +270,13 @@ fn amount_checked_div_by_weight_ceil() { let weight = Weight::from_kwu(1).unwrap(); let fee_rate = sat(1).div_by_weight_ceil(weight).unwrap(); // 1 sats / 1,000 wu = 1 sats/kwu - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); let weight = Weight::from_wu(381); let fee_rate = sat(329).div_by_weight_ceil(weight).unwrap(); // 329 sats / 381 wu = 863.5 sats/kwu // round up to 864 - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(864)); let fee_rate = Amount::ONE_SAT.div_by_weight_ceil(Weight::ZERO); assert!(fee_rate.is_error()); @@ -288,13 +288,13 @@ fn amount_checked_div_by_weight_floor() { let weight = Weight::from_kwu(1).unwrap(); let fee_rate = sat(1).div_by_weight_floor(weight).unwrap(); // 1 sats / 1,000 wu = 1 sats/kwu - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); let weight = Weight::from_wu(381); let fee_rate = sat(329).div_by_weight_floor(weight).unwrap(); // 329 sats / 381 wu = 863.5 sats/kwu // round down to 863 - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863)); let fee_rate = Amount::ONE_SAT.div_by_weight_floor(Weight::ZERO); assert!(fee_rate.is_error()); @@ -304,7 +304,7 @@ fn amount_checked_div_by_weight_floor() { #[test] fn amount_checked_div_by_fee_rate() { let amount = sat(1000); - let fee_rate = FeeRate::from_sat_per_kwu(2).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(2); // Test floor division let weight = amount.div_by_fee_rate_floor(fee_rate).unwrap(); @@ -317,20 +317,20 @@ fn amount_checked_div_by_fee_rate() { // Test truncation behavior let amount = sat(1000); - let fee_rate = FeeRate::from_sat_per_kwu(3).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(3); let floor_weight = amount.div_by_fee_rate_floor(fee_rate).unwrap(); let ceil_weight = amount.div_by_fee_rate_ceil(fee_rate).unwrap(); assert_eq!(floor_weight, Weight::from_wu(333_333)); assert_eq!(ceil_weight, Weight::from_wu(333_334)); // Test division by zero - let zero_fee_rate = FeeRate::from_sat_per_kwu(0).unwrap(); + let zero_fee_rate = FeeRate::from_sat_per_kwu(0); assert!(amount.div_by_fee_rate_floor(zero_fee_rate).is_error()); assert!(amount.div_by_fee_rate_ceil(zero_fee_rate).is_error()); // Test with maximum amount let max_amount = Amount::MAX; - let small_fee_rate = FeeRate::from_sat_per_kwu(1).unwrap(); + let small_fee_rate = FeeRate::from_sat_per_kwu(1); let weight = max_amount.div_by_fee_rate_floor(small_fee_rate).unwrap(); // 21_000_000_0000_0000 sats / (1 sat/kwu) = 2_100_000_000_000_000_000 wu assert_eq!(weight, Weight::from_wu(2_100_000_000_000_000_000)); diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 2ebc340317..57e27e120f 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -439,7 +439,7 @@ impl Amount { /// let amount = Amount::from_sat(10)?; /// let weight = Weight::from_wu(300); /// let fee_rate = amount.div_by_weight_ceil(weight).expect("valid fee rate"); - /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34).expect("valid fee rate")); + /// assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(34)); /// # Ok::<_, amount::OutOfRangeError>(()) /// ``` pub const fn div_by_weight_ceil(self, weight: Weight) -> NumOpResult { diff --git a/units/src/fee.rs b/units/src/fee.rs index 16eb0e5df7..0cd69ad8cc 100644 --- a/units/src/fee.rs +++ b/units/src/fee.rs @@ -190,12 +190,12 @@ mod tests { #[test] fn fee_rate_div_by_weight() { let fee_rate = (Amount::from_sat_u32(329) / Weight::from_wu(381)).unwrap(); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863)); } #[test] fn fee_wu() { - let fee_rate = FeeRate::from_sat_per_vb(2).unwrap(); + let fee_rate = FeeRate::from_sat_per_vb(2); let weight = Weight::from_vb(3).unwrap(); assert_eq!(fee_rate.to_fee(weight), Amount::from_sat_u32(6)); } @@ -204,19 +204,19 @@ mod tests { fn weight_mul() { let weight = Weight::from_vb(10).unwrap(); let fee: Amount = - FeeRate::from_sat_per_vb(10).unwrap().mul_by_weight(weight).expect("expected Amount"); + FeeRate::from_sat_per_vb(10).mul_by_weight(weight).expect("expected Amount"); assert_eq!(Amount::from_sat_u32(100), fee); - let fee = FeeRate::from_sat_per_kwu(10).unwrap().mul_by_weight(Weight::MAX); + let fee = FeeRate::from_sat_per_kwu(10).mul_by_weight(Weight::MAX); assert!(fee.is_error()); let weight = Weight::from_vb(3).unwrap(); - let fee_rate = FeeRate::from_sat_per_vb(3).unwrap(); + let fee_rate = FeeRate::from_sat_per_vb(3); let fee = fee_rate.mul_by_weight(weight).unwrap(); assert_eq!(Amount::from_sat_u32(9), fee); let weight = Weight::from_wu(381); - let fee_rate = FeeRate::from_sat_per_kwu(864).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(864); let fee = weight.mul_by_fee_rate(fee_rate).unwrap(); // 381 * 0.864 yields 329.18. // The result is then rounded up to 330. @@ -226,7 +226,7 @@ mod tests { #[test] #[allow(clippy::op_ref)] fn multiply() { - let two = FeeRate::from_sat_per_vb(2).unwrap(); + let two = FeeRate::from_sat_per_vb(2); let three = Weight::from_vb(3).unwrap(); let six = Amount::from_sat_u32(6); @@ -243,9 +243,9 @@ mod tests { fn amount_div_by_fee_rate() { // Test exact division let amount = Amount::from_sat_u32(1000); - let fee_rate = FeeRate::from_sat_per_kwu(2).unwrap(); - let weight = (amount / fee_rate).unwrap(); - assert_eq!(weight, Weight::from_wu(500_000)); + let fee_rate = FeeRate::from_sat_per_kwu(2); + let weight = amount / fee_rate; + assert_eq!(weight.unwrap(), Weight::from_wu(500_000)); // Test reference division let weight_ref = (&amount / fee_rate).unwrap(); @@ -257,19 +257,19 @@ mod tests { // Test truncation behavior let amount = Amount::from_sat_u32(1000); - let fee_rate = FeeRate::from_sat_per_kwu(3).unwrap(); - let weight = (amount / fee_rate).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(3); + let weight = amount / fee_rate; // 1000 * 1000 = 1,000,000 msats // 1,000,000 / 3 = 333,333.33... wu // Should truncate down to 333,333 wu - assert_eq!(weight, Weight::from_wu(333_333)); + assert_eq!(weight.unwrap(), Weight::from_wu(333_333)); // Verify that ceiling division gives different result let ceil_weight = amount.div_by_fee_rate_ceil(fee_rate).unwrap(); assert_eq!(ceil_weight, Weight::from_wu(333_334)); // Test that division by zero returns None - let zero_rate = FeeRate::from_sat_per_kwu(0).unwrap(); + let zero_rate = FeeRate::from_sat_per_kwu(0); assert!(amount.div_by_fee_rate_floor(zero_rate).is_error()); assert!(amount.div_by_fee_rate_ceil(zero_rate).is_error()); } diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index ddff10fee4..6c223f9562 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -50,19 +50,15 @@ impl FeeRate { /// The minimum fee rate required to broadcast a transaction. /// /// The value matches the default Bitcoin Core policy at the time of library release. - pub const BROADCAST_MIN: FeeRate = FeeRate::from_sat_per_vb_u32(1); + pub const BROADCAST_MIN: FeeRate = FeeRate::from_sat_per_vb(1); /// The fee rate used to compute dust amount. - pub const DUST: FeeRate = FeeRate::from_sat_per_vb_u32(3); + pub const DUST: FeeRate = FeeRate::from_sat_per_vb(3); - /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units, - /// returning `None` if overflow occurred. - pub const fn from_sat_per_kwu(sat_kwu: u64) -> Option { - // No `map()` in const context. - match sat_kwu.checked_mul(4_000) { - Some(fee_rate) => Some(FeeRate::from_sat_per_mvb(fee_rate)), - None => None, - } + /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. + pub const fn from_sat_per_kwu(sat_kwu: u32) -> Self { + let fee_rate = (sat_kwu as u64) * 4_000; // No `Into` in const context. + FeeRate::from_sat_per_mvb(fee_rate) } /// Constructs a new [`FeeRate`] from amount per 1000 weight units. @@ -74,14 +70,10 @@ impl FeeRate { } } - /// Constructs a new [`FeeRate`] from satoshis per virtual byte, - /// returning `None` if overflow occurred. - pub const fn from_sat_per_vb(sat_vb: u64) -> Option { - // No `map()` in const context. - match sat_vb.checked_mul(1_000_000) { - Some(fee_rate) => Some(FeeRate::from_sat_per_mvb(fee_rate)), - None => None, - } + /// Constructs a new [`FeeRate`] from satoshis per virtual byte. + pub const fn from_sat_per_vb(sat_vb: u32) -> Self { + let fee_rate = (sat_vb as u64) * 1_000_000; // No `Into` in const context. + FeeRate::from_sat_per_mvb(fee_rate) } /// Constructs a new [`FeeRate`] from amount per virtual byte. @@ -93,20 +85,10 @@ impl FeeRate { } } - /// Constructs a new [`FeeRate`] from satoshis per virtual bytes. - pub const fn from_sat_per_vb_u32(sat_vb: u32) -> Self { - let sat_vb = sat_vb as u64; // No `Into` in const context. - FeeRate::from_sat_per_mvb(sat_vb * 1_000_000) - } - - /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes), - /// returning `None` if overflow occurred. - pub const fn from_sat_per_kvb(sat_kvb: u64) -> Option { - // No `map()` in const context. - match sat_kvb.checked_mul(1_000) { - Some(fee_rate) => Some(FeeRate::from_sat_per_mvb(fee_rate)), - None => None, - } + /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). + pub const fn from_sat_per_kvb(sat_kvb: u32) -> Self { + let fee_rate = (sat_kvb as u64) * 1_000; // No `Into` in const context. + FeeRate::from_sat_per_mvb(fee_rate) } /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). @@ -301,18 +283,18 @@ mod tests { #[test] #[allow(clippy::op_ref)] fn feerate_div_nonzero() { - let rate = FeeRate::from_sat_per_kwu(200).unwrap(); + let rate = FeeRate::from_sat_per_kwu(200); let divisor = NonZeroU64::new(2).unwrap(); - assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100).unwrap()); - assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100).unwrap()); + assert_eq!(rate / divisor, FeeRate::from_sat_per_kwu(100)); + assert_eq!(&rate / &divisor, FeeRate::from_sat_per_kwu(100)); } #[test] #[allow(clippy::op_ref)] fn addition() { - let one = FeeRate::from_sat_per_kwu(1).unwrap(); - let two = FeeRate::from_sat_per_kwu(2).unwrap(); - let three = FeeRate::from_sat_per_kwu(3).unwrap(); + let one = FeeRate::from_sat_per_kwu(1); + let two = FeeRate::from_sat_per_kwu(2); + let three = FeeRate::from_sat_per_kwu(3); assert!(one + two == three); assert!(&one + two == three); @@ -323,9 +305,9 @@ mod tests { #[test] #[allow(clippy::op_ref)] fn subtract() { - let three = FeeRate::from_sat_per_kwu(3).unwrap(); - let seven = FeeRate::from_sat_per_kwu(7).unwrap(); - let ten = FeeRate::from_sat_per_kwu(10).unwrap(); + let three = FeeRate::from_sat_per_kwu(3); + let seven = FeeRate::from_sat_per_kwu(7); + let ten = FeeRate::from_sat_per_kwu(10); assert_eq!(ten - seven, three); assert_eq!(&ten - seven, three); @@ -335,44 +317,45 @@ mod tests { #[test] fn add_assign() { - let mut f = FeeRate::from_sat_per_kwu(1).unwrap(); - f += FeeRate::from_sat_per_kwu(2).unwrap(); - assert_eq!(f, FeeRate::from_sat_per_kwu(3).unwrap()); + let mut f = FeeRate::from_sat_per_kwu(1); + f += FeeRate::from_sat_per_kwu(2); + assert_eq!(f, FeeRate::from_sat_per_kwu(3)); - let mut f = FeeRate::from_sat_per_kwu(1).unwrap(); - f += &FeeRate::from_sat_per_kwu(2).unwrap(); - assert_eq!(f, FeeRate::from_sat_per_kwu(3).unwrap()); + let mut f = FeeRate::from_sat_per_kwu(1); + f += &FeeRate::from_sat_per_kwu(2); + assert_eq!(f, FeeRate::from_sat_per_kwu(3)); } #[test] fn sub_assign() { - let mut f = FeeRate::from_sat_per_kwu(3).unwrap(); - f -= FeeRate::from_sat_per_kwu(2).unwrap(); - assert_eq!(f, FeeRate::from_sat_per_kwu(1).unwrap()); + let mut f = FeeRate::from_sat_per_kwu(3); + f -= FeeRate::from_sat_per_kwu(2); + assert_eq!(f, FeeRate::from_sat_per_kwu(1)); - let mut f = FeeRate::from_sat_per_kwu(3).unwrap(); - f -= &FeeRate::from_sat_per_kwu(2).unwrap(); - assert_eq!(f, FeeRate::from_sat_per_kwu(1).unwrap()); + let mut f = FeeRate::from_sat_per_kwu(3); + f -= &FeeRate::from_sat_per_kwu(2); + assert_eq!(f, FeeRate::from_sat_per_kwu(1)); } #[test] fn checked_add() { - let one = FeeRate::from_sat_per_kwu(1).unwrap(); - let two = FeeRate::from_sat_per_kwu(2).unwrap(); - let three = FeeRate::from_sat_per_kwu(3).unwrap(); + let one = FeeRate::from_sat_per_kwu(1); + let two = FeeRate::from_sat_per_kwu(2); + let three = FeeRate::from_sat_per_kwu(3); assert_eq!(one.checked_add(two).unwrap(), three); - assert!(FeeRate::from_sat_per_kvb(u64::MAX).is_none()); // sanity check. + // Sanity check - no overflow adding one to per kvb max. + let _ = FeeRate::from_sat_per_kvb(u32::MAX).checked_add(one).unwrap(); let fee_rate = FeeRate::from_sat_per_mvb(u64::MAX).checked_add(one); assert!(fee_rate.is_none()); } #[test] fn checked_sub() { - let one = FeeRate::from_sat_per_kwu(1).unwrap(); - let two = FeeRate::from_sat_per_kwu(2).unwrap(); - let three = FeeRate::from_sat_per_kwu(3).unwrap(); + let one = FeeRate::from_sat_per_kwu(1); + let two = FeeRate::from_sat_per_kwu(2); + let three = FeeRate::from_sat_per_kwu(3); assert_eq!(three.checked_sub(two).unwrap(), one); let fee_rate = FeeRate::ZERO.checked_sub(one); @@ -390,35 +373,25 @@ mod tests { #[test] fn fee_rate_from_sat_per_vb() { - let fee_rate = FeeRate::from_sat_per_vb(10).expect("expected feerate in sat/kwu"); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500).unwrap()); + let fee_rate = FeeRate::from_sat_per_vb(10); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); } #[test] fn fee_rate_from_sat_per_kvb() { - let fee_rate = FeeRate::from_sat_per_kvb(11).unwrap(); + let fee_rate = FeeRate::from_sat_per_kvb(11); assert_eq!(fee_rate, FeeRate::from_sat_per_mvb(11_000)); } #[test] - fn fee_rate_from_sat_per_vb_overflow() { - let fee_rate = FeeRate::from_sat_per_vb(u64::MAX); - assert!(fee_rate.is_none()); + fn from_sat_per_vb() { + let fee_rate = FeeRate::from_sat_per_vb(10); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); } - #[test] - fn from_sat_per_vb_u32() { - let fee_rate = FeeRate::from_sat_per_vb_u32(10); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500).unwrap()); - } - - #[test] - #[cfg(debug_assertions)] - fn from_sat_per_vb_u32_cannot_panic() { FeeRate::from_sat_per_vb_u32(u32::MAX); } - #[test] fn raw_feerate() { - let fee_rate = FeeRate::from_sat_per_kwu(749).unwrap(); + let fee_rate = FeeRate::from_sat_per_kwu(749); assert_eq!(fee_rate.to_sat_per_kwu_floor(), 749); assert_eq!(fee_rate.to_sat_per_vb_floor(), 2); assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3); @@ -427,24 +400,22 @@ mod tests { #[test] fn checked_mul() { let fee_rate = FeeRate::from_sat_per_kwu(10) - .unwrap() .checked_mul(10) .expect("expected feerate in sat/kwu"); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100)); - let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap().checked_mul(u64::MAX); + let fee_rate = FeeRate::from_sat_per_kwu(10).checked_mul(u64::MAX); assert!(fee_rate.is_none()); } #[test] fn checked_div() { let fee_rate = FeeRate::from_sat_per_kwu(10) - .unwrap() .checked_div(10) .expect("expected feerate in sat/kwu"); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1).unwrap()); + assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); - let fee_rate = FeeRate::from_sat_per_kwu(10).unwrap().checked_div(0); + let fee_rate = FeeRate::from_sat_per_kwu(10).checked_div(0); assert!(fee_rate.is_none()); } diff --git a/units/src/fee_rate/serde.rs b/units/src/fee_rate/serde.rs index 27750dce6c..61390976b4 100644 --- a/units/src/fee_rate/serde.rs +++ b/units/src/fee_rate/serde.rs @@ -33,15 +33,19 @@ pub mod as_sat_per_kwu_floor { use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use crate::FeeRate; + use crate::{Amount, FeeRate}; pub fn serialize(f: &FeeRate, s: S) -> Result { u64::serialize(&f.to_sat_per_kwu_floor(), s) } pub fn deserialize<'d, D: Deserializer<'d>>(d: D) -> Result { - FeeRate::from_sat_per_kwu(u64::deserialize(d)?) - .ok_or_else(|| serde::de::Error::custom("overflowed sats/kwu")) + let sat = u64::deserialize(d)?; + FeeRate::from_per_kwu( + Amount::from_sat(sat).map_err(|_| serde::de::Error::custom("amount out of range"))?, + ) + .into_result() + .map_err(|_| serde::de::Error::custom("fee rate too big for sats/kwu")) } pub mod opt { @@ -100,8 +104,7 @@ pub mod as_sat_per_vb_floor { use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use crate::fee_rate::serde::OverflowError; - use crate::fee_rate::FeeRate; + use crate::{Amount, FeeRate}; pub fn serialize(f: &FeeRate, s: S) -> Result { u64::serialize(&f.to_sat_per_vb_floor(), s) @@ -109,9 +112,12 @@ pub mod as_sat_per_vb_floor { // Errors on overflow. pub fn deserialize<'d, D: Deserializer<'d>>(d: D) -> Result { - FeeRate::from_sat_per_vb(u64::deserialize(d)?) - .ok_or(OverflowError) - .map_err(serde::de::Error::custom) + let sat = u64::deserialize(d)?; + FeeRate::from_per_vb( + Amount::from_sat(sat).map_err(|_| serde::de::Error::custom("amount out of range"))?, + ) + .into_result() + .map_err(|_| serde::de::Error::custom("fee rate too big for sats/vb")) } pub mod opt { @@ -171,8 +177,7 @@ pub mod as_sat_per_vb_ceil { use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use crate::fee_rate::serde::OverflowError; - use crate::fee_rate::FeeRate; + use crate::{Amount, FeeRate}; pub fn serialize(f: &FeeRate, s: S) -> Result { u64::serialize(&f.to_sat_per_vb_ceil(), s) @@ -180,9 +185,12 @@ pub mod as_sat_per_vb_ceil { // Errors on overflow. pub fn deserialize<'d, D: Deserializer<'d>>(d: D) -> Result { - FeeRate::from_sat_per_vb(u64::deserialize(d)?) - .ok_or(OverflowError) - .map_err(serde::de::Error::custom) + let sat = u64::deserialize(d)?; + FeeRate::from_per_vb( + Amount::from_sat(sat).map_err(|_| serde::de::Error::custom("amount out of range"))?, + ) + .into_result() + .map_err(|_| serde::de::Error::custom("fee rate too big for sats/vb")) } pub mod opt { diff --git a/units/src/result.rs b/units/src/result.rs index a6619ac687..36f9094e0e 100644 --- a/units/src/result.rs +++ b/units/src/result.rs @@ -58,7 +58,7 @@ use crate::{Amount, FeeRate, SignedAmount, Weight}; /// let a = Amount::from_sat(123).expect("valid amount"); /// let b = Amount::from_sat(467).expect("valid amount"); /// // Fee rate for transaction. -/// let fee_rate = FeeRate::from_sat_per_vb(1).unwrap(); +/// let fee_rate = FeeRate::from_sat_per_vb(1); /// /// // Somewhat contrived example to show addition operator chained with division. /// let max_fee = a + b; From 7dc66e3476c3ba08eb341a09f3c85a795b005159 Mon Sep 17 00:00:00 2001 From: vicjuma Date: Tue, 17 Jun 2025 07:53:27 +0300 Subject: [PATCH 104/857] impl LowerHex, UpperHex, Octal, and Binary for ChildNumber Each trait forwards to the inner u32 index and formatting done based on the variant used with the alternate path See discussion: https://github.com/rust-bitcoin/rust-bitcoin/pull/4620#issuecomment-2974023604 --- bitcoin/src/bip32.rs | 104 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 08466e3c82..07f0c67b3e 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -193,6 +193,29 @@ impl ChildNumber { ChildNumber::Hardened { index: idx } => ChildNumber::from_hardened_idx(idx + 1), } } + + /// Formats the child number using the provided formatting function. + /// + /// For hardened child numbers appends a `'` or `hardened_alt_suffix` + /// depending on the formatter. + fn format_with( + &self, + f: &mut fmt::Formatter, + format_fn: F, + hardened_alt_suffix: &str, + ) -> fmt::Result + where + F: Fn(&u32, &mut fmt::Formatter) -> fmt::Result, + { + match *self { + ChildNumber::Hardened { index } => { + format_fn(&index, f)?; + let alt = f.alternate(); + f.write_str(if alt { hardened_alt_suffix } else { "'" }) + } + ChildNumber::Normal { index } => format_fn(&index, f), + } + } } impl From for ChildNumber { @@ -216,14 +239,31 @@ impl From for u32 { impl fmt::Display for ChildNumber { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ChildNumber::Hardened { index } => { - fmt::Display::fmt(&index, f)?; - let alt = f.alternate(); - f.write_str(if alt { "h" } else { "'" }) - } - ChildNumber::Normal { index } => fmt::Display::fmt(&index, f), - } + self.format_with(f, fmt::Display::fmt, "h") + } +} + +impl fmt::LowerHex for ChildNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format_with(f, fmt::LowerHex::fmt, "h") + } +} + +impl fmt::UpperHex for ChildNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format_with(f, fmt::UpperHex::fmt, "H") + } +} + +impl fmt::Octal for ChildNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format_with(f, fmt::Octal::fmt, "h") + } +} + +impl fmt::Binary for ChildNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format_with(f, fmt::Binary::fmt, "h") } } @@ -1123,6 +1163,54 @@ mod tests { assert_eq!(format!("{:#}", path), "84h/0h/0h/0/0"); } + #[test] + fn test_lowerhex_formatting() { + let normal = Normal { index: 42 }; + let hardened = Hardened { index: 42 }; + + assert_eq!(format!("{:x}", normal), "2a"); + assert_eq!(format!("{:#x}", normal), "0x2a"); + + assert_eq!(format!("{:x}", hardened), "2a'"); + assert_eq!(format!("{:#x}", hardened), "0x2ah"); + } + + #[test] + fn test_upperhex_formatting() { + let normal = Normal { index: 42 }; + let hardened = Hardened { index: 42 }; + + assert_eq!(format!("{:X}", normal), "2A"); + assert_eq!(format!("{:#X}", normal), "0x2A"); + + assert_eq!(format!("{:X}", hardened), "2A'"); + assert_eq!(format!("{:#X}", hardened), "0x2AH"); + } + + #[test] + fn test_octal_formatting() { + let normal = Normal { index: 42 }; + let hardened = Hardened { index: 42 }; + + assert_eq!(format!("{:o}", normal), "52"); + assert_eq!(format!("{:#o}", normal), "0o52"); + + assert_eq!(format!("{:o}", hardened), "52'"); + assert_eq!(format!("{:#o}", hardened), "0o52h"); + } + + #[test] + fn test_binary_formatting() { + let normal = Normal { index: 42 }; + let hardened = Hardened { index: 42 }; + + assert_eq!(format!("{:b}", normal), "101010"); + assert_eq!(format!("{:#b}", normal), "0b101010"); + + assert_eq!(format!("{:b}", hardened), "101010'"); + assert_eq!(format!("{:#b}", hardened), "0b101010h"); + } + #[test] fn parse_derivation_path_out_of_range() { let invalid_path = "2147483648"; From d9cf7270eb457fd660fa505701895ab4756e394d Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Mon, 2 Jun 2025 15:34:43 +0100 Subject: [PATCH 105/857] Move `bitcoin/p2p` into `p2p` Moves all of the content from `bitcoin/p2p` into `p2p`. `TryFrom` must be implemented for `Network -> Magic` now that `Network` is a foreign, non-exhaustive type. Ser/de test is updated accordingly, as well as the `Magic::from_network` constructor, which I have opted to return an `Option`. The `TryFrom` implementation uses a new `UnknownNetworkError(Network)` that mirrors the `Magic -> Network` error. The example handshake does not generate a random nonce for the version message, as there is no `rand` dependency in this crate and the program only makes a single, user-defined connection. It appears we can do better than copying and pasting the consensus encoding macros and functions from `bitcoin` without doing weird cross-crate macros that require some special knowledge of the crate to know when they will compile. --- Cargo-minimal.lock | 10 + Cargo-recent.lock | 10 + bitcoin/Cargo.toml | 4 - bitcoin/src/lib.rs | 1 - bitcoin/src/p2p/deser.rs | 42 -- bitcoin/src/p2p/mod.rs | 495 ------------------ fuzz/Cargo.toml | 1 + fuzz/fuzz_targets/bitcoin/deser_net_msg.rs | 2 +- .../bitcoin/p2p_address_roundtrip.rs | 2 +- p2p/Cargo.toml | 10 + {bitcoin => p2p}/examples/handshake.rs | 12 +- {bitcoin/src/p2p => p2p/src}/address.rs | 29 +- p2p/src/consensus.rs | 95 ++++ p2p/src/lib.rs | 492 +++++++++++++++++ {bitcoin/src/p2p => p2p/src}/message.rs | 47 +- .../src/p2p => p2p/src}/message_blockdata.rs | 15 +- {bitcoin/src/p2p => p2p/src}/message_bloom.rs | 6 +- .../p2p => p2p/src}/message_compact_blocks.rs | 4 +- .../src/p2p => p2p/src}/message_filter.rs | 6 +- .../src/p2p => p2p/src}/message_network.rs | 17 +- 20 files changed, 687 insertions(+), 613 deletions(-) delete mode 100644 bitcoin/src/p2p/deser.rs delete mode 100644 bitcoin/src/p2p/mod.rs rename {bitcoin => p2p}/examples/handshake.rs (90%) rename {bitcoin/src/p2p => p2p/src}/address.rs (96%) create mode 100644 p2p/src/consensus.rs rename {bitcoin/src/p2p => p2p/src}/message.rs (96%) rename {bitcoin/src/p2p => p2p/src}/message_blockdata.rs (93%) rename {bitcoin/src/p2p => p2p/src}/message_bloom.rs (89%) rename {bitcoin/src/p2p => p2p/src}/message_compact_blocks.rs (95%) rename {bitcoin/src/p2p => p2p/src}/message_filter.rs (95%) rename {bitcoin/src/p2p => p2p/src}/message_network.rs (94%) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 1ff3ceaa33..9667527dd2 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -77,6 +77,7 @@ name = "bitcoin-fuzz" version = "0.0.1" dependencies = [ "bitcoin", + "bitcoin-p2p-messages", "honggfuzz", "serde", "serde_json", @@ -109,6 +110,15 @@ dependencies = [ [[package]] name = "bitcoin-p2p-messages" version = "0.1.0" +dependencies = [ + "bitcoin", + "bitcoin-internals", + "bitcoin-io 0.2.0", + "bitcoin-units", + "bitcoin_hashes 0.16.0", + "hex-conservative 0.3.0", + "hex_lit", +] [[package]] name = "bitcoin-primitives" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index edfae1793f..ded29f2b8e 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -76,6 +76,7 @@ name = "bitcoin-fuzz" version = "0.0.1" dependencies = [ "bitcoin", + "bitcoin-p2p-messages", "honggfuzz", "serde", "serde_json", @@ -108,6 +109,15 @@ dependencies = [ [[package]] name = "bitcoin-p2p-messages" version = "0.1.0" +dependencies = [ + "bitcoin", + "bitcoin-internals", + "bitcoin-io 0.2.0", + "bitcoin-units", + "bitcoin_hashes 0.16.0", + "hex-conservative 0.3.0", + "hex_lit", +] [[package]] name = "bitcoin-primitives" diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index f6bff55c99..2e3ff37a6a 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -56,10 +56,6 @@ rustdoc-args = ["--cfg", "docsrs"] [[example]] name = "bip32" -[[example]] -name = "handshake" -required-features = ["rand-std"] - [[example]] name = "ecdsa-psbt" required-features = ["std", "bitcoinconsensus"] diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index 60e1513554..d305219262 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -94,7 +94,6 @@ extern crate serde; mod internal_macros; #[macro_use] -pub mod p2p; pub mod address; pub mod bip152; pub mod bip158; diff --git a/bitcoin/src/p2p/deser.rs b/bitcoin/src/p2p/deser.rs deleted file mode 100644 index cae2906c31..0000000000 --- a/bitcoin/src/p2p/deser.rs +++ /dev/null @@ -1,42 +0,0 @@ -macro_rules! impl_vec_wrapper { - ($wrapper: ident, $type: ty) => { - impl crate::consensus::encode::Encodable for $wrapper { - #[inline] - fn consensus_encode( - &self, - w: &mut W, - ) -> core::result::Result { - let mut len = 0; - len += w.emit_compact_size(self.0.len())?; - for c in self.0.iter() { - len += c.consensus_encode(w)?; - } - Ok(len) - } - } - - impl crate::consensus::encode::Decodable for $wrapper { - #[inline] - fn consensus_decode_from_finite_reader( - r: &mut R, - ) -> core::result::Result<$wrapper, crate::consensus::encode::Error> { - let len = r.read_compact_size()?; - // Do not allocate upfront more items than if the sequence of type - // occupied roughly quarter a block. This should never be the case - // for normal data, but even if that's not true - `push` will just - // reallocate. - // Note: OOM protection relies on reader eventually running out of - // data to feed us. - let max_capacity = - crate::consensus::encode::MAX_VEC_SIZE / 4 / core::mem::size_of::<$type>(); - let mut ret = Vec::with_capacity(core::cmp::min(len as usize, max_capacity)); - for _ in 0..len { - ret.push(Decodable::consensus_decode_from_finite_reader(r)?); - } - Ok($wrapper(ret)) - } - } - }; -} - -pub(crate) use impl_vec_wrapper; diff --git a/bitcoin/src/p2p/mod.rs b/bitcoin/src/p2p/mod.rs deleted file mode 100644 index 0f6b2ccae3..0000000000 --- a/bitcoin/src/p2p/mod.rs +++ /dev/null @@ -1,495 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Bitcoin p2p network types. -//! -//! This module defines support for (de)serialization and network transport -//! of Bitcoin data and Bitcoin p2p network messages. - -#[cfg(feature = "std")] -pub mod address; -#[cfg(feature = "std")] -mod deser; -#[cfg(feature = "std")] -pub mod message; -#[cfg(feature = "std")] -pub mod message_blockdata; -#[cfg(feature = "std")] -pub mod message_bloom; -#[cfg(feature = "std")] -pub mod message_compact_blocks; -#[cfg(feature = "std")] -pub mod message_filter; -#[cfg(feature = "std")] -pub mod message_network; - -use core::str::FromStr; -use core::{fmt, ops}; - -use hex::FromHex; -use internals::{impl_to_hex_from_lower_hex, write_err}; -use io::{BufRead, Write}; - -use crate::consensus::encode::{self, Decodable, Encodable}; -use crate::network::{Network, Params, TestnetVersion}; -use crate::prelude::{Borrow, BorrowMut, String, ToOwned}; - -#[rustfmt::skip] -#[doc(inline)] -#[cfg(feature = "std")] -pub use self::address::Address; - -/// Version of the protocol as appearing in network message headers. -/// -/// This constant is used to signal to other peers which features you support. Increasing it implies -/// that your software also supports every feature prior to this version. Doing so without support -/// may lead to you incorrectly banning other peers or other peers banning you. -/// -/// These are the features required for each version: -/// 70016 - Support receiving `wtxidrelay` message between `version` and `verack` message -/// 70015 - Support receiving invalid compact blocks from a peer without banning them -/// 70014 - Support compact block messages `sendcmpct`, `cmpctblock`, `getblocktxn` and `blocktxn` -/// 70013 - Support `feefilter` message -/// 70012 - Support `sendheaders` message and announce new blocks via headers rather than inv -/// 70011 - Support NODE_BLOOM service flag and don't support bloom filter messages if it is not set -/// 70002 - Support `reject` message -/// 70001 - Support bloom filter messages `filterload`, `filterclear` `filteradd`, `merkleblock` and FILTERED_BLOCK inventory type -/// 60002 - Support `mempool` message -/// 60001 - Support `pong` message and nonce in `ping` message -pub const PROTOCOL_VERSION: u32 = 70001; - -/// Flags to indicate which network services a node supports. -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ServiceFlags(u64); - -impl ServiceFlags { - /// NONE means no services supported. - pub const NONE: ServiceFlags = ServiceFlags(0); - - /// NETWORK means that the node is capable of serving the complete block chain. It is currently - /// set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light - /// clients. - pub const NETWORK: ServiceFlags = ServiceFlags(1 << 0); - - /// GETUTXO means the node is capable of responding to the getutxo protocol request. Bitcoin - /// Core does not support this but a patch set called Bitcoin XT does. - /// See BIP 64 for details on how this is implemented. - pub const GETUTXO: ServiceFlags = ServiceFlags(1 << 1); - - /// BLOOM means the node is capable and willing to handle bloom-filtered connections. Bitcoin - /// Core nodes used to support this by default, without advertising this bit, but no longer do - /// as of protocol version 70011 (= NO_BLOOM_VERSION) - pub const BLOOM: ServiceFlags = ServiceFlags(1 << 2); - - /// WITNESS indicates that a node can be asked for blocks and transactions including witness - /// data. - pub const WITNESS: ServiceFlags = ServiceFlags(1 << 3); - - /// COMPACT_FILTERS means the node will service basic block filter requests. - /// See BIP157 and BIP158 for details on how this is implemented. - pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6); - - /// NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only serving the last - /// 288 (2 day) blocks. - /// See BIP159 for details on how this is implemented. - pub const NETWORK_LIMITED: ServiceFlags = ServiceFlags(1 << 10); - - /// P2P_V2 indicates that the node supports the P2P v2 encrypted transport protocol. - /// See BIP324 for details on how this is implemented. - pub const P2P_V2: ServiceFlags = ServiceFlags(1 << 11); - - // NOTE: When adding new flags, remember to update the Display impl accordingly. - - /// Add [ServiceFlags] together. - /// - /// Returns itself. - pub fn add(&mut self, other: ServiceFlags) -> ServiceFlags { - self.0 |= other.0; - *self - } - - /// Remove [ServiceFlags] from this. - /// - /// Returns itself. - pub fn remove(&mut self, other: ServiceFlags) -> ServiceFlags { - self.0 &= !other.0; - *self - } - - /// Check whether [ServiceFlags] are included in this one. - pub fn has(self, flags: ServiceFlags) -> bool { (self.0 | flags.0) == self.0 } - - /// Gets the integer representation of this [`ServiceFlags`]. - pub fn to_u64(self) -> u64 { self.0 } -} - -impl fmt::LowerHex for ServiceFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } -} -impl_to_hex_from_lower_hex!(ServiceFlags, |service_flags: &ServiceFlags| 16 - - service_flags.0.leading_zeros() as usize / 4); - -impl fmt::UpperHex for ServiceFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) } -} - -impl fmt::Display for ServiceFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut flags = *self; - if flags == ServiceFlags::NONE { - return write!(f, "ServiceFlags(NONE)"); - } - let mut first = true; - macro_rules! write_flag { - ($f:ident) => { - if flags.has(ServiceFlags::$f) { - if !first { - write!(f, "|")?; - } - first = false; - write!(f, stringify!($f))?; - flags.remove(ServiceFlags::$f); - } - }; - } - write!(f, "ServiceFlags(")?; - write_flag!(NETWORK); - write_flag!(GETUTXO); - write_flag!(BLOOM); - write_flag!(WITNESS); - write_flag!(COMPACT_FILTERS); - write_flag!(NETWORK_LIMITED); - write_flag!(P2P_V2); - // If there are unknown flags left, we append them in hex. - if flags != ServiceFlags::NONE { - if !first { - write!(f, "|")?; - } - write!(f, "0x{:x}", flags)?; - } - write!(f, ")") - } -} - -impl From for ServiceFlags { - fn from(f: u64) -> Self { ServiceFlags(f) } -} - -impl From for u64 { - fn from(flags: ServiceFlags) -> Self { flags.0 } -} - -impl ops::BitOr for ServiceFlags { - type Output = Self; - - fn bitor(mut self, rhs: Self) -> Self { self.add(rhs) } -} - -impl ops::BitOrAssign for ServiceFlags { - fn bitor_assign(&mut self, rhs: Self) { self.add(rhs); } -} - -impl ops::BitXor for ServiceFlags { - type Output = Self; - - fn bitxor(mut self, rhs: Self) -> Self { self.remove(rhs) } -} - -impl ops::BitXorAssign for ServiceFlags { - fn bitxor_assign(&mut self, rhs: Self) { self.remove(rhs); } -} - -impl Encodable for ServiceFlags { - #[inline] - fn consensus_encode(&self, w: &mut W) -> Result { - self.0.consensus_encode(w) - } -} - -impl Decodable for ServiceFlags { - #[inline] - fn consensus_decode(r: &mut R) -> Result { - Ok(ServiceFlags(Decodable::consensus_decode(r)?)) - } -} -/// Network magic bytes to identify the cryptocurrency network the message was intended for. -#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] -pub struct Magic([u8; 4]); - -impl Magic { - /// Bitcoin mainnet network magic bytes. - pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]); - /// Bitcoin testnet3 network magic bytes. - #[deprecated(since = "0.33.0", note = "use `TESTNET3` instead")] - pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]); - /// Bitcoin testnet3 network magic bytes. - pub const TESTNET3: Self = Self([0x0B, 0x11, 0x09, 0x07]); - /// Bitcoin testnet4 network magic bytes. - pub const TESTNET4: Self = Self([0x1c, 0x16, 0x3f, 0x28]); - /// Bitcoin signet network magic bytes. - pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]); - /// Bitcoin regtest network magic bytes. - pub const REGTEST: Self = Self([0xFA, 0xBF, 0xB5, 0xDA]); - - /// Construct a new network magic from bytes. - pub const fn from_bytes(bytes: [u8; 4]) -> Magic { Magic(bytes) } - - /// Get network magic bytes. - pub fn to_bytes(self) -> [u8; 4] { self.0 } - - /// Returns the magic bytes for the network defined by `params`. - pub fn from_params(params: impl AsRef) -> Self { params.as_ref().network.into() } -} - -impl FromStr for Magic { - type Err = ParseMagicError; - - fn from_str(s: &str) -> Result { - match <[u8; 4]>::from_hex(s) { - Ok(magic) => Ok(Magic::from_bytes(magic)), - Err(e) => Err(ParseMagicError { error: e, magic: s.to_owned() }), - } - } -} - -impl From for Magic { - fn from(network: Network) -> Self { - match network { - Network::Bitcoin => Magic::BITCOIN, - Network::Testnet(TestnetVersion::V3) => Magic::TESTNET3, - Network::Testnet(TestnetVersion::V4) => Magic::TESTNET4, - Network::Signet => Magic::SIGNET, - Network::Regtest => Magic::REGTEST, - // Remember to add the `TryFrom` for new networks - } - } -} - -impl TryFrom for Network { - type Error = UnknownMagicError; - - fn try_from(magic: Magic) -> Result { - match magic { - Magic::BITCOIN => Ok(Network::Bitcoin), - Magic::TESTNET3 => Ok(Network::Testnet(TestnetVersion::V3)), - Magic::TESTNET4 => Ok(Network::Testnet(TestnetVersion::V4)), - Magic::SIGNET => Ok(Network::Signet), - Magic::REGTEST => Ok(Network::Regtest), - _ => Err(UnknownMagicError(magic)), - } - } -} - -impl fmt::Display for Magic { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?; - Ok(()) - } -} - -impl fmt::Debug for Magic { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fmt::Display::fmt(self, f) } -} - -impl fmt::LowerHex for Magic { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?; - Ok(()) - } -} -impl_to_hex_from_lower_hex!(Magic, |_| 8); - -impl fmt::UpperHex for Magic { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Upper)?; - Ok(()) - } -} - -impl Encodable for Magic { - fn consensus_encode(&self, writer: &mut W) -> Result { - self.0.consensus_encode(writer) - } -} - -impl Decodable for Magic { - fn consensus_decode(reader: &mut R) -> Result { - Ok(Magic(Decodable::consensus_decode(reader)?)) - } -} - -impl AsRef<[u8]> for Magic { - fn as_ref(&self) -> &[u8] { &self.0 } -} - -impl AsRef<[u8; 4]> for Magic { - fn as_ref(&self) -> &[u8; 4] { &self.0 } -} - -impl AsMut<[u8]> for Magic { - fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } -} - -impl AsMut<[u8; 4]> for Magic { - fn as_mut(&mut self) -> &mut [u8; 4] { &mut self.0 } -} - -impl Borrow<[u8]> for Magic { - fn borrow(&self) -> &[u8] { &self.0 } -} - -impl Borrow<[u8; 4]> for Magic { - fn borrow(&self) -> &[u8; 4] { &self.0 } -} - -impl BorrowMut<[u8]> for Magic { - fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 } -} - -impl BorrowMut<[u8; 4]> for Magic { - fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 } -} - -/// An error in parsing magic bytes. -#[derive(Debug, Clone, PartialEq, Eq)] -#[non_exhaustive] -pub struct ParseMagicError { - /// The error that occurred when parsing the string. - error: hex::HexToArrayError, - /// The byte string that failed to parse. - magic: String, -} - -impl fmt::Display for ParseMagicError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write_err!(f, "failed to parse {} as network magic", self.magic; self.error) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ParseMagicError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.error) } -} - -/// Error in creating a Network from Magic bytes. -#[derive(Debug, Clone, PartialEq, Eq)] -#[non_exhaustive] -pub struct UnknownMagicError(Magic); - -impl fmt::Display for UnknownMagicError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "unknown network magic {}", self.0) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for UnknownMagicError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::consensus::encode::{deserialize, serialize}; - - #[test] - fn serialize_deserialize() { - assert_eq!(serialize(&Magic::BITCOIN), &[0xf9, 0xbe, 0xb4, 0xd9]); - let magic: Magic = Network::Bitcoin.into(); - assert_eq!(serialize(&magic), &[0xf9, 0xbe, 0xb4, 0xd9]); - assert_eq!(serialize(&Magic::TESTNET3), &[0x0b, 0x11, 0x09, 0x07]); - let magic: Magic = Network::Testnet(TestnetVersion::V3).into(); - assert_eq!(serialize(&magic), &[0x0b, 0x11, 0x09, 0x07]); - assert_eq!(serialize(&Magic::TESTNET4), &[0x1c, 0x16, 0x3f, 0x28]); - let magic: Magic = Network::Testnet(TestnetVersion::V4).into(); - assert_eq!(serialize(&magic), &[0x1c, 0x16, 0x3f, 0x28]); - assert_eq!(serialize(&Magic::SIGNET), &[0x0a, 0x03, 0xcf, 0x40]); - let magic: Magic = Network::Signet.into(); - assert_eq!(serialize(&magic), &[0x0a, 0x03, 0xcf, 0x40]); - assert_eq!(serialize(&Magic::REGTEST), &[0xfa, 0xbf, 0xb5, 0xda]); - let magic: Magic = Network::Regtest.into(); - assert_eq!(serialize(&magic), &[0xfa, 0xbf, 0xb5, 0xda]); - - assert_eq!( - deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), - Some(Network::Bitcoin.into()) - ); - assert_eq!( - deserialize::(&[0x0b, 0x11, 0x09, 0x07]).ok(), - Some(Network::Testnet(TestnetVersion::V3).into()) - ); - assert_eq!( - deserialize::(&[0x1c, 0x16, 0x3f, 0x28]).ok(), - Some(Network::Testnet(TestnetVersion::V4).into()) - ); - assert_eq!( - deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), - Some(Network::Signet.into()) - ); - assert_eq!( - deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), - Some(Network::Regtest.into()) - ); - } - - #[test] - fn service_flags_test() { - let all = [ - ServiceFlags::NETWORK, - ServiceFlags::GETUTXO, - ServiceFlags::BLOOM, - ServiceFlags::WITNESS, - ServiceFlags::COMPACT_FILTERS, - ServiceFlags::NETWORK_LIMITED, - ServiceFlags::P2P_V2, - ]; - - let mut flags = ServiceFlags::NONE; - for f in all.iter() { - assert!(!flags.has(*f)); - } - - flags |= ServiceFlags::WITNESS; - assert_eq!(flags, ServiceFlags::WITNESS); - - let mut flags2 = flags | ServiceFlags::GETUTXO; - for f in all.iter() { - assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO); - } - - flags2 ^= ServiceFlags::WITNESS; - assert_eq!(flags2, ServiceFlags::GETUTXO); - - flags2 |= ServiceFlags::COMPACT_FILTERS; - flags2 ^= ServiceFlags::GETUTXO; - assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS); - - // Test formatting. - assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string()); - assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string()); - assert_eq!("ServiceFlags(P2P_V2)", ServiceFlags::P2P_V2.to_string()); - let flag = ServiceFlags::WITNESS - | ServiceFlags::BLOOM - | ServiceFlags::NETWORK - | ServiceFlags::P2P_V2; - assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS|P2P_V2)", flag.to_string()); - let flag = ServiceFlags::WITNESS | 0xf0.into(); - assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string()); - } - - #[test] - fn magic_from_str() { - let known_network_magic_strs = [ - ("f9beb4d9", Network::Bitcoin), - ("0b110907", Network::Testnet(TestnetVersion::V3)), - ("1c163f28", Network::Testnet(TestnetVersion::V4)), - ("fabfb5da", Network::Regtest), - ("0a03cf40", Network::Signet), - ]; - - for (magic_str, network) in &known_network_magic_strs { - let magic: Magic = magic_str.parse::().unwrap(); - assert_eq!(Network::try_from(magic).unwrap(), *network); - assert_eq!(&magic.to_string(), magic_str); - } - } -} diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 38adb8b8c9..5cf7898410 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -11,6 +11,7 @@ cargo-fuzz = true [dependencies] honggfuzz = { version = "0.5.56", default-features = false } bitcoin = { path = "../bitcoin", features = [ "serde" ] } +p2p = { path = "../p2p", package = "bitcoin-p2p-messages" } serde = { version = "1.0.103", features = [ "derive" ] } serde_json = "1.0" diff --git a/fuzz/fuzz_targets/bitcoin/deser_net_msg.rs b/fuzz/fuzz_targets/bitcoin/deser_net_msg.rs index 906bcee9f5..635a4a7a08 100644 --- a/fuzz/fuzz_targets/bitcoin/deser_net_msg.rs +++ b/fuzz/fuzz_targets/bitcoin/deser_net_msg.rs @@ -1,7 +1,7 @@ use honggfuzz::fuzz; fn do_test(data: &[u8]) { - let _: Result = + let _: Result = bitcoin::consensus::encode::deserialize(data); } diff --git a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs index 4fa4ffb272..5fba06632b 100644 --- a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs +++ b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs @@ -2,7 +2,7 @@ use std::convert::TryFrom; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use bitcoin::consensus::Decodable; -use bitcoin::p2p::address::AddrV2; +use p2p::address::AddrV2; use honggfuzz::fuzz; fn do_test(data: &[u8]) { diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index 37166211c8..892eee9025 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -13,8 +13,18 @@ rust-version = "1.63.0" exclude = ["tests", "contrib"] [dependencies] +bitcoin = { path = "../bitcoin/" } +hashes = { package = "bitcoin_hashes", path = "../hashes", default-features = false, features = ["std"] } +hex = { package = "hex-conservative", version = "0.3.0", default-features = false, features = ["std"] } +internals = { package = "bitcoin-internals", path = "../internals", features = ["std"] } +io = { package = "bitcoin-io", path = "../io", default-features = false, features = ["std"] } +units = { package = "bitcoin-units", path = "../units", default-features = false, features = ["std"] } [dev-dependencies] +hex_lit = "0.1.1" + +[[example]] +name = "handshake" [package.metadata.docs.rs] all-features = true diff --git a/bitcoin/examples/handshake.rs b/p2p/examples/handshake.rs similarity index 90% rename from bitcoin/examples/handshake.rs rename to p2p/examples/handshake.rs index dbc383dd11..ad91945974 100644 --- a/bitcoin/examples/handshake.rs +++ b/p2p/examples/handshake.rs @@ -4,8 +4,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use std::{env, process}; use bitcoin::consensus::{encode, Decodable}; -use bitcoin::p2p::{self, address, message, message_network, Magic}; -use bitcoin::secp256k1::rand::Rng; +use bitcoin_p2p_messages::{self, address, message, message_network, Magic, ServiceFlags}; fn main() { // This example establishes a connection to a Bitcoin node, sends the initial @@ -71,19 +70,20 @@ fn build_version_message(address: SocketAddr) -> message::NetworkMessage { let my_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0); // "bitfield of features to be enabled for this connection" - let services = p2p::ServiceFlags::NONE; + let services = ServiceFlags::NONE; // "standard UNIX timestamp in seconds" let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time error").as_secs(); // "The network address of the node receiving this message" - let addr_recv = address::Address::new(&address, p2p::ServiceFlags::NONE); + let addr_recv = address::Address::new(&address, ServiceFlags::NONE); // "The network address of the node emitting this message" - let addr_from = address::Address::new(&my_address, p2p::ServiceFlags::NONE); + let addr_from = address::Address::new(&my_address, ServiceFlags::NONE); // "Node random nonce, randomly generated every time a version packet is sent. This nonce is used to detect connections to self." - let nonce: u64 = secp256k1::rand::thread_rng().gen(); + // Because this crate does not include the `rand` dependency, this is a fixed value. + let nonce: u64 = 42; // "User Agent (0x00 if string is 0 bytes long)" let user_agent = String::from("rust-example"); diff --git a/bitcoin/src/p2p/address.rs b/p2p/src/address.rs similarity index 96% rename from bitcoin/src/p2p/address.rs rename to p2p/src/address.rs index 7a4af27e4e..f83c705638 100644 --- a/bitcoin/src/p2p/address.rs +++ b/p2p/src/address.rs @@ -10,9 +10,8 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV use io::{BufRead, Read, Write}; -use crate::consensus; -use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt}; -use crate::p2p::ServiceFlags; +use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt}; +use crate::ServiceFlags; /// A message which can be sent on the Bitcoin network #[derive(Clone, PartialEq, Eq, Hash)] @@ -207,7 +206,7 @@ impl Encodable for AddrV2 { network: u8, bytes: &[u8], ) -> Result { - Ok(network.consensus_encode(w)? + encode::consensus_encode_with_size(bytes, w)?) + Ok(network.consensus_encode(w)? + crate::consensus::consensus_encode_with_size(bytes, w)?) } Ok(match *self { AddrV2::Ipv4(ref addr) => encode_addr(w, 1, &addr.octets())?, @@ -225,28 +224,28 @@ impl Decodable for AddrV2 { let network_id = u8::consensus_decode(r)?; let len = r.read_compact_size()?; if len > 512 { - return Err(consensus::parse_failed_error("IP must be <= 512 bytes")); + return Err(crate::consensus::parse_failed_error("IP must be <= 512 bytes")); } Ok(match network_id { 1 => { if len != 4 { - return Err(consensus::parse_failed_error("invalid IPv4 address")); + return Err(crate::consensus::parse_failed_error("invalid IPv4 address")); } let addr: [u8; 4] = Decodable::consensus_decode(r)?; AddrV2::Ipv4(Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3])) } 2 => { if len != 16 { - return Err(consensus::parse_failed_error("invalid IPv6 address")); + return Err(crate::consensus::parse_failed_error("invalid IPv6 address")); } let addr: [u16; 8] = read_be_address(r)?; if addr[0..3] == ONION { - return Err(consensus::parse_failed_error( + return Err(crate::consensus::parse_failed_error( "OnionCat address sent with IPv6 network id", )); } if addr[0..6] == [0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF] { - return Err(consensus::parse_failed_error( + return Err(crate::consensus::parse_failed_error( "IPV4 wrapped address sent with IPv6 network id", )); } @@ -257,26 +256,26 @@ impl Decodable for AddrV2 { 4 => { if len != 32 { - return Err(consensus::parse_failed_error("invalid TorV3 address")); + return Err(crate::consensus::parse_failed_error("invalid TorV3 address")); } let pubkey = Decodable::consensus_decode(r)?; AddrV2::TorV3(pubkey) } 5 => { if len != 32 { - return Err(consensus::parse_failed_error("invalid I2P address")); + return Err(crate::consensus::parse_failed_error("invalid I2P address")); } let hash = Decodable::consensus_decode(r)?; AddrV2::I2p(hash) } 6 => { if len != 16 { - return Err(consensus::parse_failed_error("invalid CJDNS address")); + return Err(crate::consensus::parse_failed_error("invalid CJDNS address")); } let addr: [u16; 8] = read_be_address(r)?; // check the first byte for the CJDNS marker if addr[0] >> 8 != 0xFC { - return Err(consensus::parse_failed_error("invalid CJDNS address")); + return Err(crate::consensus::parse_failed_error("invalid CJDNS address")); } AddrV2::Cjdns(Ipv6Addr::new( addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], @@ -438,12 +437,12 @@ impl std::error::Error for AddrV2ToIpv6AddrError {} mod test { use std::net::IpAddr; + use bitcoin::consensus::encode::{deserialize, serialize}; use hex::FromHex; use hex_lit::hex; use super::*; - use crate::consensus::encode::{deserialize, serialize}; - use crate::p2p::message::AddrV2Payload; + use crate::message::AddrV2Payload; #[test] fn serialize_address() { diff --git a/p2p/src/consensus.rs b/p2p/src/consensus.rs new file mode 100644 index 0000000000..68ea527d49 --- /dev/null +++ b/p2p/src/consensus.rs @@ -0,0 +1,95 @@ +use bitcoin::consensus::encode::WriteExt; +use io::Write; + +pub(crate) fn consensus_encode_with_size( + data: &[u8], + w: &mut W, +) -> Result { + Ok(w.emit_compact_size(data.len())? + w.emit_slice(data)?) +} + +pub(crate) fn parse_failed_error(msg: &'static str) -> bitcoin::consensus::encode::Error { + bitcoin::consensus::encode::Error::Parse(bitcoin::consensus::encode::ParseError::ParseFailed(msg)) +} + +macro_rules! impl_consensus_encoding { + ($thing:ident, $($field:ident),+) => ( + impl bitcoin::consensus::Encodable for $thing { + #[inline] + fn consensus_encode( + &self, + w: &mut W, + ) -> core::result::Result { + let mut len = 0; + $(len += self.$field.consensus_encode(w)?;)+ + Ok(len) + } + } + + impl bitcoin::consensus::Decodable for $thing { + + #[inline] + fn consensus_decode_from_finite_reader( + r: &mut R, + ) -> core::result::Result<$thing, bitcoin::consensus::encode::Error> { + Ok($thing { + $($field: bitcoin::consensus::Decodable::consensus_decode_from_finite_reader(r)?),+ + }) + } + + #[inline] + fn consensus_decode( + r: &mut R, + ) -> core::result::Result<$thing, bitcoin::consensus::encode::Error> { + let mut r = r.take(internals::ToU64::to_u64(bitcoin::consensus::encode::MAX_VEC_SIZE)); + Ok($thing { + $($field: bitcoin::consensus::Decodable::consensus_decode(&mut r)?),+ + }) + } + } + ); +} +pub(crate) use impl_consensus_encoding; + +macro_rules! impl_vec_wrapper { + ($wrapper: ident, $type: ty) => { + impl bitcoin::consensus::encode::Encodable for $wrapper { + #[inline] + fn consensus_encode( + &self, + w: &mut W, + ) -> core::result::Result { + let mut len = 0; + len += w.emit_compact_size(self.0.len())?; + for c in self.0.iter() { + len += c.consensus_encode(w)?; + } + Ok(len) + } + } + + impl bitcoin::consensus::encode::Decodable for $wrapper { + #[inline] + fn consensus_decode_from_finite_reader( + r: &mut R, + ) -> core::result::Result<$wrapper, bitcoin::consensus::encode::Error> { + let len = r.read_compact_size()?; + // Do not allocate upfront more items than if the sequence of type + // occupied roughly quarter a block. This should never be the case + // for normal data, but even if that's not true - `push` will just + // reallocate. + // Note: OOM protection relies on reader eventually running out of + // data to feed us. + let max_capacity = + bitcoin::consensus::encode::MAX_VEC_SIZE / 4 / core::mem::size_of::<$type>(); + let mut ret = Vec::with_capacity(core::cmp::min(len as usize, max_capacity)); + for _ in 0..len { + ret.push(Decodable::consensus_decode_from_finite_reader(r)?); + } + Ok($wrapper(ret)) + } + } + }; +} + +pub(crate) use impl_vec_wrapper; diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index bb9afc7d9d..3250263187 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -14,3 +14,495 @@ #![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134 #![allow(clippy::manual_range_contains)] // More readable than clippy's format. #![allow(clippy::uninlined_format_args)] // Allow `format!("{}", x)`instead of enforcing `format!("{x}")` + +pub mod address; +pub mod message; +pub mod message_blockdata; +pub mod message_bloom; +pub mod message_compact_blocks; +pub mod message_filter; +pub mod message_network; +mod consensus; + +extern crate alloc; + +use core::str::FromStr; +use core::{fmt, ops}; + +use std::borrow::{Borrow, BorrowMut, ToOwned}; + +use hex::FromHex; +use internals::impl_to_hex_from_lower_hex; +use io::{BufRead, Write}; + +use bitcoin::consensus::encode::{self, Decodable, Encodable}; +use bitcoin::network::{Network, Params, TestnetVersion}; + +#[rustfmt::skip] +#[doc(inline)] +pub use self::address::Address; + +/// Version of the protocol as appearing in network message headers. +/// +/// This constant is used to signal to other peers which features you support. Increasing it implies +/// that your software also supports every feature prior to this version. Doing so without support +/// may lead to you incorrectly banning other peers or other peers banning you. +/// +/// These are the features required for each version: +/// 70016 - Support receiving `wtxidrelay` message between `version` and `verack` message +/// 70015 - Support receiving invalid compact blocks from a peer without banning them +/// 70014 - Support compact block messages `sendcmpct`, `cmpctblock`, `getblocktxn` and `blocktxn` +/// 70013 - Support `feefilter` message +/// 70012 - Support `sendheaders` message and announce new blocks via headers rather than inv +/// 70011 - Support NODE_BLOOM service flag and don't support bloom filter messages if it is not set +/// 70002 - Support `reject` message +/// 70001 - Support bloom filter messages `filterload`, `filterclear` `filteradd`, `merkleblock` and FILTERED_BLOCK inventory type +/// 60002 - Support `mempool` message +/// 60001 - Support `pong` message and nonce in `ping` message +pub const PROTOCOL_VERSION: u32 = 70001; + +/// Flags to indicate which network services a node supports. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ServiceFlags(u64); + +impl ServiceFlags { + /// NONE means no services supported. + pub const NONE: ServiceFlags = ServiceFlags(0); + + /// NETWORK means that the node is capable of serving the complete block chain. It is currently + /// set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light + /// clients. + pub const NETWORK: ServiceFlags = ServiceFlags(1 << 0); + + /// GETUTXO means the node is capable of responding to the getutxo protocol request. Bitcoin + /// Core does not support this but a patch set called Bitcoin XT does. + /// See BIP 64 for details on how this is implemented. + pub const GETUTXO: ServiceFlags = ServiceFlags(1 << 1); + + /// BLOOM means the node is capable and willing to handle bloom-filtered connections. Bitcoin + /// Core nodes used to support this by default, without advertising this bit, but no longer do + /// as of protocol version 70011 (= NO_BLOOM_VERSION) + pub const BLOOM: ServiceFlags = ServiceFlags(1 << 2); + + /// WITNESS indicates that a node can be asked for blocks and transactions including witness + /// data. + pub const WITNESS: ServiceFlags = ServiceFlags(1 << 3); + + /// COMPACT_FILTERS means the node will service basic block filter requests. + /// See BIP157 and BIP158 for details on how this is implemented. + pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6); + + /// NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only serving the last + /// 288 (2 day) blocks. + /// See BIP159 for details on how this is implemented. + pub const NETWORK_LIMITED: ServiceFlags = ServiceFlags(1 << 10); + + /// P2P_V2 indicates that the node supports the P2P v2 encrypted transport protocol. + /// See BIP324 for details on how this is implemented. + pub const P2P_V2: ServiceFlags = ServiceFlags(1 << 11); + + // NOTE: When adding new flags, remember to update the Display impl accordingly. + + /// Add [ServiceFlags] together. + /// + /// Returns itself. + #[must_use] + pub fn add(&mut self, other: ServiceFlags) -> ServiceFlags { + self.0 |= other.0; + *self + } + + /// Remove [ServiceFlags] from this. + /// + /// Returns itself. + #[must_use] + pub fn remove(&mut self, other: ServiceFlags) -> ServiceFlags { + self.0 &= !other.0; + *self + } + + /// Check whether [ServiceFlags] are included in this one. + pub fn has(self, flags: ServiceFlags) -> bool { (self.0 | flags.0) == self.0 } + + /// Gets the integer representation of this [`ServiceFlags`]. + pub fn to_u64(self) -> u64 { self.0 } +} + +impl fmt::LowerHex for ServiceFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } +} +impl_to_hex_from_lower_hex!(ServiceFlags, |service_flags: &ServiceFlags| 16 + - service_flags.0.leading_zeros() as usize / 4); + +impl fmt::UpperHex for ServiceFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) } +} + +impl fmt::Display for ServiceFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut flags = *self; + if flags == ServiceFlags::NONE { + return write!(f, "ServiceFlags(NONE)"); + } + let mut first = true; + macro_rules! write_flag { + ($f:ident) => { + if flags.has(ServiceFlags::$f) { + if !first { + write!(f, "|")?; + } + first = false; + write!(f, stringify!($f))?; + let _ = flags.remove(ServiceFlags::$f); + } + }; + } + write!(f, "ServiceFlags(")?; + write_flag!(NETWORK); + write_flag!(GETUTXO); + write_flag!(BLOOM); + write_flag!(WITNESS); + write_flag!(COMPACT_FILTERS); + write_flag!(NETWORK_LIMITED); + write_flag!(P2P_V2); + // If there are unknown flags left, we append them in hex. + if flags != ServiceFlags::NONE { + if !first { + write!(f, "|")?; + } + write!(f, "0x{:x}", flags)?; + } + write!(f, ")") + } +} + +impl From for ServiceFlags { + fn from(f: u64) -> Self { ServiceFlags(f) } +} + +impl From for u64 { + fn from(flags: ServiceFlags) -> Self { flags.0 } +} + +impl ops::BitOr for ServiceFlags { + type Output = Self; + + fn bitor(mut self, rhs: Self) -> Self { self.add(rhs) } +} + +impl ops::BitOrAssign for ServiceFlags { + fn bitor_assign(&mut self, rhs: Self) { let _ = self.add(rhs); } +} + +impl ops::BitXor for ServiceFlags { + type Output = Self; + + fn bitxor(mut self, rhs: Self) -> Self { self.remove(rhs) } +} + +impl ops::BitXorAssign for ServiceFlags { + fn bitxor_assign(&mut self, rhs: Self) { let _ = self.remove(rhs); } +} + +impl Encodable for ServiceFlags { + #[inline] + fn consensus_encode(&self, w: &mut W) -> Result { + self.0.consensus_encode(w) + } +} + +impl Decodable for ServiceFlags { + #[inline] + fn consensus_decode(r: &mut R) -> Result { + Ok(ServiceFlags(Decodable::consensus_decode(r)?)) + } +} +/// Network magic bytes to identify the cryptocurrency network the message was intended for. +#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] +pub struct Magic([u8; 4]); + +impl Magic { + /// Bitcoin mainnet network magic bytes. + pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]); + /// Bitcoin testnet3 network magic bytes. + #[deprecated(since = "0.33.0", note = "use `TESTNET3` instead")] + pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]); + /// Bitcoin testnet3 network magic bytes. + pub const TESTNET3: Self = Self([0x0B, 0x11, 0x09, 0x07]); + /// Bitcoin testnet4 network magic bytes. + pub const TESTNET4: Self = Self([0x1c, 0x16, 0x3f, 0x28]); + /// Bitcoin signet network magic bytes. + pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]); + /// Bitcoin regtest network magic bytes. + pub const REGTEST: Self = Self([0xFA, 0xBF, 0xB5, 0xDA]); + + /// Construct a new network magic from bytes. + pub const fn from_bytes(bytes: [u8; 4]) -> Magic { Magic(bytes) } + + /// Get network magic bytes. + pub fn to_bytes(self) -> [u8; 4] { self.0 } + + /// Returns the magic bytes for the network defined by `params`. + pub fn from_params(params: impl AsRef) -> Option { params.as_ref().network.try_into().ok() } +} + +impl FromStr for Magic { + type Err = ParseMagicError; + + fn from_str(s: &str) -> Result { + match <[u8; 4]>::from_hex(s) { + Ok(magic) => Ok(Magic::from_bytes(magic)), + Err(e) => Err(ParseMagicError { error: e, magic: s.to_owned() }), + } + } +} + +impl TryFrom for Magic { + type Error = UnknownNetworkError; + + fn try_from(network: Network) -> Result { + match network { + Network::Bitcoin => Ok(Magic::BITCOIN), + Network::Testnet(TestnetVersion::V3) => Ok(Magic::TESTNET3), + Network::Testnet(TestnetVersion::V4) => Ok(Magic::TESTNET4), + Network::Signet => Ok(Magic::SIGNET), + Network::Regtest => Ok(Magic::REGTEST), + _ => Err(UnknownNetworkError(network)), + } + } +} + +impl TryFrom for Network { + type Error = UnknownMagicError; + + fn try_from(magic: Magic) -> Result { + match magic { + Magic::BITCOIN => Ok(Network::Bitcoin), + Magic::TESTNET3 => Ok(Network::Testnet(TestnetVersion::V3)), + Magic::TESTNET4 => Ok(Network::Testnet(TestnetVersion::V4)), + Magic::SIGNET => Ok(Network::Signet), + Magic::REGTEST => Ok(Network::Regtest), + _ => Err(UnknownMagicError(magic)), + } + } +} + +impl fmt::Display for Magic { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?; + Ok(()) + } +} + +impl fmt::Debug for Magic { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fmt::Display::fmt(self, f) } +} + +impl fmt::LowerHex for Magic { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?; + Ok(()) + } +} +impl_to_hex_from_lower_hex!(Magic, |_| 8); + +impl fmt::UpperHex for Magic { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Upper)?; + Ok(()) + } +} + +impl Encodable for Magic { + fn consensus_encode(&self, writer: &mut W) -> Result { + self.0.consensus_encode(writer) + } +} + +impl Decodable for Magic { + fn consensus_decode(reader: &mut R) -> Result { + Ok(Magic(Decodable::consensus_decode(reader)?)) + } +} + +impl AsRef<[u8]> for Magic { + fn as_ref(&self) -> &[u8] { &self.0 } +} + +impl AsRef<[u8; 4]> for Magic { + fn as_ref(&self) -> &[u8; 4] { &self.0 } +} + +impl AsMut<[u8]> for Magic { + fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } +} + +impl AsMut<[u8; 4]> for Magic { + fn as_mut(&mut self) -> &mut [u8; 4] { &mut self.0 } +} + +impl Borrow<[u8]> for Magic { + fn borrow(&self) -> &[u8] { &self.0 } +} + +impl Borrow<[u8; 4]> for Magic { + fn borrow(&self) -> &[u8; 4] { &self.0 } +} + +impl BorrowMut<[u8]> for Magic { + fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 } +} + +impl BorrowMut<[u8; 4]> for Magic { + fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 } +} + +/// An error in parsing magic bytes. +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub struct ParseMagicError { + /// The error that occurred when parsing the string. + error: hex::HexToArrayError, + /// The byte string that failed to parse. + magic: String, +} + +impl fmt::Display for ParseMagicError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "failed to parse {} as network magic", self.magic) + } +} + +impl std::error::Error for ParseMagicError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.error) } +} + +/// Error in creating a Network from Magic bytes. +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub struct UnknownMagicError(Magic); + +impl fmt::Display for UnknownMagicError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "unknown network magic {}", self.0) + } +} + +impl std::error::Error for UnknownMagicError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } +} + +/// Error in creating a Magic from a Network. +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub struct UnknownNetworkError(Network); + +impl fmt::Display for UnknownNetworkError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "unknown network {}", self.0) + } +} + +impl std::error::Error for UnknownNetworkError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } +} + +#[cfg(test)] +mod tests { + use super::*; + use bitcoin::consensus::encode::{deserialize, serialize}; + + #[test] + fn serialize_deserialize() { + assert_eq!(serialize(&Magic::BITCOIN), &[0xf9, 0xbe, 0xb4, 0xd9]); + let magic: Magic = Network::Bitcoin.try_into().unwrap(); + assert_eq!(serialize(&magic), &[0xf9, 0xbe, 0xb4, 0xd9]); + assert_eq!(serialize(&Magic::TESTNET3), &[0x0b, 0x11, 0x09, 0x07]); + let magic: Magic = Network::Testnet(TestnetVersion::V3).try_into().unwrap(); + assert_eq!(serialize(&magic), &[0x0b, 0x11, 0x09, 0x07]); + assert_eq!(serialize(&Magic::TESTNET4), &[0x1c, 0x16, 0x3f, 0x28]); + let magic: Magic = Network::Testnet(TestnetVersion::V4).try_into().unwrap(); + assert_eq!(serialize(&magic), &[0x1c, 0x16, 0x3f, 0x28]); + assert_eq!(serialize(&Magic::SIGNET), &[0x0a, 0x03, 0xcf, 0x40]); + let magic: Magic = Network::Signet.try_into().unwrap(); + assert_eq!(serialize(&magic), &[0x0a, 0x03, 0xcf, 0x40]); + assert_eq!(serialize(&Magic::REGTEST), &[0xfa, 0xbf, 0xb5, 0xda]); + let magic: Magic = Network::Regtest.try_into().unwrap(); + assert_eq!(serialize(&magic), &[0xfa, 0xbf, 0xb5, 0xda]); + + assert_eq!(deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Network::Bitcoin.try_into().ok()); + assert_eq!( + deserialize::(&[0x0b, 0x11, 0x09, 0x07]).ok(), + Network::Testnet(TestnetVersion::V3).try_into().ok() + ); + assert_eq!( + deserialize::(&[0x1c, 0x16, 0x3f, 0x28]).ok(), + Network::Testnet(TestnetVersion::V4).try_into().ok() + ); + assert_eq!(deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Network::Signet.try_into().ok()); + assert_eq!(deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Network::Regtest.try_into().ok()); + } + + + #[test] + fn service_flags_test() { + let all = [ + ServiceFlags::NETWORK, + ServiceFlags::GETUTXO, + ServiceFlags::BLOOM, + ServiceFlags::WITNESS, + ServiceFlags::COMPACT_FILTERS, + ServiceFlags::NETWORK_LIMITED, + ServiceFlags::P2P_V2, + ]; + + let mut flags = ServiceFlags::NONE; + for f in all.iter() { + assert!(!flags.has(*f)); + } + + flags |= ServiceFlags::WITNESS; + assert_eq!(flags, ServiceFlags::WITNESS); + + let mut flags2 = flags | ServiceFlags::GETUTXO; + for f in all.iter() { + assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO); + } + + flags2 ^= ServiceFlags::WITNESS; + assert_eq!(flags2, ServiceFlags::GETUTXO); + + flags2 |= ServiceFlags::COMPACT_FILTERS; + flags2 ^= ServiceFlags::GETUTXO; + assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS); + + // Test formatting. + assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string()); + assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string()); + assert_eq!("ServiceFlags(P2P_V2)", ServiceFlags::P2P_V2.to_string()); + let flag = ServiceFlags::WITNESS + | ServiceFlags::BLOOM + | ServiceFlags::NETWORK + | ServiceFlags::P2P_V2; + assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS|P2P_V2)", flag.to_string()); + let flag = ServiceFlags::WITNESS | 0xf0.into(); + assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string()); + } + + #[test] + fn magic_from_str() { + let known_network_magic_strs = [ + ("f9beb4d9", Network::Bitcoin), + ("0b110907", Network::Testnet(TestnetVersion::V3)), + ("1c163f28", Network::Testnet(TestnetVersion::V4)), + ("fabfb5da", Network::Regtest), + ("0a03cf40", Network::Signet), + ]; + + for (magic_str, network) in &known_network_magic_strs { + let magic: Magic = magic_str.parse::().unwrap(); + assert_eq!(Network::try_from(magic).unwrap(), *network); + assert_eq!(&magic.to_string(), magic_str); + } + } +} diff --git a/bitcoin/src/p2p/message.rs b/p2p/src/message.rs similarity index 96% rename from bitcoin/src/p2p/message.rs rename to p2p/src/message.rs index 14b11f27da..c83bfde917 100644 --- a/bitcoin/src/p2p/message.rs +++ b/p2p/src/message.rs @@ -6,21 +6,23 @@ //! are used for (de)serializing Bitcoin objects for transmission on the network. use core::{fmt, iter}; +use std::borrow::Cow; +use std::boxed::Box; +use std::borrow::ToOwned; use hashes::sha256d; use internals::ToU64 as _; use io::{BufRead, Write}; -use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, ReadExt, WriteExt}; -use crate::merkle_tree::MerkleBlock; -use crate::p2p::address::{AddrV2Message, Address}; -use crate::p2p::deser::impl_vec_wrapper; -use crate::p2p::{ +use bitcoin::consensus::encode::{self, CheckedData, Decodable, Encodable, ReadExt, WriteExt}; +use bitcoin::merkle_tree::MerkleBlock; +use crate::address::{AddrV2Message, Address}; +use crate::consensus::impl_vec_wrapper; +use crate::{ message_blockdata, message_bloom, message_compact_blocks, message_filter, message_network, Magic, }; -use crate::prelude::{Box, Cow, String, ToOwned, Vec}; -use crate::{block, consensus, transaction}; +use bitcoin::{block, transaction}; /// The maximum number of [super::message_blockdata::Inventory] items in an `inv` message. /// @@ -144,7 +146,6 @@ impl fmt::Display for CommandStringError { } } -#[cfg(feature = "std")] impl std::error::Error for CommandStringError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } @@ -518,7 +519,7 @@ impl Decodable for HeaderDeserializationWrapper { for _ in 0..len { ret.push(Decodable::consensus_decode(r)?); if u8::consensus_decode(r)? != 0u8 { - return Err(consensus::parse_failed_error( + return Err(crate::consensus::parse_failed_error( "Headers message should not contain transactions", )); } @@ -718,21 +719,21 @@ mod test { use units::BlockHeight; use super::*; - use crate::bip152::BlockTransactionsRequest; - use crate::bip158::{FilterHash, FilterHeader}; - use crate::block::{Block, BlockHash}; - use crate::consensus::encode::{deserialize, deserialize_partial, serialize}; - use crate::p2p::address::AddrV2; - use crate::p2p::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory}; - use crate::p2p::message_bloom::{BloomFlags, FilterAdd, FilterLoad}; - use crate::p2p::message_compact_blocks::{GetBlockTxn, SendCmpct}; - use crate::p2p::message_filter::{ + use bitcoin::bip152::BlockTransactionsRequest; + use bitcoin::bip158::{FilterHash, FilterHeader}; + use bitcoin::block::{Block, BlockHash}; + use bitcoin::consensus::encode::{deserialize, deserialize_partial, serialize}; + use bitcoin::script::ScriptBuf; + use bitcoin::transaction::{Transaction, Txid}; + use crate::address::AddrV2; + use crate::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory}; + use crate::message_bloom::{BloomFlags, FilterAdd, FilterLoad}; + use crate::message_compact_blocks::{GetBlockTxn, SendCmpct}; + use crate::message_filter::{ CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters, }; - use crate::p2p::message_network::{Reject, RejectReason, VersionMessage}; - use crate::p2p::ServiceFlags; - use crate::script::ScriptBuf; - use crate::transaction::{Transaction, Txid}; + use crate::message_network::{Reject, RejectReason, VersionMessage}; + use crate::ServiceFlags; fn hash(array: [u8; 32]) -> sha256d::Hash { sha256d::Hash::from_byte_array(array) } @@ -740,7 +741,7 @@ mod test { fn full_round_ser_der_raw_network_message() { let version_msg: VersionMessage = deserialize(&hex!("721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001")).unwrap(); let tx: Transaction = deserialize(&hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000")).unwrap(); - let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap(); + let block: Block = deserialize(&hex!("00608e2e094d41aecfbcbf8fe70cb60be57516b07db1bafee4c4de5dad760000000000004aec16eab3be95abe9c54e01cf850c14b8c5cad1bc6b2e73e811db5d5998ada404503e66fcff031b4ebd99d701010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3402983a000404503e6604f1f617271083bc3d6600000000000000000007bb1b0a636b706f6f6c0d506f72746c616e642e484f444cffffffff0200f2052a010000001976a9142ce72b25fe97b52638c199acfaa5e3891ddfed5b88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000")).unwrap(); let header: block::Header = deserialize(&hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b")).unwrap(); let script: ScriptBuf = deserialize(&hex!("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")).unwrap(); diff --git a/bitcoin/src/p2p/message_blockdata.rs b/p2p/src/message_blockdata.rs similarity index 93% rename from bitcoin/src/p2p/message_blockdata.rs rename to p2p/src/message_blockdata.rs index 3d92312043..e2c388af7d 100644 --- a/bitcoin/src/p2p/message_blockdata.rs +++ b/p2p/src/message_blockdata.rs @@ -7,11 +7,10 @@ use io::{BufRead, Write}; -use crate::block::BlockHash; -use crate::consensus::encode::{self, Decodable, Encodable}; -use crate::internal_macros::impl_consensus_encoding; -use crate::p2p; -use crate::transaction::{Txid, Wtxid}; +use bitcoin::block::BlockHash; +use bitcoin::consensus::encode::{self, Decodable, Encodable}; +use bitcoin::transaction::{Txid, Wtxid}; +use crate::consensus::impl_consensus_encoding; /// An inventory item. #[derive(PartialEq, Eq, Clone, Debug, Copy, Hash, PartialOrd, Ord)] @@ -127,7 +126,7 @@ pub struct GetHeadersMessage { impl GetBlocksMessage { /// Construct a new `getblocks` message pub fn new(locator_hashes: Vec, stop_hash: BlockHash) -> GetBlocksMessage { - GetBlocksMessage { version: p2p::PROTOCOL_VERSION, locator_hashes, stop_hash } + GetBlocksMessage { version: crate::PROTOCOL_VERSION, locator_hashes, stop_hash } } } @@ -136,7 +135,7 @@ impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash); impl GetHeadersMessage { /// Construct a new `getheaders` message pub fn new(locator_hashes: Vec, stop_hash: BlockHash) -> GetHeadersMessage { - GetHeadersMessage { version: p2p::PROTOCOL_VERSION, locator_hashes, stop_hash } + GetHeadersMessage { version: crate::PROTOCOL_VERSION, locator_hashes, stop_hash } } } @@ -147,7 +146,7 @@ mod tests { use hex_lit::hex; use super::*; - use crate::consensus::encode::{deserialize, serialize}; + use bitcoin::consensus::encode::{deserialize, serialize}; #[test] fn getblocks_message() { diff --git a/bitcoin/src/p2p/message_bloom.rs b/p2p/src/message_bloom.rs similarity index 89% rename from bitcoin/src/p2p/message_bloom.rs rename to p2p/src/message_bloom.rs index 2a75f9a64d..69f079da2f 100644 --- a/bitcoin/src/p2p/message_bloom.rs +++ b/p2p/src/message_bloom.rs @@ -6,8 +6,8 @@ use io::{BufRead, Write}; -use crate::consensus::{self, encode, Decodable, Encodable, ReadExt}; -use crate::internal_macros::impl_consensus_encoding; +use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; +use crate::consensus::impl_consensus_encoding; /// `filterload` message sets the current bloom filter #[derive(Clone, PartialEq, Eq, Debug)] @@ -52,7 +52,7 @@ impl Decodable for BloomFlags { 0 => BloomFlags::None, 1 => BloomFlags::All, 2 => BloomFlags::PubkeyOnly, - _ => return Err(consensus::parse_failed_error("unknown bloom flag")), + _ => return Err(crate::consensus::parse_failed_error("unknown bloom flag")), }) } } diff --git a/bitcoin/src/p2p/message_compact_blocks.rs b/p2p/src/message_compact_blocks.rs similarity index 95% rename from bitcoin/src/p2p/message_compact_blocks.rs rename to p2p/src/message_compact_blocks.rs index 333a8c243f..9b6735c0d9 100644 --- a/bitcoin/src/p2p/message_compact_blocks.rs +++ b/p2p/src/message_compact_blocks.rs @@ -3,8 +3,8 @@ //! //! BIP152 Compact Blocks network messages -use crate::bip152; -use crate::internal_macros::impl_consensus_encoding; +use bitcoin::bip152; +use crate::consensus::impl_consensus_encoding; /// sendcmpct message #[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord, Hash)] diff --git a/bitcoin/src/p2p/message_filter.rs b/p2p/src/message_filter.rs similarity index 95% rename from bitcoin/src/p2p/message_filter.rs rename to p2p/src/message_filter.rs index 344e2d0a8b..65c9c3d7c9 100644 --- a/bitcoin/src/p2p/message_filter.rs +++ b/p2p/src/message_filter.rs @@ -6,9 +6,9 @@ use units::BlockHeight; -use crate::bip158::{FilterHash, FilterHeader}; -use crate::block::BlockHash; -use crate::internal_macros::impl_consensus_encoding; +use bitcoin::bip158::{FilterHash, FilterHeader}; +use bitcoin::block::BlockHash; +use crate::consensus::impl_consensus_encoding; /// getcfilters message #[derive(PartialEq, Eq, Clone, Debug)] diff --git a/bitcoin/src/p2p/message_network.rs b/p2p/src/message_network.rs similarity index 94% rename from bitcoin/src/p2p/message_network.rs rename to p2p/src/message_network.rs index d4a41b9e1c..258221a0cd 100644 --- a/bitcoin/src/p2p/message_network.rs +++ b/p2p/src/message_network.rs @@ -4,16 +4,15 @@ //! //! This module defines network messages which describe peers and their //! capabilities. +use std::borrow::Cow; use hashes::sha256d; use io::{BufRead, Write}; -use crate::consensus::{self, encode, Decodable, Encodable, ReadExt}; -use crate::internal_macros::impl_consensus_encoding; -use crate::p2p; -use crate::p2p::address::Address; -use crate::p2p::ServiceFlags; -use crate::prelude::{Cow, String}; +use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; +use crate::address::Address; +use crate::consensus::impl_consensus_encoding; +use crate::ServiceFlags; // Some simple messages @@ -61,7 +60,7 @@ impl VersionMessage { start_height: i32, ) -> VersionMessage { VersionMessage { - version: p2p::PROTOCOL_VERSION, + version: crate::PROTOCOL_VERSION, services, timestamp, receiver, @@ -126,7 +125,7 @@ impl Decodable for RejectReason { 0x41 => RejectReason::Dust, 0x42 => RejectReason::Fee, 0x43 => RejectReason::Checkpoint, - _ => return Err(consensus::parse_failed_error("unknown reject code")), + _ => return Err(crate::consensus::parse_failed_error("unknown reject code")), }) } } @@ -151,7 +150,7 @@ mod tests { use hex_lit::hex; use super::*; - use crate::consensus::encode::{deserialize, serialize}; + use bitcoin::consensus::encode::{deserialize, serialize}; #[test] fn version_message_test() { From f6dea36e313c59c3dca534aba2b7de459f094e9f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 13:11:59 +1000 Subject: [PATCH 106/857] units: Make error constructor private We typically do not want to have public constructors on error types. Currently we do on the `TimeOverflowError` so that we can call it in `primitives` but it turns out we can just use `NumberOf512Seconds` constructors instead. --- primitives/src/sequence.rs | 16 +++++----------- units/src/locktime/relative.rs | 12 ------------ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/primitives/src/sequence.rs b/primitives/src/sequence.rs index 7d68c7cdf0..ecad225dc5 100644 --- a/primitives/src/sequence.rs +++ b/primitives/src/sequence.rs @@ -20,7 +20,7 @@ use core::fmt; use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use units::locktime::relative::TimeOverflowError; +use units::locktime::relative::{NumberOf512Seconds, TimeOverflowError}; use units::parse::{self, PrefixedHexError, UnprefixedHexError}; use crate::locktime::relative; @@ -156,11 +156,8 @@ impl Sequence { /// Will return an error if the input cannot be encoded in 16 bits. #[inline] pub fn from_seconds_floor(seconds: u32) -> Result { - if let Ok(interval) = u16::try_from(seconds / 512) { - Ok(Sequence::from_512_second_intervals(interval)) - } else { - Err(TimeOverflowError::new(seconds)) - } + let intervals = NumberOf512Seconds::from_seconds_floor(seconds)?; + Ok(Sequence::from_512_second_intervals(intervals.to_512_second_intervals())) } /// Constructs a new relative lock-time from seconds, converting the seconds into 512 second @@ -169,11 +166,8 @@ impl Sequence { /// Will return an error if the input cannot be encoded in 16 bits. #[inline] pub fn from_seconds_ceil(seconds: u32) -> Result { - if let Ok(interval) = u16::try_from((seconds + 511) / 512) { - Ok(Sequence::from_512_second_intervals(interval)) - } else { - Err(TimeOverflowError::new(seconds)) - } + let intervals = NumberOf512Seconds::from_seconds_ceil(seconds)?; + Ok(Sequence::from_512_second_intervals(intervals.to_512_second_intervals())) } /// Constructs a new sequence from a u32 value. diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index f3dfba28a8..5edafe01ec 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -211,18 +211,6 @@ pub struct TimeOverflowError { pub(crate) seconds: u32, } -impl TimeOverflowError { - /// Constructs a new `TimeOverflowError` using `seconds`. - /// - /// # Panics - /// - /// If `seconds` would not actually overflow a `u16`. - pub fn new(seconds: u32) -> Self { - assert!(u16::try_from((seconds + 511) / 512).is_err()); - Self { seconds } - } -} - impl fmt::Display for TimeOverflowError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( From dc5249aae6d5c1375f563cf54a5d92cc8dfa3542 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 12:43:23 +1000 Subject: [PATCH 107/857] Use new type names instead of deprecated aliases Recently we changed the names of some locktime types but kept aliases to the original names. To assist with ongoing maintenance lets use the new names already. Internal change only. --- units/tests/str.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/units/tests/str.rs b/units/tests/str.rs index 8bc7146837..713fc15cdd 100644 --- a/units/tests/str.rs +++ b/units/tests/str.rs @@ -40,14 +40,14 @@ check! { lock_by_height_absolute_min, absolute::Height, absolute::Height::MIN, "0"; lock_by_height_absolute_max, absolute::Height, absolute::Height::MAX, "499999999"; - lock_by_height_relative_min, relative::Height, relative::Height::MIN, "0"; - lock_by_height_relative_max, relative::Height, relative::Height::MAX, "65535"; + lock_by_height_relative_min, relative::NumberOfBlocks, relative::NumberOfBlocks::MIN, "0"; + lock_by_height_relative_max, relative::NumberOfBlocks, relative::NumberOfBlocks::MAX, "65535"; - lock_by_time_absolute_min, absolute::Time, absolute::Time::MIN, "500000000"; - lock_by_time_absolute_max, absolute::Time, absolute::Time::MAX, "4294967295"; + lock_by_time_absolute_min, absolute::MedianTimePast, absolute::MedianTimePast::MIN, "500000000"; + lock_by_time_absolute_max, absolute::MedianTimePast, absolute::MedianTimePast::MAX, "4294967295"; - lock_by_time_relative_min, relative::Time, relative::Time::MIN, "0"; - lock_by_time_relative_max, relative::Time, relative::Time::MAX, "65535"; + lock_by_time_relative_min, relative::NumberOf512Seconds, relative::NumberOf512Seconds::MIN, "0"; + lock_by_time_relative_max, relative::NumberOf512Seconds, relative::NumberOf512Seconds::MAX, "65535"; weight_min, Weight, Weight::MIN, "0"; weight_max, Weight, Weight::MAX, "18446744073709551615"; From 1031851da408ee038d0a72ac652f7438a88df4ca Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 14:02:47 +1000 Subject: [PATCH 108/857] units: Manually implement serde traits for block types Done so we can stop enabling the `derive` feature of `serde`. --- units/src/block.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/units/src/block.rs b/units/src/block.rs index 6ba9cb838a..3143dc3618 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -16,7 +16,7 @@ use core::{fmt, ops}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(doc)] use crate::locktime; @@ -44,6 +44,28 @@ macro_rules! impl_u32_wrapper { fn from(height: $newtype) -> Self { height.to_u32() } } + #[cfg(feature = "serde")] + impl Serialize for $newtype { + #[inline] + fn serialize(&self, s: S) -> Result + where + S: Serializer, + { + u32::serialize(&self.to_u32(), s) + } + } + + #[cfg(feature = "serde")] + impl<'de> Deserialize<'de> for $newtype { + #[inline] + fn deserialize(d: D) -> Result + where + D: Deserializer<'de>, + { + Ok(Self::from_u32(u32::deserialize(d)?)) + } + } + #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for $newtype { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { @@ -67,7 +89,6 @@ impl_u32_wrapper! { /// /// This is a thin wrapper around a `u32` that may take on all values of a `u32`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockHeight(u32); } @@ -128,7 +149,6 @@ impl_u32_wrapper! { /// This type is not meant for constructing relative height based timelocks. It is a general /// purpose block interval abstraction. For locktimes please see [`locktime::relative::NumberOfBlocks`]. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockHeightInterval(u32); } @@ -191,7 +211,6 @@ impl_u32_wrapper! { /// /// This is a thin wrapper around a `u32` that may take on all values of a `u32`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockMtp(u32); } @@ -265,7 +284,6 @@ impl_u32_wrapper! { /// /// This is a thin wrapper around a `u32` that may take on all values of a `u32`. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockMtpInterval(u32); } From f746aecb61456f1eb97280e1d091434250832e72 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 14:04:55 +1000 Subject: [PATCH 109/857] Use NumberOfBlocks in rustdoc --- units/src/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/block.rs b/units/src/block.rs index 6ba9cb838a..f17e8202f7 100644 --- a/units/src/block.rs +++ b/units/src/block.rs @@ -6,7 +6,7 @@ //! //! These are general types for abstracting over block heights, they are not designed to use with //! lock times. If you are creating lock times you should be using the -//! [`locktime::absolute::Height`] and [`locktime::relative::Height`] types. +//! [`locktime::absolute::Height`] and [`locktime::relative::NumberOfBlocks`] types. //! //! The difference between these types and the locktime types is that these types are thin wrappers //! whereas the locktime types contain more complex locktime specific abstractions. From d8377d90dd8d6bd066f51f45c23ffdfe2d0ab694 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 15 May 2025 08:48:37 +1000 Subject: [PATCH 110/857] units: Remove serde derive feature Currently we only need the `derive` feature of `serde` in test code. Observe: - We do not need the error testing logic because `ParseAmountError` is already exhaustively tested. - The rest of the `serde` test logic in `amount` can be done using the public API so it can be moved to the integration test directory. Move the unit test code to `tests/` excluding the error testing logic. Remove the `derive` feature from the `serde` dependency. Add a `dev-dependency` on `serde` that enables the `derive` feature. --- units/Cargo.toml | 3 +- units/src/amount/tests.rs | 206 -------------------------------------- units/tests/serde.rs | 199 ++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 207 deletions(-) diff --git a/units/Cargo.toml b/units/Cargo.toml index 5134003cdd..1bad34a7c9 100644 --- a/units/Cargo.toml +++ b/units/Cargo.toml @@ -20,12 +20,13 @@ alloc = ["internals/alloc","serde?/alloc"] [dependencies] internals = { package = "bitcoin-internals", path = "../internals" } -serde = { version = "1.0.103", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0.103", default-features = false, optional = true } arbitrary = { version = "1.4", optional = true } [dev-dependencies] internals = { package = "bitcoin-internals", path = "../internals", features = ["test-serde"] } bincode = "1.3.1" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } serde_test = "1.0" serde_json = "1.0" diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 1eebfe6f49..9c1d616f16 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -10,9 +10,6 @@ use core::num::{NonZeroI64, NonZeroU64}; #[cfg(feature = "std")] use std::panic; -#[cfg(feature = "serde")] -use ::serde::{Deserialize, Serialize}; - use super::*; #[cfg(feature = "alloc")] use crate::{FeeRate, Weight}; @@ -827,209 +824,6 @@ fn to_string_with_denomination_from_str_roundtrip() { ); } -#[cfg(feature = "serde")] -#[test] -fn serde_as_sat() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct T { - #[serde(with = "crate::amount::serde::as_sat")] - pub amt: Amount, - #[serde(with = "crate::amount::serde::as_sat")] - pub samt: SignedAmount, - } - - serde_test::assert_tokens( - &T { amt: sat(123_456_789), samt: ssat(-123_456_789) }, - &[ - serde_test::Token::Struct { name: "T", len: 2 }, - serde_test::Token::Str("amt"), - serde_test::Token::U64(123_456_789), - serde_test::Token::Str("samt"), - serde_test::Token::I64(-123_456_789), - serde_test::Token::StructEnd, - ], - ); -} - -#[cfg(feature = "serde")] -#[cfg(feature = "alloc")] -#[test] -#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. -fn serde_as_btc() { - use serde_json; - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct T { - #[serde(with = "crate::amount::serde::as_btc")] - pub amt: Amount, - #[serde(with = "crate::amount::serde::as_btc")] - pub samt: SignedAmount, - } - - let orig = T { amt: sat(20_000_000__000_000_01), samt: ssat(-20_000_000__000_000_01) }; - - let json = "{\"amt\": 20000000.00000001, \ - \"samt\": -20000000.00000001}"; - let t: T = serde_json::from_str(json).unwrap(); - assert_eq!(t, orig); - - let value: serde_json::Value = serde_json::from_str(json).unwrap(); - assert_eq!(t, serde_json::from_value(value).unwrap()); - - // errors - let t: Result = - serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}"); - assert!(t.unwrap_err().to_string().contains( - &ParseAmountError(ParseAmountErrorInner::TooPrecise(TooPreciseError { position: 16 })) - .to_string() - )); - let t: Result = serde_json::from_str("{\"amt\": -1, \"samt\": 1}"); - assert!(t.unwrap_err().to_string().contains(&OutOfRangeError::negative().to_string())); -} - -#[cfg(feature = "serde")] -#[cfg(feature = "alloc")] -#[test] -fn serde_as_str() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct T { - #[serde(with = "crate::amount::serde::as_str")] - pub amt: Amount, - #[serde(with = "crate::amount::serde::as_str")] - pub samt: SignedAmount, - } - - serde_test::assert_tokens( - &T { amt: sat(123_456_789), samt: ssat(-123_456_789) }, - &[ - serde_test::Token::Struct { name: "T", len: 2 }, - serde_test::Token::String("amt"), - serde_test::Token::String("1.23456789"), - serde_test::Token::String("samt"), - serde_test::Token::String("-1.23456789"), - serde_test::Token::StructEnd, - ], - ); -} - -#[cfg(feature = "serde")] -#[cfg(feature = "alloc")] -#[test] -#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. -fn serde_as_btc_opt() { - use serde_json; - - #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)] - struct T { - #[serde(default, with = "crate::amount::serde::as_btc::opt")] - pub amt: Option, - #[serde(default, with = "crate::amount::serde::as_btc::opt")] - pub samt: Option, - } - - let with = T { amt: Some(sat(2_500_000_00)), samt: Some(ssat(-2_500_000_00)) }; - let without = T { amt: None, samt: None }; - - // Test Roundtripping - for s in [&with, &without] { - let v = serde_json::to_string(s).unwrap(); - let w: T = serde_json::from_str(&v).unwrap(); - assert_eq!(w, *s); - } - - let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap(); - assert_eq!(t, with); - - let t: T = serde_json::from_str("{}").unwrap(); - assert_eq!(t, without); - - let value_with: serde_json::Value = - serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap(); - assert_eq!(with, serde_json::from_value(value_with).unwrap()); - - let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); - assert_eq!(without, serde_json::from_value(value_without).unwrap()); -} - -#[cfg(feature = "serde")] -#[cfg(feature = "alloc")] -#[test] -#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. -fn serde_as_sat_opt() { - use serde_json; - - #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)] - struct T { - #[serde(default, with = "crate::amount::serde::as_sat::opt")] - pub amt: Option, - #[serde(default, with = "crate::amount::serde::as_sat::opt")] - pub samt: Option, - } - - let with = T { amt: Some(sat(2_500_000_00)), samt: Some(ssat(-2_500_000_00)) }; - let without = T { amt: None, samt: None }; - - // Test Roundtripping - for s in [&with, &without] { - let v = serde_json::to_string(s).unwrap(); - let w: T = serde_json::from_str(&v).unwrap(); - assert_eq!(w, *s); - } - - let t: T = serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap(); - assert_eq!(t, with); - - let t: T = serde_json::from_str("{}").unwrap(); - assert_eq!(t, without); - - let value_with: serde_json::Value = - serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap(); - assert_eq!(with, serde_json::from_value(value_with).unwrap()); - - let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); - assert_eq!(without, serde_json::from_value(value_without).unwrap()); -} - -#[cfg(feature = "serde")] -#[cfg(feature = "alloc")] -#[test] -#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. -fn serde_as_str_opt() { - use serde_json; - - #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)] - struct T { - #[serde(default, with = "crate::amount::serde::as_str::opt")] - pub amt: Option, - #[serde(default, with = "crate::amount::serde::as_str::opt")] - pub samt: Option, - } - - let with = T { amt: Some(sat(123_456_789)), samt: Some(ssat(-123_456_789)) }; - let without = T { amt: None, samt: None }; - - // Test Roundtripping - for s in [&with, &without] { - let v = serde_json::to_string(s).unwrap(); - let w: T = serde_json::from_str(&v).unwrap(); - assert_eq!(w, *s); - } - - let t: T = - serde_json::from_str("{\"amt\": \"1.23456789\", \"samt\": \"-1.23456789\"}").unwrap(); - assert_eq!(t, with); - - let t: T = serde_json::from_str("{}").unwrap(); - assert_eq!(t, without); - - let value_with: serde_json::Value = - serde_json::from_str("{\"amt\": \"1.23456789\", \"samt\": \"-1.23456789\"}").unwrap(); - assert_eq!(with, serde_json::from_value(value_with).unwrap()); - - let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); - assert_eq!(without, serde_json::from_value(value_without).unwrap()); -} - #[test] fn sum_amounts() { assert_eq!([].iter().sum::>(), Amount::ZERO.into()); diff --git a/units/tests/serde.rs b/units/tests/serde.rs index 7a38f046ec..d312a82fbe 100644 --- a/units/tests/serde.rs +++ b/units/tests/serde.rs @@ -88,3 +88,202 @@ fn serde_regression() { let want = include_bytes!("data/serde_bincode"); assert_eq!(got, want); } + +#[track_caller] +fn sat(sat: u64) -> Amount { Amount::from_sat(sat).unwrap() } + +#[track_caller] +fn ssat(ssat: i64) -> SignedAmount { SignedAmount::from_sat(ssat).unwrap() } + +#[cfg(feature = "serde")] +#[test] +fn serde_as_sat() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct T { + #[serde(with = "crate::amount::serde::as_sat")] + pub amt: Amount, + #[serde(with = "crate::amount::serde::as_sat")] + pub samt: SignedAmount, + } + + serde_test::assert_tokens( + &T { amt: sat(123_456_789), samt: ssat(-123_456_789) }, + &[ + serde_test::Token::Struct { name: "T", len: 2 }, + serde_test::Token::Str("amt"), + serde_test::Token::U64(123_456_789), + serde_test::Token::Str("samt"), + serde_test::Token::I64(-123_456_789), + serde_test::Token::StructEnd, + ], + ); +} + +#[cfg(feature = "serde")] +#[cfg(feature = "alloc")] +#[test] +#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. +fn serde_as_btc() { + use serde_json; + + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct T { + #[serde(with = "crate::amount::serde::as_btc")] + pub amt: Amount, + #[serde(with = "crate::amount::serde::as_btc")] + pub samt: SignedAmount, + } + + let orig = T { amt: sat(20_000_000__000_000_01), samt: ssat(-20_000_000__000_000_01) }; + + let json = "{\"amt\": 20000000.00000001, \ + \"samt\": -20000000.00000001}"; + let t: T = serde_json::from_str(json).unwrap(); + assert_eq!(t, orig); + + let value: serde_json::Value = serde_json::from_str(json).unwrap(); + assert_eq!(t, serde_json::from_value(value).unwrap()); +} + +#[cfg(feature = "serde")] +#[cfg(feature = "alloc")] +#[test] +fn serde_as_str() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct T { + #[serde(with = "crate::amount::serde::as_str")] + pub amt: Amount, + #[serde(with = "crate::amount::serde::as_str")] + pub samt: SignedAmount, + } + + serde_test::assert_tokens( + &T { amt: sat(123_456_789), samt: ssat(-123_456_789) }, + &[ + serde_test::Token::Struct { name: "T", len: 2 }, + serde_test::Token::String("amt"), + serde_test::Token::String("1.23456789"), + serde_test::Token::String("samt"), + serde_test::Token::String("-1.23456789"), + serde_test::Token::StructEnd, + ], + ); +} + +#[cfg(feature = "serde")] +#[cfg(feature = "alloc")] +#[test] +#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. +fn serde_as_btc_opt() { + use serde_json; + + #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)] + struct T { + #[serde(default, with = "crate::amount::serde::as_btc::opt")] + pub amt: Option, + #[serde(default, with = "crate::amount::serde::as_btc::opt")] + pub samt: Option, + } + + let with = T { amt: Some(sat(2_500_000_00)), samt: Some(ssat(-2_500_000_00)) }; + let without = T { amt: None, samt: None }; + + // Test Roundtripping + for s in [&with, &without] { + let v = serde_json::to_string(s).unwrap(); + let w: T = serde_json::from_str(&v).unwrap(); + assert_eq!(w, *s); + } + + let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap(); + assert_eq!(t, with); + + let t: T = serde_json::from_str("{}").unwrap(); + assert_eq!(t, without); + + let value_with: serde_json::Value = + serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap(); + assert_eq!(with, serde_json::from_value(value_with).unwrap()); + + let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); + assert_eq!(without, serde_json::from_value(value_without).unwrap()); +} + +#[cfg(feature = "serde")] +#[cfg(feature = "alloc")] +#[test] +#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. +fn serde_as_sat_opt() { + use serde_json; + + #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)] + struct T { + #[serde(default, with = "crate::amount::serde::as_sat::opt")] + pub amt: Option, + #[serde(default, with = "crate::amount::serde::as_sat::opt")] + pub samt: Option, + } + + let with = T { amt: Some(sat(2_500_000_00)), samt: Some(ssat(-2_500_000_00)) }; + let without = T { amt: None, samt: None }; + + // Test Roundtripping + for s in [&with, &without] { + let v = serde_json::to_string(s).unwrap(); + let w: T = serde_json::from_str(&v).unwrap(); + assert_eq!(w, *s); + } + + let t: T = serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap(); + assert_eq!(t, with); + + let t: T = serde_json::from_str("{}").unwrap(); + assert_eq!(t, without); + + let value_with: serde_json::Value = + serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap(); + assert_eq!(with, serde_json::from_value(value_with).unwrap()); + + let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); + assert_eq!(without, serde_json::from_value(value_without).unwrap()); +} + +#[cfg(feature = "serde")] +#[cfg(feature = "alloc")] +#[test] +#[allow(clippy::inconsistent_digit_grouping)] // Group to show 100,000,000 sats per bitcoin. +fn serde_as_str_opt() { + use serde_json; + + #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)] + struct T { + #[serde(default, with = "crate::amount::serde::as_str::opt")] + pub amt: Option, + #[serde(default, with = "crate::amount::serde::as_str::opt")] + pub samt: Option, + } + + let with = T { amt: Some(sat(123_456_789)), samt: Some(ssat(-123_456_789)) }; + let without = T { amt: None, samt: None }; + + // Test Roundtripping + for s in [&with, &without] { + let v = serde_json::to_string(s).unwrap(); + let w: T = serde_json::from_str(&v).unwrap(); + assert_eq!(w, *s); + } + + let t: T = + serde_json::from_str("{\"amt\": \"1.23456789\", \"samt\": \"-1.23456789\"}").unwrap(); + assert_eq!(t, with); + + let t: T = serde_json::from_str("{}").unwrap(); + assert_eq!(t, without); + + let value_with: serde_json::Value = + serde_json::from_str("{\"amt\": \"1.23456789\", \"samt\": \"-1.23456789\"}").unwrap(); + assert_eq!(with, serde_json::from_value(value_with).unwrap()); + + let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); + assert_eq!(without, serde_json::from_value(value_without).unwrap()); +} From f3338655f153834395ff2486a8f965df4453ceeb Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 17:14:16 +0100 Subject: [PATCH 111/857] Test OutPoint edge case to kill mutant There is a mutant found in `FromStr for OutPoint`. Add a test to check an edge case to kill the mutant. --- primitives/src/transaction.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index ef322e62be..6dec85fa60 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -729,9 +729,20 @@ mod tests { // Check the number of bytes OutPoint contributes to the transaction is equal to SIZE let outpoint_size = outpoint.txid.as_byte_array().len() + outpoint.vout.to_le_bytes().len(); assert_eq!(outpoint_size, OutPoint::SIZE); + } - // Check TooLong error - outpoint_str.push_str("0000000000"); + #[test] + #[cfg(feature = "hex")] + fn outpoint_from_str_too_long() { + // Check edge case: length exactly 75 + let mut outpoint_str = "0".repeat(64); + outpoint_str.push_str(":1234567890"); + assert_eq!(outpoint_str.len(), 75); + assert!(outpoint_str.parse::().is_ok()); + + // Check TooLong error (length 76) + outpoint_str.push('0'); + assert_eq!(outpoint_str.len(), 76); let outpoint: Result = outpoint_str.parse(); assert_eq!(outpoint, Err(ParseOutPointError::TooLong)); } From 0b4b17307ded47467845ca19b08ee1b8a2d0df87 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 17:27:20 +0100 Subject: [PATCH 112/857] Test SignedAmount edge case to kill mutant There is a mutant found in `SignedAmount::positive_sub`. Add an edge case to the test to kill the mutant. --- units/src/amount/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 1eebfe6f49..47809e4600 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -259,6 +259,7 @@ fn checked_arithmetic() { #[test] fn positive_sub() { assert_eq!(ssat(10).positive_sub(ssat(7)).unwrap(), ssat(3)); + assert_eq!(ssat(10).positive_sub(ssat(10)).unwrap(), ssat(0)); assert!(ssat(-10).positive_sub(ssat(7)).is_none()); assert!(ssat(10).positive_sub(ssat(-7)).is_none()); assert!(ssat(10).positive_sub(ssat(11)).is_none()); From bd50943234e74047b21c32ef3fdb96a313df5538 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 17:32:30 +0100 Subject: [PATCH 113/857] Add a roundtrip test to kill a mutant There is a mutant found in relative locktime `to_512_second_intervals`. Add a round trip test to kill the mutant. --- units/src/locktime/relative.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 5edafe01ec..ca2fbe8af9 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -307,6 +307,13 @@ mod tests { assert_eq!(NumberOf512Seconds::from_512_second_intervals(1).to_seconds(), 512); } + #[test] + fn from_512_second_intervals_roundtrip() { + let intervals = 100_u16; + let locktime = NumberOf512Seconds::from_512_second_intervals(intervals); + assert_eq!(locktime.to_512_second_intervals(), intervals); + } + #[test] fn from_seconds_ceil_success() { let actual = NumberOf512Seconds::from_seconds_ceil(100).unwrap(); From 5edcc5dad411cf5cc2d51fcb3c55395475c1abad Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 20:35:32 +0100 Subject: [PATCH 114/857] Remove repeated fee_rate test One of the tests is a copy of the test two above it with a similar name. Remove the copy of the test. --- units/src/fee_rate/mod.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 6c223f9562..0a856b7f91 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -383,12 +383,6 @@ mod tests { assert_eq!(fee_rate, FeeRate::from_sat_per_mvb(11_000)); } - #[test] - fn from_sat_per_vb() { - let fee_rate = FeeRate::from_sat_per_vb(10); - assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(2500)); - } - #[test] fn raw_feerate() { let fee_rate = FeeRate::from_sat_per_kwu(749); From ef56baa69670f9c2e453cb981d6f3488247d000c Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 19 Jun 2025 20:37:01 +0100 Subject: [PATCH 115/857] Improve fee_rate test to kill a mutant There is a mutant found in `FeeRate` `to_sat_per_kvb_floor` and `ceil`. Add to the existing test so that all 6 to_sat floor and ceil functions are tested. --- units/src/fee_rate/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 0a856b7f91..b61e24d395 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -384,11 +384,20 @@ mod tests { } #[test] - fn raw_feerate() { - let fee_rate = FeeRate::from_sat_per_kwu(749); - assert_eq!(fee_rate.to_sat_per_kwu_floor(), 749); + fn fee_rate_to_sat_per_x() { + let fee_rate = FeeRate::from_sat_per_mvb(2_000_400); + + // sat/kwu: 2_000_400 / 4_000 = 500.1 + assert_eq!(fee_rate.to_sat_per_kwu_floor(), 500); + assert_eq!(fee_rate.to_sat_per_kwu_ceil(), 501); + + // sat/vB: 2_000_400 / 1_000_000 = 2.0004 assert_eq!(fee_rate.to_sat_per_vb_floor(), 2); assert_eq!(fee_rate.to_sat_per_vb_ceil(), 3); + + // sat/kvb: 2_000_400 / 1_000 = 2_000.4 + assert_eq!(fee_rate.to_sat_per_kvb_floor(), 2_000); + assert_eq!(fee_rate.to_sat_per_kvb_ceil(), 2_001); } #[test] From 64e10686dee5d0c91053cbac73181f442156a985 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 12:59:03 +1000 Subject: [PATCH 116/857] Improve rustdoc examples for absolute locktime Improve the rustdoc examples and fleshing them out, using non-deprecated functions, and returning an error if required (so we can use `?`). --- units/src/locktime/absolute.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index 73102af8d2..50d08ae835 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -65,11 +65,12 @@ impl Height { /// # Examples /// /// ```rust - /// use bitcoin_units::locktime::absolute::Height; + /// use bitcoin_units::locktime::absolute; /// /// let h: u32 = 741521; - /// let height = Height::from_u32(h).expect("invalid height value"); - /// assert_eq!(height.to_consensus_u32(), h); + /// let height = absolute::Height::from_u32(h)?; + /// assert_eq!(height.to_u32(), h); + /// # Ok::<_, absolute::ConversionError>(()) /// ``` #[inline] pub const fn from_u32(n: u32) -> Result { @@ -81,6 +82,14 @@ impl Height { } /// Converts this [`Height`] to a raw `u32` value. + /// + /// # Examples + /// + /// ```rust + /// use bitcoin_units::locktime::absolute; + /// + /// assert_eq!(absolute::Height::MAX.to_u32(), 499_999_999); + /// ``` #[inline] pub const fn to_u32(self) -> u32 { self.0 } @@ -189,11 +198,12 @@ impl MedianTimePast { /// # Examples /// /// ```rust - /// use bitcoin_units::locktime::absolute::MedianTimePast; + /// use bitcoin_units::locktime::absolute; /// /// let t: u32 = 1653195600; // May 22nd, 5am UTC. - /// let time = MedianTimePast::from_u32(t).expect("invalid time value"); - /// assert_eq!(time.to_consensus_u32(), t); + /// let time = absolute::MedianTimePast::from_u32(t)?; + /// assert_eq!(time.to_u32(), t); + /// # Ok::<_, absolute::ConversionError>(()) /// ``` #[inline] pub const fn from_u32(n: u32) -> Result { @@ -205,6 +215,14 @@ impl MedianTimePast { } /// Converts this [`MedianTimePast`] to a raw `u32` value. + /// + /// # Examples + /// + /// ```rust + /// use bitcoin_units::locktime::absolute; + /// + /// assert_eq!(absolute::MedianTimePast::MIN.to_u32(), 500_000_000); + /// ``` #[inline] pub const fn to_u32(self) -> u32 { self.0 } From 64ece63f192a1a8a9b61fe6b84bf98a43d9a0644 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 13:00:13 +1000 Subject: [PATCH 117/857] Add missing whitespace character to rustdoc Fix trivial typo. --- units/src/locktime/absolute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index 50d08ae835..f008665fde 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -228,7 +228,7 @@ impl MedianTimePast { /// Returns true if a transaction with this locktime can be included in the next block. /// - /// `self`is the value of the `LockTime` and if `time` is the median time past of the block at + /// `self` is the value of the `LockTime` and if `time` is the median time past of the block at /// the chain tip then a transaction with this lock can be broadcast for inclusion in the next /// block. #[inline] From ebf92fcb010d126781d4006fb366f342ba56af79 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 13:01:08 +1000 Subject: [PATCH 118/857] Use ASCII in rusdocs Feels unnecessarily fancy, lets just use ASCII. Fix the column width to be below the 100 character conventional width while we are at it. --- units/src/locktime/absolute.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index f008665fde..8f193f2e39 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -153,7 +153,8 @@ impl MedianTimePast { /// The maximum MTP allowable in a locktime (Sun Feb 07 2106 06:28:15 GMT+0000). pub const MAX: Self = MedianTimePast(u32::MAX); - /// Constructs an [`MedianTimePast`] by computing the median‐time‐past from the last 11 block timestamps + /// Constructs an [`MedianTimePast`] by computing the median-time-past from the last + /// 11 block timestamps. /// /// Because block timestamps are not monotonic, this function internally sorts them; /// it is therefore not important what order they appear in the array; use whatever From 70221ffa085e3cd0a50683f788f5e78cdfae04ae Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 13:24:22 +1000 Subject: [PATCH 119/857] Fix link to use new name Use `NumberOfBlocks` not the `Height` alias. Fixes link. --- units/src/locktime/relative.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 5edafe01ec..418852dc9e 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -30,7 +30,7 @@ impl NumberOfBlocks { #[inline] pub const fn from_height(blocks: u16) -> Self { Self(blocks) } - /// Express the [`Height`] as a count of blocks. + /// Express the [`NumberOfBlocks`] as a count of blocks. #[inline] #[must_use] pub const fn to_height(self) -> u16 { self.0 } From a6ab5c9fd0516f03f67a8075affed18c8c6b7245 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 19 Jun 2025 12:37:36 +1000 Subject: [PATCH 120/857] Implement Arbitrary for result types Implement `Arbitrary` for the `NumOpResult` and `MathOp` types from the `result` module. --- units/src/result.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/units/src/result.rs b/units/src/result.rs index 36f9094e0e..18f968ea57 100644 --- a/units/src/result.rs +++ b/units/src/result.rs @@ -5,6 +5,8 @@ use core::convert::Infallible; use core::fmt; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use NumOpResult as R; use crate::{Amount, FeeRate, SignedAmount, Weight}; @@ -320,6 +322,32 @@ impl fmt::Display for MathOp { } } +#[cfg(feature = "arbitrary")] +impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for NumOpResult { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let choice = u.int_in_range(0..=1)?; + match choice { + 0 => Ok(NumOpResult::Valid(T::arbitrary(u)?)), + _ => Ok(NumOpResult::Error(NumOpError(MathOp::arbitrary(u)?))), + } + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for MathOp { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let choice = u.int_in_range(0..=5)?; + match choice { + 0 => Ok(MathOp::Add), + 1 => Ok(MathOp::Sub), + 2 => Ok(MathOp::Mul), + 3 => Ok(MathOp::Div), + 4 => Ok(MathOp::Rem), + _ => Ok(MathOp::Neg), + } + } +} + #[cfg(test)] mod tests { use crate::MathOp; From 2b07f59545de16b66b3bf8ee988757c2d0c14afb Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 18 Jun 2025 10:45:01 +1000 Subject: [PATCH 121/857] units: Fix up the api test A lot has changed over the last few months. Fix up the API integration test to match the current state of the crate. --- units/tests/api.rs | 185 ++++++++++++++++++++++++--------------------- 1 file changed, 99 insertions(+), 86 deletions(-) diff --git a/units/tests/api.rs b/units/tests/api.rs index f3115ecfc9..c5db6da465 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -12,39 +12,49 @@ #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; // These imports test "typical" usage by user code. -use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::Height`. +use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::LockTime`. use bitcoin_units::{ - amount, block, fee_rate, locktime, parse, weight, Amount, BlockHeight, BlockInterval, BlockMtp, - BlockMtpInterval, BlockTime, CheckedSum, FeeRate, SignedAmount, Weight, + amount, block, fee_rate, locktime, parse, time, weight, Amount, BlockHeight, + BlockHeightInterval, BlockMtp, BlockMtpInterval, BlockTime, CheckedSum, FeeRate, MathOp, + NumOpResult, SignedAmount, Weight, }; /// A struct that includes all public non-error enums. #[derive(Debug)] // All public types implement Debug (C-DEBUG). struct Enums { a: amount::Denomination, + b: NumOpResult, + c: MathOp, } impl Enums { - fn new() -> Self { Self { a: amount::Denomination::Bitcoin } } + fn new() -> Self { + Self { + a: amount::Denomination::Bitcoin, + b: NumOpResult::Valid(Amount::MAX), + c: MathOp::Add, + } + } } /// A struct that includes all public non-error structs. #[derive(Debug)] // All public types implement Debug (C-DEBUG). struct Structs { - a: Amount, + // Full path to show alphabetic sort order. + a: amount::Amount, b: amount::Display, - c: SignedAmount, - d: BlockHeight, - e: BlockInterval, - f: FeeRate, - g: absolute::Height, - h: absolute::MedianTimePast, - i: relative::Height, - j: relative::Time, - k: Weight, - l: BlockTime, - m: BlockMtp, - n: BlockMtpInterval, + c: amount::SignedAmount, + d: block::BlockHeight, + e: block::BlockHeightInterval, + f: block::BlockMtp, + g: block::BlockMtpInterval, + h: fee_rate::FeeRate, + i: locktime::absolute::Height, + j: locktime::absolute::MedianTimePast, + k: locktime::relative::NumberOf512Seconds, + l: locktime::relative::NumberOfBlocks, + m: time::BlockTime, + n: weight::Weight, } impl Structs { @@ -54,16 +64,16 @@ impl Structs { b: Amount::MAX.display_in(amount::Denomination::Bitcoin), c: SignedAmount::MAX, d: BlockHeight::MAX, - e: BlockInterval::MAX, - f: FeeRate::MAX, - g: absolute::Height::MAX, - h: absolute::MedianTimePast::MAX, - i: relative::Height::MAX, - j: relative::Time::MAX, - k: Weight::MAX, - l: BlockTime::from_u32(u32::MAX), - m: BlockMtp::MAX, - n: BlockMtpInterval::MAX, + e: BlockHeightInterval::MAX, + f: BlockMtp::MAX, + g: BlockMtpInterval::MAX, + h: FeeRate::MAX, + i: absolute::Height::MAX, + j: absolute::MedianTimePast::MAX, + k: relative::NumberOf512Seconds::MAX, + l: relative::NumberOfBlocks::MAX, + m: BlockTime::from_u32(u32::MAX), + n: Weight::MAX, } } } @@ -83,19 +93,21 @@ impl Types { // C-COMMON-TRAITS excluding `Default` and `Display`. `Display` is done in `./str.rs`. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct CommonTraits { - a: Amount, - c: SignedAmount, - d: BlockHeight, - e: BlockInterval, - f: FeeRate, - g: absolute::Height, - h: absolute::MedianTimePast, - i: relative::Height, - j: relative::Time, - k: Weight, - l: BlockTime, - m: BlockMtp, - n: BlockMtpInterval, + // Full path to show alphabetic sort order. + a: amount::Amount, + // b: amount::Display, + c: amount::SignedAmount, + d: block::BlockHeight, + e: block::BlockHeightInterval, + f: block::BlockMtp, + g: block::BlockMtpInterval, + h: fee_rate::FeeRate, + i: locktime::absolute::Height, + j: locktime::absolute::MedianTimePast, + k: locktime::relative::NumberOf512Seconds, + l: locktime::relative::NumberOfBlocks, + m: time::BlockTime, + n: weight::Weight, } /// A struct that includes all types that implement `Default`. @@ -103,10 +115,10 @@ struct CommonTraits { struct Default { a: Amount, b: SignedAmount, - c: BlockInterval, - d: relative::Height, - e: relative::Time, - f: BlockMtpInterval, + c: BlockHeightInterval, + d: BlockMtpInterval, + e: relative::NumberOf512Seconds, + f: relative::NumberOfBlocks, } /// A struct that includes all public error types. @@ -124,28 +136,18 @@ struct Errors { i: amount::PossiblyConfusingDenominationError, j: amount::TooPreciseError, k: amount::UnknownDenominationError, - l: amount::InputTooLargeError, - m: amount::InvalidCharacterError, - n: amount::MissingDenominationError, - o: amount::MissingDigitsError, - p: amount::OutOfRangeError, - q: amount::ParseAmountError, - r: amount::ParseDenominationError, - s: amount::ParseError, - t: amount::PossiblyConfusingDenominationError, - u: amount::TooPreciseError, - v: amount::UnknownDenominationError, - w: block::TooBigForRelativeHeightError, - x: locktime::absolute::ConversionError, - y: locktime::absolute::Height, - z: locktime::absolute::ParseHeightError, - aa: locktime::absolute::ParseTimeError, - ab: locktime::relative::TimeOverflowError, - ac: locktime::relative::InvalidHeightError, - ad: locktime::relative::InvalidTimeError, - ae: parse::ParseIntError, - af: parse::PrefixedHexError, - ag: parse::UnprefixedHexError, + l: block::TooBigForRelativeHeightError, + #[cfg(feature = "serde")] + m: fee_rate::serde::OverflowError, + n: locktime::absolute::ConversionError, + o: locktime::absolute::ParseHeightError, + p: locktime::absolute::ParseTimeError, + q: locktime::relative::InvalidHeightError, + r: locktime::relative::InvalidTimeError, + s: locktime::relative::TimeOverflowError, + t: parse::ParseIntError, + u: parse::PrefixedHexError, + v: parse::UnprefixedHexError, } #[test] @@ -156,8 +158,8 @@ fn api_can_use_modules_from_crate_root() { #[test] fn api_can_use_types_from_crate_root() { use bitcoin_units::{ - Amount, BlockHeight, BlockInterval, BlockMtp, BlockMtpInterval, BlockTime, FeeRate, - SignedAmount, Weight, + Amount, BlockHeight, BlockHeightInterval, BlockInterval, BlockMtp, BlockMtpInterval, + BlockTime, FeeRate, MathOp, NumOpError, NumOpResult, SignedAmount, Weight, }; } @@ -173,11 +175,15 @@ fn api_can_use_all_types_from_module_amount() { #[test] fn api_can_use_all_types_from_module_block() { - use bitcoin_units::block::{BlockHeight, BlockHeightInterval, TooBigForRelativeHeightError}; + use bitcoin_units::block::{ + BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval, TooBigForRelativeHeightError, + }; } #[test] fn api_can_use_all_types_from_module_fee_rate() { + #[cfg(feature = "serde")] + use bitcoin_units::fee_rate::serde::OverflowError; use bitcoin_units::fee_rate::FeeRate; } @@ -190,7 +196,10 @@ fn api_can_use_all_types_from_module_locktime_absolute() { #[test] fn api_can_use_all_types_from_module_locktime_relative() { - use bitcoin_units::locktime::relative::{Height, Time, TimeOverflowError}; + use bitcoin_units::locktime::relative::{ + Height, InvalidHeightError, InvalidTimeError, NumberOf512Seconds, NumberOfBlocks, Time, + TimeOverflowError, + }; } #[test] @@ -262,10 +271,10 @@ fn regression_default() { let want = Default { a: Amount::ZERO, b: SignedAmount::ZERO, - c: BlockInterval::ZERO, - d: relative::Height::ZERO, - e: relative::Time::ZERO, - f: BlockMtpInterval::ZERO, + c: BlockHeightInterval::ZERO, + d: BlockMtpInterval::ZERO, + e: relative::NumberOf512Seconds::ZERO, + f: relative::NumberOfBlocks::ZERO, }; assert_eq!(got, want); } @@ -279,7 +288,7 @@ fn dyn_compatible() { // These traits are explicitly not dyn compatible. // b: Box, // c: Box, - // d: Box, + // d: Box, // Because of core::num::ParseIntError } } @@ -300,16 +309,16 @@ impl<'a> Arbitrary<'a> for Structs { b: Amount::MAX.display_in(amount::Denomination::Bitcoin), c: SignedAmount::arbitrary(u)?, d: BlockHeight::arbitrary(u)?, - e: BlockInterval::arbitrary(u)?, - f: FeeRate::arbitrary(u)?, - g: absolute::Height::arbitrary(u)?, - h: absolute::MedianTimePast::arbitrary(u)?, - i: relative::Height::arbitrary(u)?, - j: relative::Time::arbitrary(u)?, - k: Weight::arbitrary(u)?, - l: BlockTime::arbitrary(u)?, - m: BlockMtp::arbitrary(u)?, - n: BlockMtpInterval::arbitrary(u)?, + e: BlockHeightInterval::arbitrary(u)?, + f: BlockMtp::arbitrary(u)?, + g: BlockMtpInterval::arbitrary(u)?, + h: FeeRate::arbitrary(u)?, + i: absolute::Height::arbitrary(u)?, + j: absolute::MedianTimePast::arbitrary(u)?, + k: relative::NumberOf512Seconds::arbitrary(u)?, + l: relative::NumberOfBlocks::arbitrary(u)?, + m: BlockTime::arbitrary(u)?, + n: Weight::arbitrary(u)?, }; Ok(a) } @@ -318,7 +327,11 @@ impl<'a> Arbitrary<'a> for Structs { #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Enums { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - let a = Enums { a: amount::Denomination::arbitrary(u)? }; + let a = Enums { + a: amount::Denomination::arbitrary(u)?, + b: NumOpResult::::arbitrary(u)?, + c: MathOp::arbitrary(u)?, + }; Ok(a) } } From c06028585189bfb0f76f0e34bf10ec20573d5d71 Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 22 Jun 2025 01:46:07 +0000 Subject: [PATCH 122/857] 2025-06-22 automated rustfmt nightly --- bitcoin/src/bip32.rs | 2 +- .../bitcoin/p2p_address_roundtrip.rs | 2 +- p2p/src/address.rs | 5 +-- p2p/src/consensus.rs | 4 ++- p2p/src/lib.rs | 31 ++++++++++++------- p2p/src/message.rs | 17 +++++----- p2p/src/message_blockdata.rs | 6 ++-- p2p/src/message_bloom.rs | 2 +- p2p/src/message_compact_blocks.rs | 1 + p2p/src/message_filter.rs | 4 +-- p2p/src/message_network.rs | 4 +-- units/src/fee_rate/mod.rs | 10 +++--- 12 files changed, 49 insertions(+), 39 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 07f0c67b3e..23b7d368c6 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -1179,7 +1179,7 @@ mod tests { fn test_upperhex_formatting() { let normal = Normal { index: 42 }; let hardened = Hardened { index: 42 }; - + assert_eq!(format!("{:X}", normal), "2A"); assert_eq!(format!("{:#X}", normal), "0x2A"); diff --git a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs index 5fba06632b..91d2ba02a3 100644 --- a/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs +++ b/fuzz/fuzz_targets/bitcoin/p2p_address_roundtrip.rs @@ -2,8 +2,8 @@ use std::convert::TryFrom; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use bitcoin::consensus::Decodable; -use p2p::address::AddrV2; use honggfuzz::fuzz; +use p2p::address::AddrV2; fn do_test(data: &[u8]) { if data.len() < 2 { diff --git a/p2p/src/address.rs b/p2p/src/address.rs index f83c705638..aaafdabb00 100644 --- a/p2p/src/address.rs +++ b/p2p/src/address.rs @@ -8,9 +8,9 @@ use core::{fmt, iter}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt}; use io::{BufRead, Read, Write}; -use bitcoin::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt}; use crate::ServiceFlags; /// A message which can be sent on the Bitcoin network @@ -206,7 +206,8 @@ impl Encodable for AddrV2 { network: u8, bytes: &[u8], ) -> Result { - Ok(network.consensus_encode(w)? + crate::consensus::consensus_encode_with_size(bytes, w)?) + Ok(network.consensus_encode(w)? + + crate::consensus::consensus_encode_with_size(bytes, w)?) } Ok(match *self { AddrV2::Ipv4(ref addr) => encode_addr(w, 1, &addr.octets())?, diff --git a/p2p/src/consensus.rs b/p2p/src/consensus.rs index 68ea527d49..57a4ae6942 100644 --- a/p2p/src/consensus.rs +++ b/p2p/src/consensus.rs @@ -9,7 +9,9 @@ pub(crate) fn consensus_encode_with_size( } pub(crate) fn parse_failed_error(msg: &'static str) -> bitcoin::consensus::encode::Error { - bitcoin::consensus::encode::Error::Parse(bitcoin::consensus::encode::ParseError::ParseFailed(msg)) + bitcoin::consensus::encode::Error::Parse(bitcoin::consensus::encode::ParseError::ParseFailed( + msg, + )) } macro_rules! impl_consensus_encoding { diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index 3250263187..a430eafe7d 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -16,28 +16,26 @@ #![allow(clippy::uninlined_format_args)] // Allow `format!("{}", x)`instead of enforcing `format!("{x}")` pub mod address; +mod consensus; pub mod message; pub mod message_blockdata; pub mod message_bloom; pub mod message_compact_blocks; pub mod message_filter; pub mod message_network; -mod consensus; extern crate alloc; use core::str::FromStr; use core::{fmt, ops}; - use std::borrow::{Borrow, BorrowMut, ToOwned}; +use bitcoin::consensus::encode::{self, Decodable, Encodable}; +use bitcoin::network::{Network, Params, TestnetVersion}; use hex::FromHex; use internals::impl_to_hex_from_lower_hex; use io::{BufRead, Write}; -use bitcoin::consensus::encode::{self, Decodable, Encodable}; -use bitcoin::network::{Network, Params, TestnetVersion}; - #[rustfmt::skip] #[doc(inline)] pub use self::address::Address; @@ -243,7 +241,9 @@ impl Magic { pub fn to_bytes(self) -> [u8; 4] { self.0 } /// Returns the magic bytes for the network defined by `params`. - pub fn from_params(params: impl AsRef) -> Option { params.as_ref().network.try_into().ok() } + pub fn from_params(params: impl AsRef) -> Option { + params.as_ref().network.try_into().ok() + } } impl FromStr for Magic { @@ -409,9 +409,10 @@ impl std::error::Error for UnknownNetworkError { #[cfg(test)] mod tests { - use super::*; use bitcoin::consensus::encode::{deserialize, serialize}; + use super::*; + #[test] fn serialize_deserialize() { assert_eq!(serialize(&Magic::BITCOIN), &[0xf9, 0xbe, 0xb4, 0xd9]); @@ -430,7 +431,10 @@ mod tests { let magic: Magic = Network::Regtest.try_into().unwrap(); assert_eq!(serialize(&magic), &[0xfa, 0xbf, 0xb5, 0xda]); - assert_eq!(deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Network::Bitcoin.try_into().ok()); + assert_eq!( + deserialize::(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), + Network::Bitcoin.try_into().ok() + ); assert_eq!( deserialize::(&[0x0b, 0x11, 0x09, 0x07]).ok(), Network::Testnet(TestnetVersion::V3).try_into().ok() @@ -439,11 +443,16 @@ mod tests { deserialize::(&[0x1c, 0x16, 0x3f, 0x28]).ok(), Network::Testnet(TestnetVersion::V4).try_into().ok() ); - assert_eq!(deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Network::Signet.try_into().ok()); - assert_eq!(deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Network::Regtest.try_into().ok()); + assert_eq!( + deserialize::(&[0x0a, 0x03, 0xcf, 0x40]).ok(), + Network::Signet.try_into().ok() + ); + assert_eq!( + deserialize::(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), + Network::Regtest.try_into().ok() + ); } - #[test] fn service_flags_test() { let all = [ diff --git a/p2p/src/message.rs b/p2p/src/message.rs index c83bfde917..2d4c60f61e 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -6,23 +6,22 @@ //! are used for (de)serializing Bitcoin objects for transmission on the network. use core::{fmt, iter}; -use std::borrow::Cow; +use std::borrow::{Cow, ToOwned}; use std::boxed::Box; -use std::borrow::ToOwned; +use bitcoin::consensus::encode::{self, CheckedData, Decodable, Encodable, ReadExt, WriteExt}; +use bitcoin::merkle_tree::MerkleBlock; +use bitcoin::{block, transaction}; use hashes::sha256d; use internals::ToU64 as _; use io::{BufRead, Write}; -use bitcoin::consensus::encode::{self, CheckedData, Decodable, Encodable, ReadExt, WriteExt}; -use bitcoin::merkle_tree::MerkleBlock; use crate::address::{AddrV2Message, Address}; use crate::consensus::impl_vec_wrapper; use crate::{ message_blockdata, message_bloom, message_compact_blocks, message_filter, message_network, Magic, }; -use bitcoin::{block, transaction}; /// The maximum number of [super::message_blockdata::Inventory] items in an `inv` message. /// @@ -715,16 +714,16 @@ impl Decodable for V2NetworkMessage { mod test { use std::net::Ipv4Addr; - use hex_lit::hex; - use units::BlockHeight; - - use super::*; use bitcoin::bip152::BlockTransactionsRequest; use bitcoin::bip158::{FilterHash, FilterHeader}; use bitcoin::block::{Block, BlockHash}; use bitcoin::consensus::encode::{deserialize, deserialize_partial, serialize}; use bitcoin::script::ScriptBuf; use bitcoin::transaction::{Transaction, Txid}; + use hex_lit::hex; + use units::BlockHeight; + + use super::*; use crate::address::AddrV2; use crate::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory}; use crate::message_bloom::{BloomFlags, FilterAdd, FilterLoad}; diff --git a/p2p/src/message_blockdata.rs b/p2p/src/message_blockdata.rs index e2c388af7d..bf010593c5 100644 --- a/p2p/src/message_blockdata.rs +++ b/p2p/src/message_blockdata.rs @@ -5,11 +5,11 @@ //! This module describes network messages which are used for passing //! Bitcoin data (blocks and transactions) around. -use io::{BufRead, Write}; - use bitcoin::block::BlockHash; use bitcoin::consensus::encode::{self, Decodable, Encodable}; use bitcoin::transaction::{Txid, Wtxid}; +use io::{BufRead, Write}; + use crate::consensus::impl_consensus_encoding; /// An inventory item. @@ -143,10 +143,10 @@ impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash); #[cfg(test)] mod tests { + use bitcoin::consensus::encode::{deserialize, serialize}; use hex_lit::hex; use super::*; - use bitcoin::consensus::encode::{deserialize, serialize}; #[test] fn getblocks_message() { diff --git a/p2p/src/message_bloom.rs b/p2p/src/message_bloom.rs index 69f079da2f..762c05e324 100644 --- a/p2p/src/message_bloom.rs +++ b/p2p/src/message_bloom.rs @@ -4,9 +4,9 @@ //! //! This module describes BIP37 Connection Bloom filtering network messages. +use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; use io::{BufRead, Write}; -use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; use crate::consensus::impl_consensus_encoding; /// `filterload` message sets the current bloom filter diff --git a/p2p/src/message_compact_blocks.rs b/p2p/src/message_compact_blocks.rs index 9b6735c0d9..a87bd05954 100644 --- a/p2p/src/message_compact_blocks.rs +++ b/p2p/src/message_compact_blocks.rs @@ -4,6 +4,7 @@ //! BIP152 Compact Blocks network messages use bitcoin::bip152; + use crate::consensus::impl_consensus_encoding; /// sendcmpct message diff --git a/p2p/src/message_filter.rs b/p2p/src/message_filter.rs index 65c9c3d7c9..83fb461b76 100644 --- a/p2p/src/message_filter.rs +++ b/p2p/src/message_filter.rs @@ -4,10 +4,10 @@ //! //! This module describes BIP157 Client Side Block Filtering network messages. -use units::BlockHeight; - use bitcoin::bip158::{FilterHash, FilterHeader}; use bitcoin::block::BlockHash; +use units::BlockHeight; + use crate::consensus::impl_consensus_encoding; /// getcfilters message diff --git a/p2p/src/message_network.rs b/p2p/src/message_network.rs index 258221a0cd..f43ed5705c 100644 --- a/p2p/src/message_network.rs +++ b/p2p/src/message_network.rs @@ -6,10 +6,10 @@ //! capabilities. use std::borrow::Cow; +use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; use hashes::sha256d; use io::{BufRead, Write}; -use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; use crate::address::Address; use crate::consensus::impl_consensus_encoding; use crate::ServiceFlags; @@ -147,10 +147,10 @@ impl_consensus_encoding!(Reject, message, ccode, reason, hash); #[cfg(test)] mod tests { + use bitcoin::consensus::encode::{deserialize, serialize}; use hex_lit::hex; use super::*; - use bitcoin::consensus::encode::{deserialize, serialize}; #[test] fn version_message_test() { diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 6c223f9562..83a6b654bd 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -399,9 +399,8 @@ mod tests { #[test] fn checked_mul() { - let fee_rate = FeeRate::from_sat_per_kwu(10) - .checked_mul(10) - .expect("expected feerate in sat/kwu"); + let fee_rate = + FeeRate::from_sat_per_kwu(10).checked_mul(10).expect("expected feerate in sat/kwu"); assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(100)); let fee_rate = FeeRate::from_sat_per_kwu(10).checked_mul(u64::MAX); @@ -410,9 +409,8 @@ mod tests { #[test] fn checked_div() { - let fee_rate = FeeRate::from_sat_per_kwu(10) - .checked_div(10) - .expect("expected feerate in sat/kwu"); + let fee_rate = + FeeRate::from_sat_per_kwu(10).checked_div(10).expect("expected feerate in sat/kwu"); assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(1)); let fee_rate = FeeRate::from_sat_per_kwu(10).checked_div(0); From 9d4381c8fe636d2d1d63b394b246e939f1192de7 Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Sun, 15 Jun 2025 23:14:26 -0500 Subject: [PATCH 123/857] Improve `Xpriv::derive_xpriv` and `Xpub::derive_xpub` ergonomics This change enables references to slices, arrays, and Vecs to be passed to derive methods. --- bitcoin/src/bip32.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 23b7d368c6..b7659e0723 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -756,7 +756,7 @@ impl Xpriv { pub fn derive_priv>( &self, secp: &Secp256k1, - path: &P, + path: P, ) -> Result { self.derive_xpriv(secp, path) } @@ -767,7 +767,7 @@ impl Xpriv { pub fn derive_xpriv>( &self, secp: &Secp256k1, - path: &P, + path: P, ) -> Result { let mut sk: Xpriv = *self; for cnum in path.as_ref() { @@ -910,7 +910,7 @@ impl Xpub { pub fn derive_pub>( &self, secp: &Secp256k1, - path: &P, + path: P, ) -> Result { self.derive_xpub(secp, path) } @@ -921,7 +921,7 @@ impl Xpub { pub fn derive_xpub>( &self, secp: &Secp256k1, - path: &P, + path: P, ) -> Result { let mut pk: Xpub = *self; for cnum in path.as_ref() { From c7bdec14fbf79097c4d73051cc0d594cf9b61e8b Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Tue, 17 Jun 2025 14:37:23 -0500 Subject: [PATCH 124/857] Fix clippy lint and formatting for `Xpriv::derive_xpriv` and `Xpriv::derive_xpub` calls --- bitcoin/examples/bip32.rs | 2 +- bitcoin/examples/ecdsa-psbt-simple.rs | 4 ++-- bitcoin/examples/ecdsa-psbt.rs | 2 +- bitcoin/examples/taproot-psbt-simple.rs | 4 ++-- bitcoin/examples/taproot-psbt.rs | 11 ++++------- bitcoin/src/psbt/mod.rs | 2 +- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/bitcoin/examples/bip32.rs b/bitcoin/examples/bip32.rs index 41f3791ea6..d8edab2fc3 100644 --- a/bitcoin/examples/bip32.rs +++ b/bitcoin/examples/bip32.rs @@ -46,7 +46,7 @@ fn main() { // generate first receiving address at m/0/0 // manually creating indexes this time let zero = ChildNumber::ZERO_NORMAL; - let public_key = xpub.derive_xpub(&secp, &[zero, zero]).unwrap().public_key; + let public_key = xpub.derive_xpub(&secp, [zero, zero]).unwrap().public_key; let address = Address::p2wpkh(CompressedPublicKey(public_key), KnownHrp::Mainnet); println!("First receiving address: {address}"); } diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs index 73f209bb2e..1798f6edfb 100644 --- a/bitcoin/examples/ecdsa-psbt-simple.rs +++ b/bitcoin/examples/ecdsa-psbt-simple.rs @@ -67,7 +67,7 @@ fn get_external_address_xpriv( let external_index = ChildNumber::ZERO_NORMAL; let idx = ChildNumber::from_normal_idx(index).expect("valid index number"); - child_xpriv.derive_xpriv(secp, &[external_index, idx]).expect("only deriving two more steps") + child_xpriv.derive_xpriv(secp, [external_index, idx]).expect("only deriving two more steps") } // Derive the internal address xpriv. @@ -83,7 +83,7 @@ fn get_internal_address_xpriv( let internal_index = ChildNumber::ONE_NORMAL; let idx = ChildNumber::from_normal_idx(index).expect("valid index number"); - child_xpriv.derive_xpriv(secp, &[internal_index, idx]).expect("only deriving two more steps") + child_xpriv.derive_xpriv(secp, [internal_index, idx]).expect("only deriving two more steps") } // The address to send to. diff --git a/bitcoin/examples/ecdsa-psbt.rs b/bitcoin/examples/ecdsa-psbt.rs index 0ac297654c..f16a9dc12d 100644 --- a/bitcoin/examples/ecdsa-psbt.rs +++ b/bitcoin/examples/ecdsa-psbt.rs @@ -260,7 +260,7 @@ impl WatchOnly { secp: &Secp256k1, ) -> Result<(CompressedPublicKey, Address, DerivationPath)> { let path = [ChildNumber::ONE_NORMAL, ChildNumber::ZERO_NORMAL]; - let derived = self.account_0_xpub.derive_xpub(secp, &path)?; + let derived = self.account_0_xpub.derive_xpub(secp, path)?; let pk = derived.to_public_key(); let addr = Address::p2wpkh(pk, NETWORK); diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index c35dbe4635..4260610729 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -65,7 +65,7 @@ fn get_external_address_xpriv( let external_index = ChildNumber::ZERO_NORMAL; let idx = ChildNumber::from_normal_idx(index).expect("valid index number"); - child_xpriv.derive_xpriv(secp, &[external_index, idx]).expect("only deriving two more steps") + child_xpriv.derive_xpriv(secp, [external_index, idx]).expect("only deriving two more steps") } // Derive the internal address xpriv. @@ -81,7 +81,7 @@ fn get_internal_address_xpriv( let internal_index = ChildNumber::ONE_NORMAL; let idx = ChildNumber::from_normal_idx(index).expect("valid index number"); - child_xpriv.derive_xpriv(secp, &[internal_index, idx]).expect("only deriving two more steps") + child_xpriv.derive_xpriv(secp, [internal_index, idx]).expect("only deriving two more steps") } // Get the Taproot Key Origin. diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index 39b70f9f4e..e850a4567b 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -298,7 +298,7 @@ fn generate_bip86_key_spend_tx( .ok_or("missing Taproot key origin")?; let secret_key = - master_xpriv.derive_xpriv(secp, &derivation_path)?.to_private_key().inner; + master_xpriv.derive_xpriv(secp, derivation_path)?.to_private_key().inner; sign_psbt_taproot( secret_key, input.tap_internal_key.unwrap(), @@ -540,7 +540,7 @@ impl BenefactorWallet { .ok_or("missing Taproot key origin")?; let secret_key = self .master_xpriv - .derive_xpriv(&self.secp, &derivation_path) + .derive_xpriv(&self.secp, derivation_path) .expect("derivation path is short") .to_private_key() .inner; @@ -664,11 +664,8 @@ impl BeneficiaryWallet { for (x_only_pubkey, (leaf_hashes, (_, derivation_path))) in &psbt.inputs[0].tap_key_origins.clone() { - let secret_key = self - .master_xpriv - .derive_xpriv(&self.secp, &derivation_path)? - .to_private_key() - .inner; + let secret_key = + self.master_xpriv.derive_xpriv(&self.secp, derivation_path)?.to_private_key().inner; for lh in leaf_hashes { let sighash_type = TapSighashType::All; let hash = SighashCache::new(&unsigned_tx).taproot_script_spend_signature_hash( diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index e78328feef..a4a0275f14 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -814,7 +814,7 @@ impl GetKey for Xpriv { KeyRequest::XOnlyPubkey(_) => Err(GetKeyError::NotSupported), KeyRequest::Bip32((fingerprint, path)) => { let key = if self.fingerprint(secp) == *fingerprint { - let k = self.derive_xpriv(secp, &path).map_err(GetKeyError::Bip32)?; + let k = self.derive_xpriv(secp, path).map_err(GetKeyError::Bip32)?; Some(k.to_private_key()) } else if self.parent_fingerprint == *fingerprint && !path.is_empty() From bd3f4b6bf12b2832cfb3bb11bc0a0e52e1057fe7 Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Thu, 19 Jun 2025 16:45:43 -0500 Subject: [PATCH 125/857] psbt: Add test for GetKey bip32 --- bitcoin/src/psbt/mod.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index a4a0275f14..81f197cfce 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -2397,6 +2397,27 @@ mod tests { ); } + #[test] + fn get_key_xpriv_bip32_parent() { + let secp = Secp256k1::new(); + + let seed = hex!("000102030405060708090a0b0c0d0e0f"); + let parent_xpriv: Xpriv = Xpriv::new_master(NetworkKind::Main, &seed); + let path: DerivationPath = "m/1/2/3".parse().unwrap(); + let path_prefix: DerivationPath = "m/1".parse().unwrap(); + + let expected_private_key = + parent_xpriv.derive_xpriv(&secp, &path).unwrap().to_private_key(); + + let derived_xpriv = parent_xpriv.derive_xpriv(&secp, &path_prefix).unwrap(); + + let derived_key = derived_xpriv + .get_key(&KeyRequest::Bip32((parent_xpriv.fingerprint(&secp), path.clone())), &secp) + .unwrap(); + + assert_eq!(derived_key, Some(expected_private_key)); + } + #[test] fn fee() { let output_0_val = Amount::from_sat_u32(99_999_699); From 352712257e66c7959b80a9f6375961295a292306 Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Thu, 19 Jun 2025 16:47:51 -0500 Subject: [PATCH 126/857] psbt: Use new `derive_xpriv` flexibility in GetKey --- bitcoin/src/psbt/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 81f197cfce..9de21061a2 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -21,7 +21,7 @@ use std::collections::{HashMap, HashSet}; use internals::write_err; use secp256k1::{Keypair, Message, Secp256k1, Signing, Verification}; -use crate::bip32::{self, DerivationPath, KeySource, Xpriv, Xpub}; +use crate::bip32::{self, KeySource, Xpriv, Xpub}; use crate::crypto::key::{PrivateKey, PublicKey}; use crate::crypto::{ecdsa, taproot}; use crate::key::{TapTweak, XOnlyPublicKey}; @@ -820,8 +820,7 @@ impl GetKey for Xpriv { && !path.is_empty() && path[0] == self.child_number { - let path = DerivationPath::from_iter(path.into_iter().skip(1).copied()); - let k = self.derive_xpriv(secp, &path).map_err(GetKeyError::Bip32)?; + let k = self.derive_xpriv(secp, &path[1..]).map_err(GetKeyError::Bip32)?; Some(k.to_private_key()) } else { None @@ -1330,7 +1329,7 @@ mod tests { #[cfg(feature = "rand-std")] use { crate::address::script_pubkey::ScriptBufExt as _, - crate::bip32::{DerivationPath, Fingerprint}, + crate::bip32::Fingerprint, crate::locktime, crate::witness_version::WitnessVersion, crate::WitnessProgram, @@ -1339,7 +1338,7 @@ mod tests { use super::*; use crate::address::script_pubkey::ScriptExt as _; - use crate::bip32::ChildNumber; + use crate::bip32::{ChildNumber, DerivationPath}; use crate::locktime::absolute; use crate::network::NetworkKind; use crate::psbt::serialize::{Deserialize, Serialize}; From f22f10b5cab3d70fe31256e0cb462aedeab0879e Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 24 Jun 2025 12:06:06 +0100 Subject: [PATCH 127/857] Simplify PartialOrd implementation Lint error with new nightly version "non-canonical implementation of `partial_cmp` on an `Ord` type". Update to directly call instead of dereferencing first. --- bitcoin/src/taproot/serialized_signature.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/taproot/serialized_signature.rs b/bitcoin/src/taproot/serialized_signature.rs index a63af0fe21..60a71584f2 100644 --- a/bitcoin/src/taproot/serialized_signature.rs +++ b/bitcoin/src/taproot/serialized_signature.rs @@ -49,7 +49,7 @@ impl PartialEq for [u8] { impl PartialOrd for SerializedSignature { fn partial_cmp(&self, other: &SerializedSignature) -> Option { - Some((**self).cmp(&**other)) + Some(self.cmp(other)) } } From 0624d96415337e7c1a60d978bb0e5b783990fb62 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 24 Jun 2025 12:08:12 +0100 Subject: [PATCH 128/857] Use the anonymous lifetime for path Lint error from new nightly "lifetime flowing from input to output with different syntax can be confusing". Add the anonymous lifetime to make it explicit. --- bitcoin/src/blockdata/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 7bcba7a23f..654388b485 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -309,7 +309,7 @@ pub trait TransactionExt: sealed::Sealed { /// This is useful in combination with [`predict_weight`] if you have the transaction already /// constructed with a dummy value in the fee output which you'll adjust after calculating the /// weight. - fn script_pubkey_lens(&self) -> TxOutToScriptPubkeyLengthIter; + fn script_pubkey_lens(&self) -> TxOutToScriptPubkeyLengthIter<'_>; /// Counts the total number of sigops. /// From a5db001fc0be214fd7027997cfac991fa0c1e0c4 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 24 Jun 2025 12:10:10 +0100 Subject: [PATCH 129/857] Update Github CI to rustc nightly-2025-06-20 Automated update failed CI due to new lint errors. Now lint errors have been fixed update the nightly version. --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index e1c42351ed..b54e2edfcd 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-06-06 +nightly-2025-06-20 From 8552534b612dc7d059368e6c630c16640379b949 Mon Sep 17 00:00:00 2001 From: yancy Date: Tue, 24 Jun 2025 11:20:01 -0500 Subject: [PATCH 130/857] Use u32 for struct and member variables in IWP, saturating to u32::MAX To prevent panics during addition if `usize` is `u64`, use `u32` member variables internally. TK use `u32::saturating_add` instead of basic addition. However, to use `u32::saturating_add()`, the variables need to be of type `u32`. Therefore, this commit transforms the internal types to `u32`. In so doing, add a `const` function `saturate_to_u32()` which saturates a usize to `u32`. Also, replace `compact_size::encoded_size()` with a new function `encoded_size()` which returns a `u32`, avoiding needless casts. --- bitcoin/src/blockdata/transaction.rs | 37 ++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 0e64bdd3c2..f9a31b30bf 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -932,8 +932,8 @@ pub const fn predict_weight_from_slices( /// associated constants/methods. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct InputWeightPrediction { - script_size: usize, - witness_size: usize, + script_size: u32, + witness_size: u32, } impl InputWeightPrediction { @@ -996,6 +996,23 @@ impl InputWeightPrediction { /// [`InputWeightPrediction::new`]. pub const P2TR_KEY_NON_DEFAULT_SIGHASH: Self = InputWeightPrediction::from_slice(0, &[65]); + const fn saturate_to_u32(x: usize) -> u32 { + if x > u32::MAX as usize { + u32::MAX + } else { + x as u32 //cast ok, condition prevents larger than u32::MAX. + } + } + + const fn encoded_size(value: usize) -> u32 { + match value { + 0..=0xFC => 1, + 0xFD..=0xFFFF => 3, + 0x10000..=0xFFFFFFFF => 5, + _ => 9, + } + } + /// Input weight prediction corresponding to spending of P2WPKH output using [signature /// grinding]. /// @@ -1065,16 +1082,16 @@ impl InputWeightPrediction { T::Item: Borrow, { let (count, total_size) = witness_element_lengths.into_iter().fold( - (0usize, 0), + (0usize, 0u32), |(count, total_size), elem_len| { let elem_len = *elem_len.borrow(); - let elem_size = elem_len + compact_size::encoded_size(elem_len); + let elem_size = Self::saturate_to_u32(elem_len) + Self::encoded_size(elem_len); (count + 1, total_size + elem_size) }, ); - let witness_size = - if count > 0 { total_size + compact_size::encoded_size(count) } else { 0 }; - let script_size = input_script_len + compact_size::encoded_size(input_script_len); + let witness_size = if count > 0 { total_size + Self::encoded_size(count) } else { 0 }; + let script_size = + Self::saturate_to_u32(input_script_len) + Self::encoded_size(input_script_len); InputWeightPrediction { script_size, witness_size } } @@ -1090,17 +1107,17 @@ impl InputWeightPrediction { // for loops not supported in const fn while i < witness_element_lengths.len() { let elem_len = witness_element_lengths[i]; - let elem_size = elem_len + compact_size::encoded_size_const(elem_len as u64); + let elem_size = Self::saturate_to_u32(elem_len) + Self::encoded_size(elem_len); total_size += elem_size; i += 1; } let witness_size = if !witness_element_lengths.is_empty() { - total_size + compact_size::encoded_size_const(witness_element_lengths.len() as u64) + total_size + Self::encoded_size(witness_element_lengths.len()) } else { 0 }; let script_size = - input_script_len + compact_size::encoded_size_const(input_script_len as u64); + Self::saturate_to_u32(input_script_len) + Self::encoded_size(input_script_len); InputWeightPrediction { script_size, witness_size } } From e4c3d1e7a62a446d930e2a73dc98415999aefdcb Mon Sep 17 00:00:00 2001 From: yancy Date: Tue, 17 Jun 2025 13:18:16 -0500 Subject: [PATCH 131/857] Use saturating add in IWP constructors In order to avoid panics during weight prediction replace addition with `u32::saturating_add()`. --- bitcoin/src/blockdata/transaction.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index f9a31b30bf..690996ece6 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1085,8 +1085,9 @@ impl InputWeightPrediction { (0usize, 0u32), |(count, total_size), elem_len| { let elem_len = *elem_len.borrow(); - let elem_size = Self::saturate_to_u32(elem_len) + Self::encoded_size(elem_len); - (count + 1, total_size + elem_size) + let elem_size = + Self::saturate_to_u32(elem_len).saturating_add(Self::encoded_size(elem_len)); + (count + 1, total_size.saturating_add(elem_size)) }, ); let witness_size = if count > 0 { total_size + Self::encoded_size(count) } else { 0 }; @@ -1103,21 +1104,22 @@ impl InputWeightPrediction { /// `new` and thus is intended to be only used in `const` context. pub const fn from_slice(input_script_len: usize, witness_element_lengths: &[usize]) -> Self { let mut i = 0; - let mut total_size = 0; + let mut total_size: u32 = 0; // for loops not supported in const fn while i < witness_element_lengths.len() { let elem_len = witness_element_lengths[i]; - let elem_size = Self::saturate_to_u32(elem_len) + Self::encoded_size(elem_len); - total_size += elem_size; + let elem_size = + Self::saturate_to_u32(elem_len).saturating_add(Self::encoded_size(elem_len)); + total_size = total_size.saturating_add(elem_size); i += 1; } let witness_size = if !witness_element_lengths.is_empty() { - total_size + Self::encoded_size(witness_element_lengths.len()) + total_size.saturating_add(Self::encoded_size(witness_element_lengths.len())) } else { 0 }; - let script_size = - Self::saturate_to_u32(input_script_len) + Self::encoded_size(input_script_len); + let script_size = Self::saturate_to_u32(input_script_len) + .saturating_add(Self::encoded_size(input_script_len)); InputWeightPrediction { script_size, witness_size } } From 8559a49e03be2b8b3ea4215227ae003e822a663c Mon Sep 17 00:00:00 2001 From: yancy Date: Tue, 27 May 2025 18:58:02 -0500 Subject: [PATCH 132/857] Do not bound Arbitrary parameters passed to InputWeightPrediction Now that InputWeightPrediction can no longer overflow due to extreme values, there is no longer need to bound the Arbitrary parameters passed. --- bitcoin/src/blockdata/transaction.rs | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 690996ece6..2eecfed62b 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1165,22 +1165,6 @@ mod sealed { #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for InputWeightPrediction { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - // limit script size to 4Mwu block size. - let max_block = Weight::MAX_BLOCK.to_wu() as usize; - let input_script_len = u.int_in_range(0..=max_block)?; - let remaining = max_block - input_script_len; - - // create witness data if there is remaining space. - let mut witness_length = u.int_in_range(0..=remaining)?; - let mut witness_element_lengths = Vec::new(); - - // build vec of random witness element lengths. - while witness_length > 0 { - let elem = u.int_in_range(1..=witness_length)?; - witness_element_lengths.push(elem); - witness_length -= elem; - } - match u.int_in_range(0..=7)? { 0 => Ok(InputWeightPrediction::P2WPKH_MAX), 1 => Ok(InputWeightPrediction::NESTED_P2WPKH_MAX), @@ -1188,8 +1172,16 @@ impl<'a> Arbitrary<'a> for InputWeightPrediction { 3 => Ok(InputWeightPrediction::P2PKH_UNCOMPRESSED_MAX), 4 => Ok(InputWeightPrediction::P2TR_KEY_DEFAULT_SIGHASH), 5 => Ok(InputWeightPrediction::P2TR_KEY_NON_DEFAULT_SIGHASH), - 6 => Ok(InputWeightPrediction::new(input_script_len, witness_element_lengths)), - _ => Ok(InputWeightPrediction::from_slice(input_script_len, &witness_element_lengths)), + 6 => { + let input_script_len = usize::arbitrary(u)?; + let witness_element_lengths: Vec = Vec::arbitrary(u)?; + Ok(InputWeightPrediction::new(input_script_len, witness_element_lengths)) + } + _ => { + let input_script_len = usize::arbitrary(u)?; + let witness_element_lengths: Vec = Vec::arbitrary(u)?; + Ok(InputWeightPrediction::from_slice(input_script_len, &witness_element_lengths)) + } } } } From 3355400d6706ce8fee3daa258e9dbbd648a87dca Mon Sep 17 00:00:00 2001 From: yancy Date: Thu, 19 Jun 2025 13:27:40 -0500 Subject: [PATCH 133/857] docs: document IWP function return limit and panic case Document the newly added saturation point for internal arithmetic. --- bitcoin/src/blockdata/transaction.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 2eecfed62b..b5e81bae23 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1126,12 +1126,18 @@ impl InputWeightPrediction { /// Computes the **signature weight** added to a transaction by an input with this weight prediction, /// not counting the prevout (txid, index), sequence, potential witness flag bytes or the witness count varint. + /// + /// This function's internal arithmetic saturates at u32::MAX, so the return value of this + /// function may be inaccurate for extremely large witness predictions. #[deprecated(since = "TBD", note = "use `InputWeightPrediction::witness_weight()` instead")] pub const fn weight(&self) -> Weight { Self::witness_weight(self) } /// Computes the signature, prevout (txid, index), and sequence weights of this weight /// prediction. /// + /// This function's internal arithmetic saturates at u32::MAX, so the return value of this + /// function may be inaccurate for extremely large witness predictions. + /// /// See also [`InputWeightPrediction::witness_weight`] pub const fn total_weight(&self) -> Weight { // `impl const Trait` is currently unavailable: rust/issues/67792 @@ -1142,6 +1148,9 @@ impl InputWeightPrediction { /// Computes the **signature weight** added to a transaction by an input with this weight prediction, /// not counting the prevout (txid, index), sequence, potential witness flag bytes or the witness count varint. + /// + /// This function's internal arithmetic saturates at u32::MAX, so the return value of this + /// function may be inaccurate for extremely large witness predictions. /// /// See also [`InputWeightPrediction::total_weight`] pub const fn witness_weight(&self) -> Weight { From 1f9c48b5d3a48868419ce2f3080d88059c48f767 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 24 Jun 2025 13:01:51 +1000 Subject: [PATCH 134/857] units: Set explicit internals dependency version to v0.4.0 `cargo publish` does not allow publishing a crate without all dependencies having explicit version numbers. We discovered recently that having patching the root manifest was annoying when downstream testing so we removing the version numbers in #4284 in favor of `path`. It turns out we can include both. Props to nyonson for discovering that. ref: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations Use an explicit version number to the `internals` dep in `units`. --- units/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/units/Cargo.toml b/units/Cargo.toml index 1bad34a7c9..078c9a6426 100644 --- a/units/Cargo.toml +++ b/units/Cargo.toml @@ -18,13 +18,13 @@ std = ["alloc", "internals/std"] alloc = ["internals/alloc","serde?/alloc"] [dependencies] -internals = { package = "bitcoin-internals", path = "../internals" } +internals = { package = "bitcoin-internals", path = "../internals", version = "0.4.0" } serde = { version = "1.0.103", default-features = false, optional = true } arbitrary = { version = "1.4", optional = true } [dev-dependencies] -internals = { package = "bitcoin-internals", path = "../internals", features = ["test-serde"] } +internals = { package = "bitcoin-internals", path = "../internals", version = "0.4.0", features = ["test-serde"] } bincode = "1.3.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } serde_test = "1.0" From 806b34aefc554c23cec2d1293113a589718c8cdf Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 27 Feb 2025 10:52:04 +1100 Subject: [PATCH 135/857] units: Bump version to 1.0.0-rc.0 In preparation for doing the first 1.0 RC release set the version number, add a changelog entry, and update the lock files. --- Cargo-minimal.lock | 2 +- Cargo-recent.lock | 2 +- units/CHANGELOG.md | 48 +++++++++++++++++++++++++++++++++++++++++----- units/Cargo.toml | 2 +- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 9667527dd2..63d43f9197 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -137,7 +137,7 @@ dependencies = [ [[package]] name = "bitcoin-units" -version = "0.2.0" +version = "1.0.0-rc.0" dependencies = [ "arbitrary", "bincode", diff --git a/Cargo-recent.lock b/Cargo-recent.lock index ded29f2b8e..fcf5c2cc3c 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -136,7 +136,7 @@ dependencies = [ [[package]] name = "bitcoin-units" -version = "0.2.0" +version = "1.0.0-rc.0" dependencies = [ "arbitrary", "bincode", diff --git a/units/CHANGELOG.md b/units/CHANGELOG.md index c2f6a470f9..bd072693b4 100644 --- a/units/CHANGELOG.md +++ b/units/CHANGELOG.md @@ -1,8 +1,46 @@ -# Unreleased - -- TODO: Make a comment about `Amount::MAX_MONEY` including breaking serde - -- Use MAX_MONEY in serde regression test [#3950](https://github.com/rust-bitcoin/rust-bitcoin/pull/3950) +# 1.0.0 - 2025-02-24 + +BOOM! A long time in the making but here goes, our first 1.0 crate release. + +This changelog is a rolling description of everything that will eventually end up in `v1.0`. + +* Introduce limit to `Amount` + * Prepare to enforce `MAX_MONEY` invariant [#4164](https://github.com/rust-bitcoin/rust-bitcoin/pull/4164) + * Enforce `MAX_MONEY` invariant in amount types [#4157](https://github.com/rust-bitcoin/rust-bitcoin/pull/4157) +* New `NumOpResult` type + * Introduce monadic `NumOpResult` type [#4007](https://github.com/rust-bitcoin/rust-bitcoin/pull/4007) + * Add impls for `NumOpResult` div and mul [#4337](https://github.com/rust-bitcoin/rust-bitcoin/pull/4337) + * Use `NumOpResult` instead of `Option` [#4428](https://github.com/rust-bitcoin/rust-bitcoin/pull/4428) + * Return `NumOpResult` when implementing `Div` [#4312](https://github.com/rust-bitcoin/rust-bitcoin/pull/4312) +* Heavily modify `fee_rate` module: + * Make `FeeRate` use MvB internally [#4534](https://github.com/rust-bitcoin/rust-bitcoin/pull/4534) + * Add `FeeRate` addition and subtraction traits [#3381](https://github.com/rust-bitcoin/rust-bitcoin/pull/3381) + * Remove `Display`/`FromStr` for `FeeRate` [#4512](https://github.com/rust-bitcoin/rust-bitcoin/pull/4512) + * Implement `serde` modules for `FeeRate` [#3666](https://github.com/rust-bitcoin/rust-bitcoin/pull/3666) +* Fix and improve `locktime` modules + * Modify locktime `serde` implementations [#4511](https://github.com/rust-bitcoin/rust-bitcoin/pull/4511) + * Improve lock times - fix off-by-one bug [#4468](https://github.com/rust-bitcoin/rust-bitcoin/pull/4468) + * Do lock time renames [#4462](https://github.com/rust-bitcoin/rust-bitcoin/pull/4462) +* Make block-related types have private inner fields [#4508](https://github.com/rust-bitcoin/rust-bitcoin/pull/4508) +* `Timestamp`/`BlockTime` + * Add `Timestamp` newtype [#4092](https://github.com/rust-bitcoin/rust-bitcoin/pull/4092) + * Rename then new `Timestamp` type to `BlockTime` [#4219](https://github.com/rust-bitcoin/rust-bitcoin/pull/4219) +* Add µBTC as a recognized str form of a `MicroBitcoin` `Denomination` [#3943](https://github.com/rust-bitcoin/rust-bitcoin/pull/3943) +* Remove `InputString` from the public API [#3905](https://github.com/rust-bitcoin/rust-bitcoin/pull/3905) +* Hide the remaining public macros [#3867](https://github.com/rust-bitcoin/rust-bitcoin/pull/3867) +* Change method return type for `to_unsigned()` [#3769](https://github.com/rust-bitcoin/rust-bitcoin/pull/3769) +* Change paramater type used for whole bitcoin [#3744](https://github.com/rust-bitcoin/rust-bitcoin/pull/3744) +* Add `Weight::to_kwu_ceil` [#3740](https://github.com/rust-bitcoin/rust-bitcoin/pull/3740) +* Replace `String` with `InputString` [#3559](https://github.com/rust-bitcoin/rust-bitcoin/pull/3559) + +## Changes relate to error types + +* Close the hex parse errors [#3673](https://github.com/rust-bitcoin/rust-bitcoin/pull/3673) + +## Improved support for `Arbitrary` + +* Implement `Arbitrary` for `units` types [#3777](https://github.com/rust-bitcoin/rust-bitcoin/pull/3777) +* Add `Arbitrary` to `Weight` [#3257](https://github.com/rust-bitcoin/rust-bitcoin/pull/3257) # 0.2.0 - 2024-09-18 diff --git a/units/Cargo.toml b/units/Cargo.toml index 078c9a6426..8d943b44f0 100644 --- a/units/Cargo.toml +++ b/units/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitcoin-units" -version = "0.2.0" +version = "1.0.0-rc.0" authors = ["Andrew Poelstra "] license = "CC0-1.0" repository = "https://github.com/rust-bitcoin/rust-bitcoin/" From 3337b7a030795547077e1920120bf0f82463bf8e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 23 Jun 2025 20:13:55 +0000 Subject: [PATCH 136/857] psbt: introduce IncorrectNonWitnessUtxo error variant Putting this in its own commit so that the fix and the test can live in separate commits which reviewers can swap. --- bitcoin/src/psbt/error.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bitcoin/src/psbt/error.rs b/bitcoin/src/psbt/error.rs index 58338ab691..6095c85ff5 100644 --- a/bitcoin/src/psbt/error.rs +++ b/bitcoin/src/psbt/error.rs @@ -80,6 +80,16 @@ pub enum Error { NegativeFee, /// Integer overflow in fee calculation FeeOverflow, + /// Non-witness UTXO (which is a complete transaction) has [`crate::Txid`] that + /// does not match the transaction input. + IncorrectNonWitnessUtxo { + /// The index of the input in question. + index: usize, + /// The outpoint of the input, as it appears in the unsigned transaction. + input_outpoint: crate::OutPoint, + /// The ['crate::Txid`] of the non-witness UTXO. + non_witness_utxo_txid: crate::Txid, + }, /// Parsing error indicating invalid public keys InvalidPublicKey(crate::crypto::key::FromSliceError), /// Parsing error indicating invalid secp256k1 public keys @@ -154,6 +164,13 @@ impl fmt::Display for Error { write_err!(f, "error parsing bitcoin consensus encoded object"; e), NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"), FeeOverflow => f.write_str("integer overflow in fee calculation"), + IncorrectNonWitnessUtxo { index, input_outpoint, non_witness_utxo_txid } => { + write!( + f, + "non-witness utxo txid is {}, which does not match input {}'s outpoint {}", + non_witness_utxo_txid, index, input_outpoint + ) + } InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e), InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e), InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"), @@ -200,6 +217,7 @@ impl std::error::Error for Error { | CombineInconsistentKeySources(_) | NegativeFee | FeeOverflow + | IncorrectNonWitnessUtxo { .. } | InvalidPublicKey(_) | InvalidSecp256k1PublicKey(_) | InvalidXOnlyPublicKey From 74f22a0a67f95ec6dc993cc550b3122d4527bd42 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 23 Jun 2025 20:13:55 +0000 Subject: [PATCH 137/857] psbt: validate that non_witness_utxo txids match the input txids This requires updating a couple serde test vectors -- we are tightening validation so that some existing serde-serialized PSBTs no longer deserialize. I believe this is the correct thing to do. --- bitcoin/src/psbt/mod.rs | 1 + bitcoin/src/psbt/serialize.rs | 16 ++++++++++++++-- bitcoin/tests/data/serde/psbt_base64.json | 2 +- bitcoin/tests/data/serde/psbt_bincode | Bin 810 -> 810 bytes bitcoin/tests/serde.rs | 1 + 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index e78328feef..e55480b882 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1667,6 +1667,7 @@ mod tests { }, unsigned_tx: { let mut unsigned = tx.clone(); + unsigned.input[0].previous_output.txid = tx.compute_txid(); unsigned.input[0].script_sig = ScriptBuf::new(); unsigned.input[0].witness = Witness::default(); unsigned diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 542c9798fa..468afae2dd 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -103,8 +103,20 @@ impl Psbt { let mut inputs: Vec = Vec::with_capacity(inputs_len); - for _ in 0..inputs_len { - inputs.push(Input::decode(r)?); + for i in 0..inputs_len { + let input = Input::decode(r)?; + if let Some(ref tx) = input.non_witness_utxo { + let input_outpoint = global.unsigned_tx.input[i].previous_output; + let txid = tx.compute_txid(); + if txid != input_outpoint.txid { + return Err(Error::IncorrectNonWitnessUtxo { + index: i, + input_outpoint, + non_witness_utxo_txid: txid, + }); + } + } + inputs.push(input); } inputs diff --git a/bitcoin/tests/data/serde/psbt_base64.json b/bitcoin/tests/data/serde/psbt_base64.json index 6bb318f103..d051551779 100644 --- a/bitcoin/tests/data/serde/psbt_base64.json +++ b/bitcoin/tests/data/serde/psbt_base64.json @@ -1 +1 @@ -"cHNidP8BAFMBAAAAAYmjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAAAD/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAAAAAE8BBIiyHgAAAAAAAAAAAIc9/4HAL1JWI/0f5RZ+rDpVoEnePTFLtC7iJ//tN9UIAzmjYBMwFZfa70H75ZOgLMUT0LVVJ+wt8QUOLo/0nIXCDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAAEAjwEAAAAAAQGJo8ceq00g4Dcbu6TMaY+ilclGOvouOX+FM8y2L5Vn5QEAAAAXFgAUvhjRUqmwEgOdrz2n3k9TNJ7suYX/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUAAAAAAQEgcv74TiwAAAAXqRQzlyW6Ie/WKsdTqbzQZ9bHpqOdBYciAgM5iA3JI5S3NV49BDn6KDwx3nWQgS6gEcQkXAZ0poXog0cwRAIgT2fir7dhQtRPrliiSV0zo0GdqibNDbjQTzRStjKJrA8CIBB2Kp+2fpTMXK2QJvbcmf9/Bw9CeNMPvH0Mhp3TjH/nAQEDBIMAAAABBAFRIgYDOYgNySOUtzVePQQ5+ig8Md51kIEuoBHEJFwGdKaF6IMM3q2+7wAAAIABAAAAAQgGAgIBAwEFFQoYn3yLGjhv/o7tkbODDHp7zR53jAIBAiELoShx/uIQ+4YZKR6uoZRYHL0lMeSyN1nSJfaAaSP2MiICAQIVDBXMSeGRy8Ug2RlEYApct3r2qjKRAgECIQ12pWrO2RXSUT3NhMLDeLLoqlzWMrW3HKLyrFsOOmSb2wIBAhD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFACICAzmIDckjlLc1Xj0EOfooPDHedZCBLqARxCRcBnSmheiDDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAA==" \ No newline at end of file +"cHNidP8BAFMBAAAAATkUkZZWjQ4TAMqaOkez2dl2+5yBsfd38qS6x8fkjesmAQAAAAD/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAAAAAE8BBIiyHgAAAAAAAAAAAIc9/4HAL1JWI/0f5RZ+rDpVoEnePTFLtC7iJ//tN9UIAzmjYBMwFZfa70H75ZOgLMUT0LVVJ+wt8QUOLo/0nIXCDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAAEAjwEAAAAAAQGJo8ceq00g4Dcbu6TMaY+ilclGOvouOX+FM8y2L5Vn5QEAAAAXFgAUvhjRUqmwEgOdrz2n3k9TNJ7suYX/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUAAAAAAQEgcv74TiwAAAAXqRQzlyW6Ie/WKsdTqbzQZ9bHpqOdBYciAgM5iA3JI5S3NV49BDn6KDwx3nWQgS6gEcQkXAZ0poXog0cwRAIgT2fir7dhQtRPrliiSV0zo0GdqibNDbjQTzRStjKJrA8CIBB2Kp+2fpTMXK2QJvbcmf9/Bw9CeNMPvH0Mhp3TjH/nAQEDBIMAAAABBAFRIgYDOYgNySOUtzVePQQ5+ig8Md51kIEuoBHEJFwGdKaF6IMM3q2+7wAAAIABAAAAAQgGAgIBAwEFFQoYn3yLGjhv/o7tkbODDHp7zR53jAIBAiELoShx/uIQ+4YZKR6uoZRYHL0lMeSyN1nSJfaAaSP2MiICAQIVDBXMSeGRy8Ug2RlEYApct3r2qjKRAgECIQ12pWrO2RXSUT3NhMLDeLLoqlzWMrW3HKLyrFsOOmSb2wIBAhD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFACICAzmIDckjlLc1Xj0EOfooPDHedZCBLqARxCRcBnSmheiDDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAA==" \ No newline at end of file diff --git a/bitcoin/tests/data/serde/psbt_bincode b/bitcoin/tests/data/serde/psbt_bincode index 35d580f4b0ddd26395b7974739e0cd48ad82fbe4..0423835c0ee0459e4560ca54f4c3583e246b7664 100644 GIT binary patch delta 43 zcmV+`0M!4g2C4>-6(Bhjk(O4C4if;%nmR|b+1YmcoPn|Tck-mV$H(N2>n5=^^#Y#~ B7196z delta 13 VcmZ3*wu)_n=)@N)8!bOF0RSbZ1%Lnm diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index 3d2b4a28ac..0a4f4bbb12 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -285,6 +285,7 @@ fn serde_regression_psbt() { }, unsigned_tx: { let mut unsigned = tx.clone(); + unsigned.input[0].previous_output.txid = tx.compute_txid(); unsigned.input[0].script_sig = ScriptBuf::new(); unsigned.input[0].witness = Witness::default(); unsigned From 53b93321c87ed57680e0ca49a0691c4deb7edde7 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 23 Jun 2025 20:04:54 +0000 Subject: [PATCH 138/857] psbt: add test vector where non-witness UTXO TXID does not match input txid --- bitcoin/src/psbt/mod.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index e55480b882..4fe91060e1 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -2113,6 +2113,28 @@ mod tests { } } + #[test] + fn invalid_vector_4617() { + let err = hex_psbt("70736274ff01007374ff0103010000000000000000002e2873007374ff0107736205000000000000000000000000000000000006060005feffffff74ff01000a000000000000002cc760008530b38dac0100030500000074ff01070100000000000000000000000000c0316888e006000600050000736274ff00d90001007374ff41030100000000000a0a06002e2873007374ff01070100000000000000000000000000000000ff0000060600050000736274ff01000a0080000000000024c7600005193b1e400700030500000074ff0107010000000000a9c7df3f07000570ed62c76004c3ca95c5f90200010742420a0a000000000000").unwrap_err(); + match err { + Error::IncorrectNonWitnessUtxo { index: 0, input_outpoint, non_witness_utxo_txid } => { + assert_eq!( + input_outpoint, + "00000000000000000000000562730701ff74730073282e000000000000000000:0" + .parse() + .unwrap(), + ); + assert_eq!( + non_witness_utxo_txid, + "9ed45fd3f73b038649bee6e763dbd70868745c48a0d2b0299f42c68f957995f4" + .parse() + .unwrap(), + ); + } + _ => panic!("expected output hash mismatch error, got {}", err), + } + } + #[test] fn serialize_and_deserialize_preimage_psbt() { // create a sha preimage map From b6d8d2a4ab997caf7decc0dc5ec2394710108388 Mon Sep 17 00:00:00 2001 From: Update Stable Rustc Bot Date: Fri, 27 Jun 2025 01:06:59 +0000 Subject: [PATCH 139/857] Automated update to Github CI to rustc stable-1.88.0 --- .github/workflows/stable-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stable-version b/.github/workflows/stable-version index f634271672..59be592144 100644 --- a/.github/workflows/stable-version +++ b/.github/workflows/stable-version @@ -1 +1 @@ -1.87.0 +1.88.0 From 24971a21d7dcd69002b1cf84e71493c6bdb56288 Mon Sep 17 00:00:00 2001 From: Update Nightly Rustc Bot Date: Sat, 28 Jun 2025 01:57:26 +0000 Subject: [PATCH 140/857] Automated update to Github CI to rustc nightly-2025-06-27 --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index b54e2edfcd..e1fde0ed06 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-06-20 +nightly-2025-06-27 From ba29dac6ad6b52752f411b266f11111355ada7b8 Mon Sep 17 00:00:00 2001 From: strmfos <155266597+strmfos@users.noreply.github.com> Date: Sat, 28 Jun 2025 14:32:04 +0200 Subject: [PATCH 141/857] minor correction bridge.rs --- io/src/bridge.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/src/bridge.rs b/io/src/bridge.rs index 816820a2a5..f82a872071 100644 --- a/io/src/bridge.rs +++ b/io/src/bridge.rs @@ -469,7 +469,7 @@ impl_our! { impl Write for std::process::ChildStdin } -// No ide why other &ChildStd* are not implemented +// No idea why other &ChildStd* are not implemented impl_our! { impl Write for &'_ std::process::ChildStdin } From 4e869b7415afb4d86883c7b02c64f8bf1a546039 Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 29 Jun 2025 01:48:11 +0000 Subject: [PATCH 142/857] 2025-06-29 automated rustfmt nightly --- bitcoin/src/blockdata/transaction.rs | 2 +- units/src/locktime/relative.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 87d9daefcf..10343cd28e 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1142,7 +1142,7 @@ impl InputWeightPrediction { /// Computes the **signature weight** added to a transaction by an input with this weight prediction, /// not counting the prevout (txid, index), sequence, potential witness flag bytes or the witness count varint. - /// + /// /// This function's internal arithmetic saturates at u32::MAX, so the return value of this /// function may be inaccurate for extremely large witness predictions. /// diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs index 88719e2bfe..3a9bcd8517 100644 --- a/units/src/locktime/relative.rs +++ b/units/src/locktime/relative.rs @@ -313,7 +313,7 @@ mod tests { let locktime = NumberOf512Seconds::from_512_second_intervals(intervals); assert_eq!(locktime.to_512_second_intervals(), intervals); } - + #[test] fn from_seconds_ceil_success() { let actual = NumberOf512Seconds::from_seconds_ceil(100).unwrap(); From c642bebeb7c452cdb81977f4fb9e36f2b1872be7 Mon Sep 17 00:00:00 2001 From: Afounso Souza Date: Sun, 29 Jun 2025 21:23:29 +0200 Subject: [PATCH 143/857] fix typo in error message --- bitcoin/src/bip32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index b7659e0723..847335b4f5 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -672,7 +672,7 @@ impl From for IndexOutOfRangeError { impl fmt::Display for IndexOutOfRangeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "index {} out of range [0, 2^31 - 1] (do you have an hardened child number, rather than an index?)", self.index) + write!(f, "index {} out of range [0, 2^31 - 1] (do you have a hardened child number, rather than an index?)", self.index) } } From a520a8ab08e66df362db3ec1a9b50b587cf13650 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 30 Jun 2025 08:33:09 +1000 Subject: [PATCH 144/857] units: Test generic Add and Sub We have `Add` and `Sub` implemented for `NumOpResult` but because the impls are generic they are not grouped in the file with the other add/sub impls. This makes it hard to see if they are supported. Add to the `add` and `sub` unit tests to verify support is implemented. --- units/src/amount/tests.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 088497504c..74d8fab971 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -227,6 +227,10 @@ fn add() { assert!(ssat(-127) + ssat(179) == ssat(52).into()); assert!(ssat(127) + ssat(-179) == ssat(-52).into()); assert!(ssat(-127) + ssat(-179) == ssat(-306).into()); + + // Implemented using generic impl. + assert!(res(127) + sat(179) == sat(306).into()); + assert!(sres(127) + ssat(179) == ssat(306).into()); } #[test] @@ -240,6 +244,10 @@ fn sub() { assert!(ssat(-127) - ssat(179) == ssat(-306).into()); assert!(ssat(127) - ssat(-179) == ssat(306).into()); assert!(ssat(-127) - ssat(-179) == ssat(52).into()); + + // Implemented using generic impl. + assert!(res(179) - sat(127) == sat(52).into()); + assert!(sres(179) - ssat(127) == ssat(52).into()); } #[test] From 63b61e94973bb48022ea23c6d083727578e18727 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 1 Jul 2025 13:06:15 -0400 Subject: [PATCH 145/857] Remove delete match arm and match guard mutation exclusion As of the most recent cargo mutants version v25.2.0 delete match arm and replace match guard mutations can now be identified on function name patterns and as a result can be effectively excluded using the existing mutation exclusion patterns. --- .cargo/mutants.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml index 70a1b8fd3e..d63ac77476 100644 --- a/.cargo/mutants.toml +++ b/.cargo/mutants.toml @@ -10,7 +10,6 @@ exclude_re = [ ".*Error", "deserialize", # Skip serde mutation tests "Iterator", # Mutating operations in an iterator can result in an infinite loop - "match arm", "match guard", # New addition in cargo-mutants 25.0.1 deletes match arms and replaces match guards even in excluded functions # ----------------------------------Crate-specific exclusions---------------------------------- # Units From 13c5df083d6761c5780fc998e33ba4d38d45edf6 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 1 Jul 2025 13:07:48 -0400 Subject: [PATCH 146/857] Enhance the weekly mutation workflow markdown This adds a code block to the cargo mutants issue creator for the missed mutations and prints the current version of cargo mutants being used so any new versions can easily be tracked where or why there are new mutations. --- .github/workflows/cron-weekly-cargo-mutants.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cron-weekly-cargo-mutants.yml b/.github/workflows/cron-weekly-cargo-mutants.yml index 74ec346299..3e7b01debf 100644 --- a/.github/workflows/cron-weekly-cargo-mutants.yml +++ b/.github/workflows/cron-weekly-cargo-mutants.yml @@ -22,13 +22,15 @@ jobs: run: | if [ -s mutants.out/missed.txt ]; then echo "New missed mutants found" + MUTANTS_VERSION=$(cargo mutants --version) gh issue create \ --title "New Mutants Found" \ --body "$(cat < Date: Wed, 2 Jul 2025 13:01:21 +0100 Subject: [PATCH 147/857] Add test for impl Display for Script Match arms in `impl fmt::Display for Script` were untested. Add a regression test for the `OP_PUSHDATAx` match arms. --- primitives/src/script/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs index 012b4f4448..5a5e6b60e2 100644 --- a/primitives/src/script/mod.rs +++ b/primitives/src/script/mod.rs @@ -802,6 +802,21 @@ mod tests { assert!(!format!("{:?}", script).is_empty()); } + #[test] + fn script_display_pushdata() { + // OP_PUSHDATA1 + let script = Script::from_bytes(&[0x4c, 0x02, 0xab, 0xcd]); + assert_eq!(format!("{}", script), "OP_PUSHDATA1 abcd"); + + // OP_PUSHDATA2 + let script = Script::from_bytes(&[0x4d, 0x02, 0x00, 0x12, 0x34]); + assert_eq!(format!("{}", script), "OP_PUSHDATA2 1234"); + + // OP_PUSHDATA4 + let script = Script::from_bytes(&[0x4e, 0x02, 0x00, 0x00, 0x00, 0x56, 0x78]); + assert_eq!(format!("{}", script), "OP_PUSHDATA4 5678"); + } + #[test] fn scriptbuf_display() { let script_buf = ScriptBuf::from(vec![0x00, 0xa1, 0xb2]); From 4d31b141a857e4c90a417cc5805105f160846842 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Wed, 2 Jul 2025 13:29:00 +0100 Subject: [PATCH 148/857] Improve is_too_precise test Two of the match arms in `is_too_precise` were untested. Expand the existing test to check all 4 cases. --- units/src/amount/tests.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 088497504c..933ea5aa52 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -52,8 +52,14 @@ fn sanity_check() { #[test] fn check_if_num_is_too_precise() { - assert_eq!(is_too_precise("1234", 3).unwrap(), 3); - assert_eq!(is_too_precise("1234.1234", 3).unwrap(), 3); + // Has decimal, not too precise + assert_eq!(is_too_precise("1234.5678", 4), Some(0)); + // Has decimal, is too precise + assert_eq!(is_too_precise("1234.5678", 3), Some(3)); + // No decimal, not too precise + assert_eq!(is_too_precise("1234", 4), Some(0)); + // No decimal, is too precise + assert_eq!(is_too_precise("1234", 2), Some(3)); } #[test] From f0562504b7f758a439de60fe5fa76ad9ebfaba00 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Wed, 2 Jul 2025 13:34:29 +0100 Subject: [PATCH 149/857] Exclude deprecated fn from mutation testing Mutation testing generates mutants for deprecated functions `MedianTimePast::to_consensus_u32` and `Height::to_consensus_u32`. Add the functions to the mutation testing exclude list. --- .cargo/mutants.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml index 70a1b8fd3e..c2dc71d46e 100644 --- a/.cargo/mutants.toml +++ b/.cargo/mutants.toml @@ -25,6 +25,8 @@ exclude_re = [ "SignedAmount::checked_abs", # Deprecated "NumberOfBlocks::value", # Deprecated "NumberOf512Seconds::to_consensus_u32", # Deprecated + "MedianTimePast::to_consensus_u32", # Deprecated + "Height::to_consensus_u32", # Deprecated # primitives "Sequence::from_512_second_intervals", # Mutant from replacing | with ^, this returns the same value since the XOR is taken against the u16 with an all-zero bitmask From c0345f8b8f617e5cf98bccb7500f2389511b1865 Mon Sep 17 00:00:00 2001 From: Martin Habovstiak Date: Wed, 2 Jul 2025 14:48:00 +0200 Subject: [PATCH 150/857] Use relative import paths rather than absolute When doing large refactorings such as moving entire modules around referring to items defined in a parent module by mentioning `crate` is umbersome since the paths change and make the move confusing. It also obscures the fact that some concepts are related. This changes a few paths to relative so that the refactoring in the future will be easier. --- bitcoin/src/network/params.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bitcoin/src/network/params.rs b/bitcoin/src/network/params.rs index e9e4adab1a..fc745e455c 100644 --- a/bitcoin/src/network/params.rs +++ b/bitcoin/src/network/params.rs @@ -62,11 +62,10 @@ use units::{BlockHeight, BlockHeightInterval}; -use crate::network::Network; +use super::{Network, TestnetVersion}; #[cfg(doc)] use crate::pow::CompactTarget; use crate::pow::Target; -use crate::TestnetVersion; /// Parameters that influence chain consensus. #[non_exhaustive] From f8823f5c6a596238ff5f7fa30610737291fe0e5e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 3 Jul 2025 12:59:03 +1000 Subject: [PATCH 151/857] Remove BuilderExt trait We (I) must have created the `BuilderExt` at some stage when we thought the `Builder` would go in `primitives` - it has not and will not for the next release so we do not need an extension trait. Inline the `push_key` and `push_x_only_key` methods into the main `Builder` impl block. --- bitcoin/examples/taproot-psbt.rs | 2 +- bitcoin/src/address/script_pubkey.rs | 20 -------------------- bitcoin/src/blockdata/script/builder.rs | 15 +++++++++++++++ bitcoin/src/blockdata/script/tests.rs | 4 +--- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index e850a4567b..ce29c42701 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -77,7 +77,7 @@ const UTXO_3: P2trUtxo = P2trUtxo { use std::collections::BTreeMap; -use bitcoin::address::script_pubkey::{BuilderExt as _, ScriptBufExt as _}; +use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv, Xpub}; use bitcoin::consensus::encode; use bitcoin::consensus_validation::TransactionExt as _; diff --git a/bitcoin/src/address/script_pubkey.rs b/bitcoin/src/address/script_pubkey.rs index bc3637de3b..3ea083be20 100644 --- a/bitcoin/src/address/script_pubkey.rs +++ b/bitcoin/src/address/script_pubkey.rs @@ -8,7 +8,6 @@ use secp256k1::{Secp256k1, Verification}; use crate::internal_macros::define_extension_trait; use crate::key::{ PubkeyHash, PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, WPubkeyHash, - XOnlyPublicKey, }; use crate::opcodes::all::*; use crate::script::witness_program::{WitnessProgram, P2A_PROGRAM}; @@ -19,25 +18,6 @@ use crate::script::{ }; use crate::taproot::TapNodeHash; -define_extension_trait! { - /// Extension functionality to add scriptPubkey support to the [`Builder`] type. - pub trait BuilderExt impl for Builder { - /// Adds instructions to push a public key onto the stack. - fn push_key(self, key: PublicKey) -> Builder { - if key.compressed { - self.push_slice(key.inner.serialize()) - } else { - self.push_slice(key.inner.serialize_uncompressed()) - } - } - - /// Adds instructions to push an XOnly public key onto the stack. - fn push_x_only_key(self, x_only_key: XOnlyPublicKey) -> Builder { - self.push_slice(x_only_key.serialize()) - } - } -} - define_extension_trait! { /// Extension functionality to add scriptPubkey support to the [`Script`] type. pub trait ScriptExt impl for Script { diff --git a/bitcoin/src/blockdata/script/builder.rs b/bitcoin/src/blockdata/script/builder.rs index 55d4c325a5..e68ac43a69 100644 --- a/bitcoin/src/blockdata/script/builder.rs +++ b/bitcoin/src/blockdata/script/builder.rs @@ -5,6 +5,7 @@ use core::fmt; use primitives::relative; use super::{opcode_to_verify, write_scriptint, Error, PushBytes, Script, ScriptBuf}; +use crate::key::{PublicKey, XOnlyPublicKey}; use crate::locktime::absolute; use crate::opcodes::all::*; use crate::opcodes::Opcode; @@ -137,6 +138,20 @@ impl Builder { } } + /// Adds instructions to push a public key onto the stack. + pub fn push_key(self, key: PublicKey) -> Builder { + if key.compressed { + self.push_slice(key.inner.serialize()) + } else { + self.push_slice(key.inner.serialize_uncompressed()) + } + } + + /// Adds instructions to push an XOnly public key onto the stack. + pub fn push_x_only_key(self, x_only_key: XOnlyPublicKey) -> Builder { + self.push_slice(x_only_key.serialize()) + } + /// Adds instructions to push an absolute lock time onto the stack. pub fn push_lock_time(self, lock_time: absolute::LockTime) -> Builder { self.push_int_unchecked(lock_time.to_consensus_u32().into()) diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs index 0268d850ef..a4e6c1bc9e 100644 --- a/bitcoin/src/blockdata/script/tests.rs +++ b/bitcoin/src/blockdata/script/tests.rs @@ -3,9 +3,7 @@ use hex_lit::hex; use super::*; -use crate::address::script_pubkey::{ - BuilderExt as _, ScriptBufExt as _, ScriptExt as _, ScriptExtPrivate as _, -}; +use crate::address::script_pubkey::{ScriptBufExt as _, ScriptExt as _, ScriptExtPrivate as _}; use crate::consensus::encode::{deserialize, serialize}; use crate::crypto::key::{PublicKey, XOnlyPublicKey}; use crate::{opcodes, Amount, FeeRate}; From afd36079e559f4222dd6f56b27fc25c0976eb54f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 3 Jul 2025 12:58:13 +1000 Subject: [PATCH 152/857] Inline script_pubkey Script extension traits The separation of extension traits into the `script_pubkey` module does not assist clarity and makes it less ergonomic for users having to import traits from different locations. We can put these methods on the `script::ScriptExt` and fix both issues. --- bitcoin/src/address/script_pubkey.rs | 85 +----------------------- bitcoin/src/blockdata/script/borrowed.rs | 77 ++++++++++++++++++++- bitcoin/src/blockdata/script/tests.rs | 2 +- bitcoin/src/crypto/sighash.rs | 2 +- bitcoin/src/psbt/mod.rs | 1 - 5 files changed, 79 insertions(+), 88 deletions(-) diff --git a/bitcoin/src/address/script_pubkey.rs b/bitcoin/src/address/script_pubkey.rs index 3ea083be20..d70164ec0e 100644 --- a/bitcoin/src/address/script_pubkey.rs +++ b/bitcoin/src/address/script_pubkey.rs @@ -2,7 +2,6 @@ //! Bitcoin scriptPubkey script extensions. -use internals::array::ArrayExt; use secp256k1::{Secp256k1, Verification}; use crate::internal_macros::define_extension_trait; @@ -12,90 +11,9 @@ use crate::key::{ use crate::opcodes::all::*; use crate::script::witness_program::{WitnessProgram, P2A_PROGRAM}; use crate::script::witness_version::WitnessVersion; -use crate::script::{ - self, Builder, PushBytes, RedeemScriptSizeError, Script, ScriptBuf, ScriptExt as _, ScriptHash, - WScriptHash, WitnessScriptSizeError, -}; +use crate::script::{Builder, PushBytes, Script, ScriptBuf, ScriptHash, WScriptHash}; use crate::taproot::TapNodeHash; -define_extension_trait! { - /// Extension functionality to add scriptPubkey support to the [`Script`] type. - pub trait ScriptExt impl for Script { - /// Computes the P2WSH output corresponding to this witnessScript (aka the "witness redeem - /// script"). - fn to_p2wsh(&self) -> Result { - self.wscript_hash().map(ScriptBuf::new_p2wsh) - } - - /// Computes P2TR output with a given internal key and a single script spending path equal to - /// the current script, assuming that the script is a Tapscript. - fn to_p2tr>( - &self, - secp: &Secp256k1, - internal_key: K, - ) -> ScriptBuf { - let internal_key = internal_key.into(); - let leaf_hash = self.tapscript_leaf_hash(); - let merkle_root = TapNodeHash::from(leaf_hash); - ScriptBuf::new_p2tr(secp, internal_key, Some(merkle_root)) - } - - /// Computes the P2SH output corresponding to this redeem script. - fn to_p2sh(&self) -> Result { - self.script_hash().map(ScriptBuf::new_p2sh) - } - - /// Returns the script code used for spending a P2WPKH output if this script is a script pubkey - /// for a P2WPKH output. The `scriptCode` is described in [BIP143]. - /// - /// [BIP143]: - fn p2wpkh_script_code(&self) -> Option { - if self.is_p2wpkh() { - // The `self` script is 0x00, 0x14, - let bytes = <[u8; 20]>::try_from(&self.as_bytes()[2..]).expect("length checked in is_p2wpkh()"); - let wpkh = WPubkeyHash::from_byte_array(bytes); - Some(script::p2wpkh_script_code(wpkh)) - } else { - None - } - } - - /// Checks whether a script pubkey is a P2PK output. - /// - /// You can obtain the public key, if its valid, - /// by calling [`p2pk_public_key()`](Self::p2pk_public_key) - fn is_p2pk(&self) -> bool { self.p2pk_pubkey_bytes().is_some() } - - /// Returns the public key if this script is P2PK with a **valid** public key. - /// - /// This may return `None` even when [`is_p2pk()`](Self::is_p2pk) returns true. - /// This happens when the public key is invalid (e.g. the point not being on the curve). - /// In this situation the script is unspendable. - fn p2pk_public_key(&self) -> Option { - PublicKey::from_slice(self.p2pk_pubkey_bytes()?).ok() - } - } -} - -define_extension_trait! { - pub(crate) trait ScriptExtPrivate impl for Script { - /// Returns the bytes of the (possibly invalid) public key if this script is P2PK. - fn p2pk_pubkey_bytes(&self) -> Option<&[u8]> { - if let Ok(bytes) = <&[u8; 67]>::try_from(self.as_bytes()) { - let (&first, bytes) = bytes.split_first::<66>(); - let (&last, pubkey) = bytes.split_last::<65>(); - (first == OP_PUSHBYTES_65.to_u8() && last == OP_CHECKSIG.to_u8()).then_some(pubkey) - } else if let Ok(bytes) = <&[u8; 35]>::try_from(self.as_bytes()) { - let (&first, bytes) = bytes.split_first::<34>(); - let (&last, pubkey) = bytes.split_last::<33>(); - (first == OP_PUSHBYTES_33.to_u8() && last == OP_CHECKSIG.to_u8()).then_some(pubkey) - } else { - None - } - } - } -} - define_extension_trait! { /// Extension functionality to add scriptPubkey support to the [`ScriptBuf`] type. pub trait ScriptBufExt impl for ScriptBuf { @@ -195,6 +113,7 @@ mod sealed { #[cfg(test)] mod tests { use super::*; + use crate::script::ScriptExt as _; #[test] fn shortest_witness_program() { diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 6164c0a9c4..8c13a47918 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -3,20 +3,24 @@ use core::fmt; use hex::DisplayHex as _; +use internals::array::ArrayExt; // For `split_first`. use internals::ToU64 as _; +use secp256k1::{Secp256k1, Verification}; use super::witness_version::WitnessVersion; use super::{ Builder, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScriptSizeError, ScriptHash, WScriptHash, WitnessScriptSizeError, }; +use crate::address::script_pubkey::ScriptBufExt as _; use crate::consensus::{self, Encodable}; +use crate::key::{PublicKey, UntweakedPublicKey, WPubkeyHash}; use crate::opcodes::all::*; use crate::opcodes::{self, Opcode}; use crate::policy::{DUST_RELAY_TX_FEE, MAX_OP_RETURN_RELAY}; use crate::prelude::{sink, String, ToString}; -use crate::taproot::{LeafVersion, TapLeafHash}; -use crate::{Amount, FeeRate}; +use crate::taproot::{LeafVersion, TapLeafHash, TapNodeHash}; +use crate::{script, Amount, FeeRate, ScriptBuf}; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -50,6 +54,60 @@ crate::internal_macros::define_extension_trait! { TapLeafHash::from_script(self, LeafVersion::TapScript) } + /// Computes the P2WSH output corresponding to this witnessScript (aka the "witness redeem + /// script"). + fn to_p2wsh(&self) -> Result { + self.wscript_hash().map(ScriptBuf::new_p2wsh) + } + + /// Computes P2TR output with a given internal key and a single script spending path equal to + /// the current script, assuming that the script is a Tapscript. + fn to_p2tr>( + &self, + secp: &Secp256k1, + internal_key: K, + ) -> ScriptBuf { + let internal_key = internal_key.into(); + let leaf_hash = self.tapscript_leaf_hash(); + let merkle_root = TapNodeHash::from(leaf_hash); + ScriptBuf::new_p2tr(secp, internal_key, Some(merkle_root)) + } + + /// Computes the P2SH output corresponding to this redeem script. + fn to_p2sh(&self) -> Result { + self.script_hash().map(ScriptBuf::new_p2sh) + } + + /// Returns the script code used for spending a P2WPKH output if this script is a script pubkey + /// for a P2WPKH output. The `scriptCode` is described in [BIP143]. + /// + /// [BIP143]: + fn p2wpkh_script_code(&self) -> Option { + if self.is_p2wpkh() { + // The `self` script is 0x00, 0x14, + let bytes = <[u8; 20]>::try_from(&self.as_bytes()[2..]).expect("length checked in is_p2wpkh()"); + let wpkh = WPubkeyHash::from_byte_array(bytes); + Some(script::p2wpkh_script_code(wpkh)) + } else { + None + } + } + + /// Checks whether a script pubkey is a P2PK output. + /// + /// You can obtain the public key, if its valid, + /// by calling [`p2pk_public_key()`](Self::p2pk_public_key) + fn is_p2pk(&self) -> bool { self.p2pk_pubkey_bytes().is_some() } + + /// Returns the public key if this script is P2PK with a **valid** public key. + /// + /// This may return `None` even when [`is_p2pk()`](Self::is_p2pk) returns true. + /// This happens when the public key is invalid (e.g. the point not being on the curve). + /// In this situation the script is unspendable. + fn p2pk_public_key(&self) -> Option { + PublicKey::from_slice(self.p2pk_pubkey_bytes()?).ok() + } + /// Returns witness version of the script, if any, assuming the script is a `scriptPubkey`. /// /// # Returns @@ -407,6 +465,21 @@ mod sealed { crate::internal_macros::define_extension_trait! { pub(crate) trait ScriptExtPriv impl for Script { + /// Returns the bytes of the (possibly invalid) public key if this script is P2PK. + fn p2pk_pubkey_bytes(&self) -> Option<&[u8]> { + if let Ok(bytes) = <&[u8; 67]>::try_from(self.as_bytes()) { + let (&first, bytes) = bytes.split_first::<66>(); + let (&last, pubkey) = bytes.split_last::<65>(); + (first == OP_PUSHBYTES_65.to_u8() && last == OP_CHECKSIG.to_u8()).then_some(pubkey) + } else if let Ok(bytes) = <&[u8; 35]>::try_from(self.as_bytes()) { + let (&first, bytes) = bytes.split_first::<34>(); + let (&last, pubkey) = bytes.split_last::<33>(); + (first == OP_PUSHBYTES_33.to_u8() && last == OP_CHECKSIG.to_u8()).then_some(pubkey) + } else { + None + } + } + fn minimal_non_dust_internal(&self, dust_relay_fee_rate_per_kvb: u64) -> Option { // This must never be lower than Bitcoin Core's GetDustThreshold() (as of v0.21) as it may // otherwise allow users to create transactions which likely can never be broadcast/confirmed. diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs index a4e6c1bc9e..350fec519c 100644 --- a/bitcoin/src/blockdata/script/tests.rs +++ b/bitcoin/src/blockdata/script/tests.rs @@ -3,7 +3,7 @@ use hex_lit::hex; use super::*; -use crate::address::script_pubkey::{ScriptBufExt as _, ScriptExt as _, ScriptExtPrivate as _}; +use crate::address::script_pubkey::ScriptBufExt as _; use crate::consensus::encode::{deserialize, serialize}; use crate::crypto::key::{PublicKey, XOnlyPublicKey}; use crate::{opcodes, Amount, FeeRate}; diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 7cb92cd7e7..a4618093a3 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -20,9 +20,9 @@ use hashes::{hash_newtype, sha256, sha256d, sha256t, sha256t_tag}; use internals::write_err; use io::Write; -use crate::address::script_pubkey::ScriptExt as _; use crate::consensus::{encode, Encodable}; use crate::prelude::{Borrow, BorrowMut, String, ToOwned}; +use crate::script::ScriptExt as _; use crate::taproot::{LeafVersion, TapLeafHash, TapLeafTag, TAPROOT_ANNEX_PREFIX}; use crate::transaction::TransactionExt as _; use crate::witness::Witness; diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 884389c638..bff7f3273f 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1337,7 +1337,6 @@ mod tests { }; use super::*; - use crate::address::script_pubkey::ScriptExt as _; use crate::bip32::{ChildNumber, DerivationPath}; use crate::locktime::absolute; use crate::network::NetworkKind; From 25e1d8d23d6c767f7fee00cba2bd6d263d8f93e1 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 3 Jul 2025 13:47:05 +1000 Subject: [PATCH 153/857] Inline script_pubkey ScriptBuf extension trait The separation of extension traits into the `script_pubkey` module does not assist clarity and makes it less ergonomic for users having to import traits from different locations. We can put these methods on the `script::ScriptBufExt` and fix both issues. Once this is done we can remove the `script_pubkey` module entirely. --- bitcoin/examples/ecdsa-psbt-simple.rs | 2 +- bitcoin/examples/ecdsa-psbt.rs | 1 - bitcoin/examples/sighash.rs | 3 +- bitcoin/examples/sign-tx-segwit-v0.rs | 2 +- bitcoin/examples/sign-tx-taproot.rs | 2 +- bitcoin/examples/taproot-psbt-simple.rs | 2 +- bitcoin/examples/taproot-psbt.rs | 1 - bitcoin/src/address/mod.rs | 9 +- bitcoin/src/address/script_pubkey.rs | 139 ----------------------- bitcoin/src/blockdata/script/borrowed.rs | 4 +- bitcoin/src/blockdata/script/mod.rs | 16 +++ bitcoin/src/blockdata/script/owned.rs | 77 +++++++++++++ bitcoin/src/blockdata/script/tests.rs | 25 +++- bitcoin/src/psbt/mod.rs | 1 - 14 files changed, 127 insertions(+), 157 deletions(-) delete mode 100644 bitcoin/src/address/script_pubkey.rs diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs index 1798f6edfb..096a5a4f15 100644 --- a/bitcoin/examples/ecdsa-psbt-simple.rs +++ b/bitcoin/examples/ecdsa-psbt-simple.rs @@ -24,11 +24,11 @@ //! The miner's fee will be 10,000 satoshis. use std::collections::BTreeMap; -use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; use bitcoin::key::WPubkeyHash; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; +use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{Secp256k1, Signing}; use bitcoin::witness::WitnessExt as _; use bitcoin::{ diff --git a/bitcoin/examples/ecdsa-psbt.rs b/bitcoin/examples/ecdsa-psbt.rs index f16a9dc12d..9d5520b044 100644 --- a/bitcoin/examples/ecdsa-psbt.rs +++ b/bitcoin/examples/ecdsa-psbt.rs @@ -31,7 +31,6 @@ use std::collections::BTreeMap; use std::fmt; -use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; use bitcoin::consensus::encode; use bitcoin::consensus_validation::TransactionExt as _; diff --git a/bitcoin/examples/sighash.rs b/bitcoin/examples/sighash.rs index bfa82216eb..0374b66e8a 100644 --- a/bitcoin/examples/sighash.rs +++ b/bitcoin/examples/sighash.rs @@ -1,5 +1,4 @@ -use bitcoin::address::script_pubkey::ScriptBufExt as _; -use bitcoin::script::ScriptExt as _; +use bitcoin::script::{ScriptBufExt as _, ScriptExt as _}; use bitcoin::{ consensus, ecdsa, sighash, Amount, CompressedPublicKey, Script, ScriptBuf, Transaction, }; diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs index e9a49385d5..eff851d226 100644 --- a/bitcoin/examples/sign-tx-segwit-v0.rs +++ b/bitcoin/examples/sign-tx-segwit-v0.rs @@ -2,9 +2,9 @@ //! Demonstrate creating a transaction that spends to and from p2wpkh outputs. -use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::key::WPubkeyHash; use bitcoin::locktime::absolute; +use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing}; use bitcoin::sighash::{EcdsaSighashType, SighashCache}; use bitcoin::witness::WitnessExt as _; diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index a68c968b4b..167d9047d1 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -2,9 +2,9 @@ //! Demonstrate creating a transaction that spends to and from p2tr outputs. -use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey}; use bitcoin::locktime::absolute; +use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing, Verification}; use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType}; use bitcoin::witness::WitnessExt as _; diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index 4260610729..4260c066cd 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -22,11 +22,11 @@ //! The miner's fee will be 10,000 satoshis. use std::collections::BTreeMap; -use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; use bitcoin::key::UntweakedPublicKey; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; +use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{Secp256k1, Signing}; use bitcoin::witness::WitnessExt as _; use bitcoin::{ diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index ce29c42701..e03723720c 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -77,7 +77,6 @@ const UTXO_3: P2trUtxo = P2trUtxo { use std::collections::BTreeMap; -use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv, Xpub}; use bitcoin::consensus::encode; use bitcoin::consensus_validation::TransactionExt as _; diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index c2a0b1a75b..17109c440c 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -40,7 +40,6 @@ //! ``` pub mod error; -pub mod script_pubkey; use core::fmt; use core::marker::PhantomData; @@ -52,7 +51,6 @@ use hashes::{hash160, HashEngine}; use internals::array::ArrayExt; use secp256k1::{Secp256k1, Verification}; -use crate::address::script_pubkey::ScriptBufExt as _; use crate::constants::{ PUBKEY_ADDRESS_PREFIX_MAIN, PUBKEY_ADDRESS_PREFIX_TEST, SCRIPT_ADDRESS_PREFIX_MAIN, SCRIPT_ADDRESS_PREFIX_TEST, @@ -66,8 +64,8 @@ use crate::prelude::{String, ToOwned}; use crate::script::witness_program::WitnessProgram; use crate::script::witness_version::WitnessVersion; use crate::script::{ - self, RedeemScriptSizeError, Script, ScriptBuf, ScriptExt as _, ScriptHash, WScriptHash, - WitnessScriptSizeError, + self, RedeemScriptSizeError, Script, ScriptBuf, ScriptBufExt as _, ScriptExt as _, ScriptHash, + WScriptHash, WitnessScriptSizeError, }; use crate::taproot::TapNodeHash; @@ -714,7 +712,7 @@ impl Address { Segwit { ref program, hrp: _ } => { let prog = program.program(); let version = program.version(); - script_pubkey::new_witness_program_unchecked(version, prog) + script::new_witness_program_unchecked(version, prog) } } } @@ -1022,7 +1020,6 @@ mod tests { use super::*; use crate::network::Network::{Bitcoin, Testnet}; use crate::network::{params, TestnetVersion}; - use crate::script::ScriptBufExt as _; fn roundtrips(addr: &Address, network: Network) { assert_eq!( diff --git a/bitcoin/src/address/script_pubkey.rs b/bitcoin/src/address/script_pubkey.rs deleted file mode 100644 index d70164ec0e..0000000000 --- a/bitcoin/src/address/script_pubkey.rs +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Bitcoin scriptPubkey script extensions. - -use secp256k1::{Secp256k1, Verification}; - -use crate::internal_macros::define_extension_trait; -use crate::key::{ - PubkeyHash, PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, WPubkeyHash, -}; -use crate::opcodes::all::*; -use crate::script::witness_program::{WitnessProgram, P2A_PROGRAM}; -use crate::script::witness_version::WitnessVersion; -use crate::script::{Builder, PushBytes, Script, ScriptBuf, ScriptHash, WScriptHash}; -use crate::taproot::TapNodeHash; - -define_extension_trait! { - /// Extension functionality to add scriptPubkey support to the [`ScriptBuf`] type. - pub trait ScriptBufExt impl for ScriptBuf { - /// Generates P2PK-type of scriptPubkey. - fn new_p2pk(pubkey: PublicKey) -> Self { - Builder::new().push_key(pubkey).push_opcode(OP_CHECKSIG).into_script() - } - - /// Generates P2PKH-type of scriptPubkey. - fn new_p2pkh(pubkey_hash: PubkeyHash) -> Self { - Builder::new() - .push_opcode(OP_DUP) - .push_opcode(OP_HASH160) - .push_slice(pubkey_hash) - .push_opcode(OP_EQUALVERIFY) - .push_opcode(OP_CHECKSIG) - .into_script() - } - - /// Generates P2SH-type of scriptPubkey with a given hash of the redeem script. - fn new_p2sh(script_hash: ScriptHash) -> Self { - Builder::new() - .push_opcode(OP_HASH160) - .push_slice(script_hash) - .push_opcode(OP_EQUAL) - .into_script() - } - - /// Generates P2WPKH-type of scriptPubkey. - fn new_p2wpkh(pubkey_hash: WPubkeyHash) -> Self { - // pubkey hash is 20 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv0) - new_witness_program_unchecked(WitnessVersion::V0, pubkey_hash) - } - - /// Generates P2WSH-type of scriptPubkey with a given hash of the redeem script. - fn new_p2wsh(script_hash: WScriptHash) -> Self { - // script hash is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv0) - new_witness_program_unchecked(WitnessVersion::V0, script_hash) - } - - /// Generates P2TR for script spending path using an internal public key and some optional - /// script tree Merkle root. - fn new_p2tr>( - secp: &Secp256k1, - internal_key: K, - merkle_root: Option, - ) -> Self { - let internal_key = internal_key.into(); - let (output_key, _) = internal_key.tap_tweak(secp, merkle_root); - // output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1) - new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) - } - - /// Generates P2TR for key spending path for a known [`TweakedPublicKey`]. - fn new_p2tr_tweaked(output_key: TweakedPublicKey) -> Self { - // output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1) - new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) - } - - /// Generates pay to anchor output. - fn new_p2a() -> Self { - new_witness_program_unchecked(WitnessVersion::V1, P2A_PROGRAM) - } - - /// Generates P2WSH-type of scriptPubkey with a given [`WitnessProgram`]. - fn new_witness_program(witness_program: &WitnessProgram) -> Self { - Builder::new() - .push_opcode(witness_program.version().into()) - .push_slice(witness_program.program()) - .into_script() - } - } -} - -/// Generates P2WSH-type of scriptPubkey with a given [`WitnessVersion`] and the program bytes. -/// Does not do any checks on version or program length. -/// -/// Convenience method used by `new_p2a`, `new_p2wpkh`, `new_p2wsh`, `new_p2tr`, and `new_p2tr_tweaked`. -pub(super) fn new_witness_program_unchecked>( - version: WitnessVersion, - program: T, -) -> ScriptBuf { - let program = program.as_ref(); - debug_assert!(program.len() >= 2 && program.len() <= 40); - // In SegWit v0, the program must be either 20 bytes (P2WPKH) or 32 bytes (P2WSH) long. - debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32); - Builder::new().push_opcode(version.into()).push_slice(program).into_script() -} - -mod sealed { - pub trait Sealed {} - impl Sealed for super::Script {} - impl Sealed for super::ScriptBuf {} - impl Sealed for super::Builder {} -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::script::ScriptExt as _; - - #[test] - fn shortest_witness_program() { - let bytes = [0x00; 2]; // Arbitrary bytes, witprog must be between 2 and 40. - let version = WitnessVersion::V15; // Arbitrary version number, intentionally not 0 or 1. - - let p = WitnessProgram::new(version, &bytes).expect("failed to create witness program"); - let script = ScriptBuf::new_witness_program(&p); - - assert_eq!(script.witness_version(), Some(version)); - } - - #[test] - fn longest_witness_program() { - let bytes = [0x00; 40]; // Arbitrary bytes, witprog must be between 2 and 40. - let version = WitnessVersion::V16; // Arbitrary version number, intentionally not 0 or 1. - - let p = WitnessProgram::new(version, &bytes).expect("failed to create witness program"); - let script = ScriptBuf::new_witness_program(&p); - - assert_eq!(script.witness_version(), Some(version)); - } -} diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 8c13a47918..1d3cf2ccb9 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -12,15 +12,15 @@ use super::{ Builder, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScriptSizeError, ScriptHash, WScriptHash, WitnessScriptSizeError, }; -use crate::address::script_pubkey::ScriptBufExt as _; use crate::consensus::{self, Encodable}; use crate::key::{PublicKey, UntweakedPublicKey, WPubkeyHash}; use crate::opcodes::all::*; use crate::opcodes::{self, Opcode}; use crate::policy::{DUST_RELAY_TX_FEE, MAX_OP_RETURN_RELAY}; use crate::prelude::{sink, String, ToString}; +use crate::script::{self, ScriptBufExt as _}; use crate::taproot::{LeafVersion, TapLeafHash, TapNodeHash}; -use crate::{script, Amount, FeeRate, ScriptBuf}; +use crate::{Amount, FeeRate, ScriptBuf}; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs index dccfe67272..226e9b9aed 100644 --- a/bitcoin/src/blockdata/script/mod.rs +++ b/bitcoin/src/blockdata/script/mod.rs @@ -62,6 +62,7 @@ use core::fmt; use io::{BufRead, Write}; +use self::witness_version::WitnessVersion; use crate::consensus::{encode, Decodable, Encodable}; use crate::internal_macros::impl_asref_push_bytes; use crate::key::WPubkeyHash; @@ -192,6 +193,21 @@ fn opcode_to_verify(opcode: Option) -> Option { }) } +/// Generates P2WSH-type of scriptPubkey with a given [`WitnessVersion`] and the program bytes. +/// Does not do any checks on version or program length. +/// +/// Convenience method used by `new_p2a`, `new_p2wpkh`, `new_p2wsh`, `new_p2tr`, and `new_p2tr_tweaked`. +pub(crate) fn new_witness_program_unchecked>( + version: WitnessVersion, + program: T, +) -> ScriptBuf { + let program = program.as_ref(); + debug_assert!(program.len() >= 2 && program.len() <= 40); + // In SegWit v0, the program must be either 20 bytes (P2WPKH) or 32 bytes (P2WSH) long. + debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32); + Builder::new().push_opcode(version.into()).push_slice(program).into_script() +} + impl Encodable for Script { #[inline] fn consensus_encode(&self, w: &mut W) -> Result { diff --git a/bitcoin/src/blockdata/script/owned.rs b/bitcoin/src/blockdata/script/owned.rs index da3db6e117..1e313da32b 100644 --- a/bitcoin/src/blockdata/script/owned.rs +++ b/bitcoin/src/blockdata/script/owned.rs @@ -5,12 +5,20 @@ use core::ops::Deref; use hex::FromHex as _; use internals::ToU64 as _; +use secp256k1::{Secp256k1, Verification}; use super::{opcode_to_verify, Builder, Instruction, PushBytes, ScriptExtPriv as _}; use crate::consensus; +use crate::key::{ + PubkeyHash, PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, WPubkeyHash, +}; use crate::opcodes::all::*; use crate::opcodes::{self, Opcode}; use crate::prelude::Vec; +use crate::script::witness_program::{WitnessProgram, P2A_PROGRAM}; +use crate::script::witness_version::WitnessVersion; +use crate::script::{self, ScriptHash, WScriptHash}; +use crate::taproot::TapNodeHash; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -27,6 +35,75 @@ crate::internal_macros::define_extension_trait! { Builder::new().push_opcode(OP_RETURN).push_slice(data).into_script() } + /// Generates P2PK-type of scriptPubkey. + fn new_p2pk(pubkey: PublicKey) -> Self { + Builder::new().push_key(pubkey).push_opcode(OP_CHECKSIG).into_script() + } + + /// Generates P2PKH-type of scriptPubkey. + fn new_p2pkh(pubkey_hash: PubkeyHash) -> Self { + Builder::new() + .push_opcode(OP_DUP) + .push_opcode(OP_HASH160) + .push_slice(pubkey_hash) + .push_opcode(OP_EQUALVERIFY) + .push_opcode(OP_CHECKSIG) + .into_script() + } + + /// Generates P2SH-type of scriptPubkey with a given hash of the redeem script. + fn new_p2sh(script_hash: ScriptHash) -> Self { + Builder::new() + .push_opcode(OP_HASH160) + .push_slice(script_hash) + .push_opcode(OP_EQUAL) + .into_script() + } + + /// Generates P2WPKH-type of scriptPubkey. + fn new_p2wpkh(pubkey_hash: WPubkeyHash) -> Self { + // pubkey hash is 20 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv0) + script::new_witness_program_unchecked(WitnessVersion::V0, pubkey_hash) + } + + /// Generates P2WSH-type of scriptPubkey with a given hash of the redeem script. + fn new_p2wsh(script_hash: WScriptHash) -> Self { + // script hash is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv0) + script::new_witness_program_unchecked(WitnessVersion::V0, script_hash) + } + + /// Generates P2TR for script spending path using an internal public key and some optional + /// script tree Merkle root. + fn new_p2tr>( + secp: &Secp256k1, + internal_key: K, + merkle_root: Option, + ) -> Self { + let internal_key = internal_key.into(); + let (output_key, _) = internal_key.tap_tweak(secp, merkle_root); + // output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1) + script::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) + } + + /// Generates P2TR for key spending path for a known [`TweakedPublicKey`]. + fn new_p2tr_tweaked(output_key: TweakedPublicKey) -> Self { + // output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1) + script::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) + } + + /// Generates pay to anchor output. + fn new_p2a() -> Self { + script::new_witness_program_unchecked(WitnessVersion::V1, P2A_PROGRAM) + } + + /// Generates P2WSH-type of scriptPubkey with a given [`WitnessProgram`]. + fn new_witness_program(witness_program: &WitnessProgram) -> Self { + Builder::new() + .push_opcode(witness_program.version().into()) + .push_slice(witness_program.program()) + .into_script() + } + /// Constructs a new [`ScriptBuf`] from a hex string. /// /// The input string is expected to be consensus encoded i.e., includes the length prefix. diff --git a/bitcoin/src/blockdata/script/tests.rs b/bitcoin/src/blockdata/script/tests.rs index 350fec519c..436f323b08 100644 --- a/bitcoin/src/blockdata/script/tests.rs +++ b/bitcoin/src/blockdata/script/tests.rs @@ -3,9 +3,10 @@ use hex_lit::hex; use super::*; -use crate::address::script_pubkey::ScriptBufExt as _; use crate::consensus::encode::{deserialize, serialize}; use crate::crypto::key::{PublicKey, XOnlyPublicKey}; +use crate::script::witness_program::WitnessProgram; +use crate::script::witness_version::WitnessVersion; use crate::{opcodes, Amount, FeeRate}; #[test] @@ -983,3 +984,25 @@ fn script_push_int_overflow() { // Only errors if `data == i32::MIN` (CScriptNum cannot have value -2^31). assert_eq!(Builder::new().push_int(i32::MIN), Err(Error::NumericOverflow)); } + +#[test] +fn shortest_witness_program() { + let bytes = [0x00; 2]; // Arbitrary bytes, witprog must be between 2 and 40. + let version = WitnessVersion::V15; // Arbitrary version number, intentionally not 0 or 1. + + let p = WitnessProgram::new(version, &bytes).expect("failed to create witness program"); + let script = ScriptBuf::new_witness_program(&p); + + assert_eq!(script.witness_version(), Some(version)); +} + +#[test] +fn longest_witness_program() { + let bytes = [0x00; 40]; // Arbitrary bytes, witprog must be between 2 and 40. + let version = WitnessVersion::V16; // Arbitrary version number, intentionally not 0 or 1. + + let p = WitnessProgram::new(version, &bytes).expect("failed to create witness program"); + let script = ScriptBuf::new_witness_program(&p); + + assert_eq!(script.witness_version(), Some(version)); +} diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index bff7f3273f..f642317018 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1328,7 +1328,6 @@ mod tests { use hex_lit::hex; #[cfg(feature = "rand-std")] use { - crate::address::script_pubkey::ScriptBufExt as _, crate::bip32::Fingerprint, crate::locktime, crate::witness_version::WitnessVersion, From 53083d3fe25b7a7f385b9a582f4bf561f3776d07 Mon Sep 17 00:00:00 2001 From: Update Nightly Rustc Bot Date: Sat, 5 Jul 2025 01:57:04 +0000 Subject: [PATCH 154/857] Automated update to Github CI to rustc nightly-2025-07-04 --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index e1fde0ed06..025bab15be 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-06-27 +nightly-2025-07-04 From 6571307317bc936f29e5a218026446374eb5a01c Mon Sep 17 00:00:00 2001 From: jrakibi Date: Tue, 24 Jun 2025 16:57:56 +0800 Subject: [PATCH 155/857] transaction: Add Coinbase newtype to distinguish coinbase transactions Coinbase transactions have unique consensus rules and exceptions that distinguish them from regular txs. We represent them using a dedicated Coinbase(Transaction) new type We use the transparent_newtype macro from internals for safe reference conversion (&Transaction -> &Coinbase) without manual unsafe code also it automatically adds #[repr(transparent)] which guarantees that Coinbase has the exact same memory layout as Transaction --- bitcoin/src/blockdata/transaction.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 10343cd28e..006809449f 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1154,6 +1154,21 @@ impl InputWeightPrediction { } } +internals::transparent_newtype! { + /// A wrapper type for the coinbase transaction of a block. + /// + /// This type exists to distinguish coinbase transactions from regular ones at the type level. + #[derive(Clone, PartialEq, Eq, Debug, Hash)] + pub struct Coinbase(Transaction); + + impl Coinbase { + /// Creates a reference to `Coinbase` from a reference to the inner `Transaction`. + /// + /// This method does not validate that the transaction is actually a coinbase transaction. + /// The caller must ensure that the transaction is indeed a valid coinbase transaction + pub fn assume_coinbase_ref(inner: &_) -> &Self; + } +} mod sealed { pub trait Sealed {} impl Sealed for super::Transaction {} From 1e69e63367b57eaa12c07752760d6a7c486bc62b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 26 Jun 2025 08:26:31 +1000 Subject: [PATCH 156/857] Remove non_exhausive from Network Issue #2225 is long and has many valid opposing opinions. The main argument for having non_exhaustive is that it helps future proof the ecosystem at the cost of pain now. The main argument against having non_exhaustive is why have pain now when adding a network is so rare that having pain then is ok. At the end of the thread Andrew posts: > I continue to think we should have an exhaustive enum, with a bunch of > documentation about how to use it properly. I am warming up to the > "don't have an enum, just have rules for defining your own" but I think > this would be needless work for people who just want to grab an > off-the-shelf set of networks or people who want to make their own enum > but want to see an example of how to do it first. In order to make some forward progress lets remove the `non_exhaustive` now and backport this change to 0.32, 0.31, an 0.30. Later we can add, and release in 0.33, whatever forward protection / libapocalyse protection we want to add. This removes the pain now and gives us a path to prevent future pain - that should keep all parties happy. --- bitcoin/src/network/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bitcoin/src/network/mod.rs b/bitcoin/src/network/mod.rs index d3c6dd97c6..6751117d86 100644 --- a/bitcoin/src/network/mod.rs +++ b/bitcoin/src/network/mod.rs @@ -59,9 +59,18 @@ pub enum TestnetVersion { V4, } + /// The cryptocurrency network to act on. +/// +/// This is an exhaustive enum, meaning that we cannot add any future networks without defining a +/// new, incompatible version of this type. If you are using this type directly and wish to support the +/// new network, this will be a breaking change to your APIs and likely require changes in your code. +/// +/// If you are concerned about forward compatibility, consider using `T: Into` instead of this +/// this type as a parameter to functions in your public API, or directly using the `Params` type. +// For extensive discussion on the usage of `non_exhaustive` please see: +// https://github.com/rust-bitcoin/rust-bitcoin/issues/2225 #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)] -#[non_exhaustive] pub enum Network { /// Mainnet Bitcoin. Bitcoin, From bcf0c3d92bd890b8b40f96cb010f2366805d77da Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 28 Jun 2025 10:37:42 +1000 Subject: [PATCH 157/857] bitcoin: Add a test for matching on network Add a test module showing how external users are able to match on `Network` and `Network::Testnet(TestnetVersion)`. This topic is contentious so it helps to show exactly what is possible and what is not. --- bitcoin/tests/network.rs | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 bitcoin/tests/network.rs diff --git a/bitcoin/tests/network.rs b/bitcoin/tests/network.rs new file mode 100644 index 0000000000..025912d08f --- /dev/null +++ b/bitcoin/tests/network.rs @@ -0,0 +1,74 @@ +//! Tests what a user can do when pattern matching on `Network` and associated types. + +use bitcoin::network::{Network, NetworkKind, TestnetVersion}; + +#[test] +fn can_match_exhaustively_on_network() { + // Returns true if `n` is mainnet. + fn is_mainnet(n: Network) -> bool { + matches!(n, Network::Bitcoin) + } + + assert!(is_mainnet(Network::Bitcoin)); +} + +#[test] +fn can_match_exhaustively_on_testnet() { + // Returns true if `n` is any testnet. + fn is_testnet(n: Network) -> bool { + matches!(n, Network::Testnet(_)) + } + + assert!(is_testnet(Network::Testnet(TestnetVersion::V3))); +} + +#[test] +fn can_use_network_kind() { + // Returns true if `n` is any mainnet. + fn is_mainnet(n: Network) -> bool { + NetworkKind::from(n).is_mainnet() + } + + // Returns true if `n` is a any testnet. + fn is_testnet(n: Network) -> bool { + !NetworkKind::from(n).is_mainnet() + } + + assert!(is_mainnet(Network::Bitcoin)); + assert!(!is_testnet(Network::Bitcoin)); + + assert!(is_testnet(Network::Testnet(TestnetVersion::V3))); + assert!(!is_mainnet(Network::Testnet(TestnetVersion::V3))); + +} + +#[test] +fn can_not_match_exaustively_on_testnet_version() { + // Returns true if `n` is testnet version 3. + fn is_testnet_v3(n: Network) -> bool { + match n { + Network::Testnet(TestnetVersion::V3) => true, + Network::Testnet(TestnetVersion::V4) => false, + // Catchall because of `non_exhaustive` attribute. + Network::Testnet(_) => false, + _ => false, + } + } + + assert!(is_testnet_v3(Network::Testnet(TestnetVersion::V3))); +} + +#[test] +fn can_match_on_testnet_version_3_only() { + // Returns true if `n` is testnet version 3. + fn is_testnet_v3(n: Network) -> bool { + match n { + Network::Testnet(TestnetVersion::V3) => true, + // Catchall because its logically correct to do so. + Network::Testnet(_) => false, + _ => false, + } + } + + assert!(is_testnet_v3(Network::Testnet(TestnetVersion::V3))); +} From 496d7df77ac45e23d11218e05084711356e01543 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 11:14:36 +1000 Subject: [PATCH 158/857] bitcoin: Remove re-export of Denomination `units::Denomination` does not exist, it is only at `units::amount::Denomination`. Our policy is to make the following three equivalent `bitcoin::Foo`, `primitives::Foo`, and `units::Foo` therefor we should not re-export `Denomination` at the crate root of `bitcoin`. --- bitcoin/src/lib.rs | 2 +- bitcoin/tests/bip_174.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index d305219262..3b09c32c66 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -131,7 +131,7 @@ pub use primitives::{ }; #[doc(inline)] pub use units::{ - amount::{Amount, Denomination, SignedAmount}, + amount::{Amount, SignedAmount}, block::{BlockHeight, BlockHeightInterval, BlockMtp}, fee_rate::FeeRate, time::{self, BlockTime}, diff --git a/bitcoin/tests/bip_174.rs b/bitcoin/tests/bip_174.rs index 10fb81acf9..15ab7376dd 100644 --- a/bitcoin/tests/bip_174.rs +++ b/bitcoin/tests/bip_174.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; +use bitcoin::amount::{Amount, Denomination}; use bitcoin::bip32::{Fingerprint, IntoDerivationPath, KeySource, Xpriv, Xpub}; use bitcoin::consensus::encode::{deserialize, serialize_hex}; use bitcoin::hex::FromHex; @@ -11,7 +12,7 @@ use bitcoin::psbt::{Psbt, PsbtSighashType}; use bitcoin::script::{PushBytes, ScriptBufExt as _}; use bitcoin::secp256k1::Secp256k1; use bitcoin::{ - absolute, script, transaction, Amount, Denomination, NetworkKind, OutPoint, PrivateKey, + absolute, script, transaction, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Witness, }; From a6f63cf61d921e6c59f0697f9b84afd744ddbf37 Mon Sep 17 00:00:00 2001 From: Erick Cestari Date: Mon, 30 Jun 2025 10:26:30 -0300 Subject: [PATCH 159/857] fix: validate ASCII and preserve embedded nulls in CommandString parsing Previously, CommandString decoding would silently normalize invalid commands containing embedded null bytes. For example, "mem\0pool" would be incorrectly decoded as "mempool", bypassing consensus validation. Found through differential fuzzing between btcd and rust-bitcoin, where rust-bitcoin was accepting messages with embedded null bytes in Command fields while btcd (and Bitcoin Core) correctly reject them. --- p2p/src/message.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/p2p/src/message.rs b/p2p/src/message.rs index 2d4c60f61e..eca3abadbf 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -5,7 +5,7 @@ //! This module defines the `NetworkMessage` and `RawNetworkMessage` types that //! are used for (de)serializing Bitcoin objects for transmission on the network. -use core::{fmt, iter}; +use core::fmt; use std::borrow::{Cow, ToOwned}; use std::boxed::Box; @@ -114,14 +114,15 @@ impl Decodable for CommandString { #[inline] fn consensus_decode(r: &mut R) -> Result { let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?; - let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| { - if u > 0 { - Some(u as char) - } else { - None - } - })); - Ok(CommandString(rv)) + + // Find the last non-null byte and trim null padding from the end + let trimmed = &rawbytes[..rawbytes.iter().rposition(|&b| b != 0).map_or(0, |i| i + 1)]; + + if !trimmed.is_ascii() { + return Err(crate::consensus::parse_failed_error("Command string must be ASCII")); + } + + Ok(CommandString(Cow::Owned(unsafe { String::from_utf8_unchecked(trimmed.to_vec()) }))) } } @@ -892,9 +893,18 @@ mod test { assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned()); assert_eq!(cs.unwrap(), CommandString::try_from_static("Andrew").unwrap()); - let short_cs: Result = - deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]); - assert!(short_cs.is_err()); + // Test that embedded null bytes are preserved while trailing nulls are trimmed + let cs: Result = + deserialize(&[0, 0x41u8, 0x6e, 0x64, 0, 0x72, 0x65, 0x77, 0, 0, 0, 0]); + assert!(cs.is_ok()); + assert_eq!(cs.as_ref().unwrap().to_string(), "\0And\0rew".to_owned()); + assert_eq!(cs.unwrap(), CommandString::try_from_static("\0And\0rew").unwrap()); + + // Invalid CommandString, must be ASCII + assert!(deserialize::(&[0, 0x41u8, 0x6e, 0xa4, 0, 0x72, 0x65, 0x77, 0, 0, 0, 0]).is_err()); + + // Invalid CommandString, must be 12 bytes + assert!(deserialize::(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]).is_err()); } #[test] From 1ef0e32e8fa6a9052d857a814426852cb3d194ea Mon Sep 17 00:00:00 2001 From: Kendra Karol Sevilla Date: Tue, 8 Jul 2025 17:53:42 +0200 Subject: [PATCH 160/857] fix wrong article --- hashes/src/siphash24/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashes/src/siphash24/mod.rs b/hashes/src/siphash24/mod.rs index 61f3dcf054..c53536291e 100644 --- a/hashes/src/siphash24/mod.rs +++ b/hashes/src/siphash24/mod.rs @@ -218,7 +218,7 @@ impl Hash { pub fn from_u64(hash: u64) -> Hash { Hash(hash.to_le_bytes()) } } -/// Load an u64 using up to 7 bytes of a byte slice. +/// Load a u64 using up to 7 bytes of a byte slice. /// /// Unsafe because: unchecked indexing at `start..start+len`. #[inline] From 7a6f363f089ed58c5c7470cca003bf6264328559 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 8 Jul 2025 14:02:14 +1000 Subject: [PATCH 161/857] Remove checked_sum impl for Weight The `Weight` type does not use `NumOpResult` with addition, `Add` has `Output = Weight` and uses wrapping addition. This is as expected and as desired. We do provide `Weight::checked_add` that returns an `Option`, also as expected and as desired. Further context: `Amount` was deemed 'special' such that wrapping is considered to big a risk to have silent wrapping so we added the `NumOpResult` type. This argument does not apply to `Weight`. We would like to remove the `CheckedSum` trait because summing of `Amounts` can now be done with a combination of`Sum` and the `NumOpResult` type but `Weight` currently implements `CheckedSum`. For the reasons outline in regards to wrapping a `Weight` type, providing `CheckedSum` does not add much value - remove it. Done as preparation for removing the `CheckedSum` trait all together. --- units/src/weight.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/units/src/weight.rs b/units/src/weight.rs index b0b93ce5ad..800e4dcf99 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -10,7 +10,7 @@ use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::{Amount, CheckedSum, FeeRate, NumOpResult}; +use crate::{Amount, FeeRate, NumOpResult}; /// The factor that non-witness serialization data is multiplied by during weight calculation. pub const WITNESS_SCALE_FACTOR: usize = 4; @@ -251,13 +251,6 @@ impl ops::RemAssign for Weight { fn rem_assign(&mut self, rhs: u64) { *self = Weight::from_wu(self.to_wu() % rhs); } } -impl CheckedSum for T -where - T: Iterator, -{ - fn checked_sum(mut self) -> Option { self.try_fold(Weight::ZERO, Weight::checked_add) } -} - impl core::iter::Sum for Weight { fn sum(iter: I) -> Self where @@ -541,16 +534,4 @@ mod tests { weight %= 3; assert_eq!(weight, Weight::from_wu(1)); } - - #[test] - #[cfg(feature = "alloc")] - fn checked_sum_weights() { - assert_eq!([].into_iter().checked_sum(), Some(Weight::ZERO)); - - let sum = alloc::vec![0, 1, 2].iter().map(|&w| Weight::from_wu(w)).checked_sum().unwrap(); - assert_eq!(sum, Weight::from_wu(3)); - - let sum = alloc::vec![1, u64::MAX].iter().map(|&w| Weight::from_wu(w)).checked_sum(); - assert!(sum.is_none()); - } } From bdf9e00219c19d8bd6c5f27d5b26c91f613fb05a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 8 Jul 2025 13:33:06 +1000 Subject: [PATCH 162/857] Remove CheckedSum trait The `CheckedSum` trait was introduced before we added the `NumOpResult` type. Now that we have 'checked' math operations using that type we do not need to provide the `checked_sum` capability. Remove the `CheckedSum` trait entirely. --- bitcoin/src/lib.rs | 1 - units/src/amount/mod.rs | 17 -------- units/src/amount/tests.rs | 83 +++++++++++++++------------------------ units/src/lib.rs | 18 --------- units/tests/api.rs | 6 +-- 5 files changed, 33 insertions(+), 92 deletions(-) diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index d305219262..6fd45f020e 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -203,7 +203,6 @@ pub mod amount { #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] - pub use units::CheckedSum; #[cfg(feature = "serde")] pub use units::amount::serde; pub use units::amount::{ diff --git a/units/src/amount/mod.rs b/units/src/amount/mod.rs index 19b4a9832f..cfb80068aa 100644 --- a/units/src/amount/mod.rs +++ b/units/src/amount/mod.rs @@ -26,7 +26,6 @@ use core::str::FromStr; use arbitrary::{Arbitrary, Unstructured}; use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner}; -use crate::CheckedSum; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -594,22 +593,6 @@ enum DisplayStyle { DynamicDenomination, } -impl CheckedSum for T -where - T: Iterator, -{ - fn checked_sum(mut self) -> Option { self.try_fold(Amount::ZERO, Amount::checked_add) } -} - -impl CheckedSum for T -where - T: Iterator, -{ - fn checked_sum(mut self) -> Option { - self.try_fold(SignedAmount::ZERO, SignedAmount::checked_add) - } -} - #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Denomination { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index e8ba9aebb2..1e55219e58 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -841,68 +841,47 @@ fn to_string_with_denomination_from_str_roundtrip() { #[test] fn sum_amounts() { - assert_eq!([].iter().sum::>(), Amount::ZERO.into()); - assert_eq!([].iter().sum::>(), SignedAmount::ZERO.into()); - - let results = - [NumOpResult::Valid(sat(42)), NumOpResult::Valid(sat(1337)), NumOpResult::Valid(sat(21))]; - assert_eq!(results.iter().sum::>(), NumOpResult::Valid(sat(1400))); - - let signed_results = [ - NumOpResult::Valid(ssat(42)), - NumOpResult::Valid(ssat(1337)), - NumOpResult::Valid(ssat(21)), - ]; - assert_eq!( - signed_results.iter().sum::>(), - NumOpResult::Valid(ssat(1400)) - ); - - let amounts = [sat(42), sat(1337), sat(21)]; - assert_eq!( - amounts.iter().map(|a| NumOpResult::Valid(*a)).sum::>(), - sat(1400).into(), - ); - assert_eq!( - amounts.into_iter().map(NumOpResult::Valid).sum::>(), - sat(1400).into(), - ); - - let amounts = [ssat(-42), ssat(1337), ssat(21)]; - assert_eq!( - amounts.iter().map(NumOpResult::from).sum::>(), - ssat(1316).into(), - ); - assert_eq!( - amounts.into_iter().map(NumOpResult::from).sum::>(), - ssat(1316).into() - ); -} - -#[test] -fn checked_sum_amounts() { - assert_eq!([].into_iter().checked_sum(), Some(Amount::ZERO)); - assert_eq!([].into_iter().checked_sum(), Some(SignedAmount::ZERO)); + let empty: [NumOpResult; 0] = []; + assert_eq!(empty.into_iter().sum::>(), NumOpResult::Valid(Amount::ZERO)); + let empty: [NumOpResult; 0] = []; + assert_eq!(empty.into_iter().sum::>(), NumOpResult::Valid(SignedAmount::ZERO)); let amounts = [sat(42), sat(1337), sat(21)]; - let sum = amounts.into_iter().checked_sum(); - assert_eq!(sum, Some(sat(1400))); + let sum = amounts + .into_iter() + .map(NumOpResult::from) + .sum::>() + .unwrap(); + assert_eq!(sum, sat(1400)); let amounts = [Amount::MAX_MONEY, sat(1337), sat(21)]; - let sum = amounts.into_iter().checked_sum(); - assert_eq!(sum, None); + assert!(amounts + .into_iter() + .map(NumOpResult::from) + .sum::>() + .is_error()); let amounts = [SignedAmount::MIN, ssat(-1), ssat(21)]; - let sum = amounts.into_iter().checked_sum(); - assert_eq!(sum, None); + assert!(amounts + .into_iter() + .map(NumOpResult::from) + .sum::>() + .is_error()); let amounts = [SignedAmount::MAX, ssat(1), ssat(21)]; - let sum = amounts.into_iter().checked_sum(); - assert_eq!(sum, None); + assert!(amounts + .into_iter() + .map(NumOpResult::from) + .sum::>() + .is_error()); let amounts = [ssat(42), ssat(3301), ssat(21)]; - let sum = amounts.into_iter().checked_sum(); - assert_eq!(sum, Some(ssat(3364))); + let sum = amounts + .into_iter() + .map(NumOpResult::from) + .sum::>() + .unwrap(); + assert_eq!(sum, ssat(3364)); } #[test] diff --git a/units/src/lib.rs b/units/src/lib.rs index 12c8186502..56d173cfda 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -69,21 +69,3 @@ pub(crate) use self::result::OptionExt; #[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")] #[doc(hidden)] pub type BlockInterval = BlockHeightInterval; - -/// Calculates the sum over the iterator using checked arithmetic. -pub trait CheckedSum: sealed::Sealed { - /// Calculates the sum over the iterator using checked arithmetic. If an - /// overflow happens it returns [`None`]. - fn checked_sum(self) -> Option; -} - -mod sealed { - use super::{Amount, SignedAmount, Weight}; - - /// Used to seal the `CheckedSum` trait - pub trait Sealed {} - - impl Sealed for T where T: Iterator {} - impl Sealed for T where T: Iterator {} - impl Sealed for T where T: Iterator {} -} diff --git a/units/tests/api.rs b/units/tests/api.rs index c5db6da465..0d34bfdb46 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -15,8 +15,8 @@ use arbitrary::{Arbitrary, Unstructured}; use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::LockTime`. use bitcoin_units::{ amount, block, fee_rate, locktime, parse, time, weight, Amount, BlockHeight, - BlockHeightInterval, BlockMtp, BlockMtpInterval, BlockTime, CheckedSum, FeeRate, MathOp, - NumOpResult, SignedAmount, Weight, + BlockHeightInterval, BlockMtp, BlockMtpInterval, BlockTime, FeeRate, MathOp, NumOpResult, + SignedAmount, Weight, }; /// A struct that includes all public non-error enums. @@ -283,8 +283,6 @@ fn regression_default() { fn dyn_compatible() { // If this builds then traits are dyn compatible. struct Traits { - a: Box>, - b: Box>, // These traits are explicitly not dyn compatible. // b: Box, // c: Box, From 011b629b36c69aecf0bab0ddaae191c77e448303 Mon Sep 17 00:00:00 2001 From: Update Nightly Rustc Bot Date: Sat, 12 Jul 2025 02:07:19 +0000 Subject: [PATCH 163/857] Automated update to Github CI to rustc nightly-2025-07-11 --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index 025bab15be..98cd340e39 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-07-04 +nightly-2025-07-11 From 53f1aad7d4777936cef46e7b4b6a26bc866bbcc6 Mon Sep 17 00:00:00 2001 From: otc group Date: Sat, 12 Jul 2025 23:30:08 +0200 Subject: [PATCH 164/857] fix misspelled macro's name --- hashes/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashes/src/macros.rs b/hashes/src/macros.rs index 162af9a032..283a627030 100644 --- a/hashes/src/macros.rs +++ b/hashes/src/macros.rs @@ -356,7 +356,7 @@ macro_rules! hash_newtype_struct { // duplicates/conflicts and report an error. // // FYI, no, we can't use a helper macro to first filter all `hash_newtype` attributes. We would be -// attempting to match on macros instead. So we must write `hashe_newtype` in each branch. +// attempting to match on macros instead. So we must write `hash_newtype` in each branch. #[doc(hidden)] #[macro_export] macro_rules! hash_newtype_get_direction { From 233e11bb265efa32523edc333a6602370663fcee Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 13 Jul 2025 01:51:02 +0000 Subject: [PATCH 165/857] 2025-07-13 automated rustfmt nightly --- bitcoin/tests/bip_174.rs | 4 ++-- p2p/src/message.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bitcoin/tests/bip_174.rs b/bitcoin/tests/bip_174.rs index 15ab7376dd..0eacb8782a 100644 --- a/bitcoin/tests/bip_174.rs +++ b/bitcoin/tests/bip_174.rs @@ -12,8 +12,8 @@ use bitcoin::psbt::{Psbt, PsbtSighashType}; use bitcoin::script::{PushBytes, ScriptBufExt as _}; use bitcoin::secp256k1::Secp256k1; use bitcoin::{ - absolute, script, transaction, NetworkKind, OutPoint, PrivateKey, - PublicKey, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Witness, + absolute, script, transaction, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf, + Sequence, Transaction, TxIn, TxOut, Witness, }; #[track_caller] diff --git a/p2p/src/message.rs b/p2p/src/message.rs index eca3abadbf..942e258285 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -901,10 +901,16 @@ mod test { assert_eq!(cs.unwrap(), CommandString::try_from_static("\0And\0rew").unwrap()); // Invalid CommandString, must be ASCII - assert!(deserialize::(&[0, 0x41u8, 0x6e, 0xa4, 0, 0x72, 0x65, 0x77, 0, 0, 0, 0]).is_err()); + assert!(deserialize::(&[ + 0, 0x41u8, 0x6e, 0xa4, 0, 0x72, 0x65, 0x77, 0, 0, 0, 0 + ]) + .is_err()); // Invalid CommandString, must be 12 bytes - assert!(deserialize::(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]).is_err()); + assert!(deserialize::(&[ + 0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0 + ]) + .is_err()); } #[test] From 7c438b277e4eec61d40d66bd760428976bafd7cd Mon Sep 17 00:00:00 2001 From: jrakibi Date: Tue, 24 Jun 2025 17:34:42 +0800 Subject: [PATCH 166/857] transaction: Implement Coinbase type with explicit API design We provide explicit convenience methods (compute_txid, compute_wtxid) rather than implementing Deref to only expose methods that make sense for coinbase transactions. This prevents inheritance of the entire Transaction API. inner() serves as an escape hatch when full Transaction access is needed. This forces the user to be explicit about when they need the underlying Transaction functionalities. Following this approach, we avoid implicit inheritance through Deref. We also added assume_* methods to make it clear that the caller is responsible for ensuring the transaction is actually a coinbase transaction in the first position of a block --- bitcoin/src/blockdata/transaction.rs | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 006809449f..e77168025b 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1169,6 +1169,42 @@ internals::transparent_newtype! { pub fn assume_coinbase_ref(inner: &_) -> &Self; } } + +impl Coinbase { + /// Creates a `Coinbase` wrapper assuming this transaction is a coinbase transaction. + /// + /// This method does not validate that the transaction is actually a coinbase transaction. + /// The caller must ensure that this transaction is indeed a valid coinbase transaction. + pub fn assume_coinbase(tx: Transaction) -> Self { + Self(tx) + } + + /// Returns a reference to the underlying transaction. + /// + /// Warning: The coinbase input contains dummy prevouts that should not be treated as real prevouts. + #[doc(alias = "as_inner")] + pub fn as_transaction(&self) -> &Transaction { &self.0 } + + /// Returns the underlying transaction. + /// + /// Warning: The coinbase input contains dummy prevouts that should not be treated as real prevouts. + #[doc(alias = "into_inner")] + pub fn into_transaction(self) -> Transaction { self.0 } + + /// Computes the [`Txid`] of this coinbase transaction. + pub fn compute_txid(&self) -> Txid { + self.0.compute_txid() + } + + /// Returns the wtxid of this coinbase transaction. + /// + /// For coinbase transactions, this is always `Wtxid::COINBASE`. + #[doc(alias = "compute_wtxid")] + pub const fn wtxid(&self) -> Wtxid { + Wtxid::COINBASE + } +} + mod sealed { pub trait Sealed {} impl Sealed for super::Transaction {} From ca4d87dd4a028c40b62a054fbb67d8f5d721262e Mon Sep 17 00:00:00 2001 From: jrakibi Date: Tue, 24 Jun 2025 17:41:10 +0800 Subject: [PATCH 167/857] Change Block::coinbase() to return &Coinbase instead of Option<&Transaction> This change has semantic meaning: it guarantees that every checked Block has a coinbase as its first transaction. The method is now infallible for validated blocks. As a follow-up, update bip34_block_height to work with the new Coinbase type: - Removed unnecessary error handling, since coinbase() now returns &Coinbase instead of Option<&Transaction>. - Used cb.inner() to access the underlying Transaction fields for input processing. --- bitcoin/src/blockdata/block.rs | 20 +++++++++++++------- bitcoin/src/blockdata/transaction.rs | 8 ++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 7154254d0b..d41c3176a2 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -15,6 +15,7 @@ use internals::{compact_size, ToU64}; use io::{BufRead, Write}; use units::BlockTime; +use super::transaction::Coinbase; use super::Weight; use crate::consensus::encode::WriteExt as _; use crate::consensus::{encode, Decodable, Encodable}; @@ -258,8 +259,11 @@ pub trait BlockCheckedExt: sealed::Sealed { /// > including base data and witness data. fn total_size(&self) -> usize; - /// Returns the coinbase transaction, if one is present. - fn coinbase(&self) -> Option<&Transaction>; + /// Returns the coinbase transaction. + /// + /// This method is infallible for checked blocks because validation ensures + /// that a valid coinbase transaction is always present. + fn coinbase(&self) -> &Coinbase; /// Returns the block height, as encoded in the coinbase transaction according to BIP34. fn bip34_block_height(&self) -> Result; @@ -293,8 +297,10 @@ impl BlockCheckedExt for Block { size } - /// Returns the coinbase transaction, if one is present. - fn coinbase(&self) -> Option<&Transaction> { self.transactions().first() } + fn coinbase(&self) -> &Coinbase { + let first_tx = &self.transactions()[0]; + Coinbase::assume_coinbase_ref(first_tx) + } /// Returns the block height, as encoded in the coinbase transaction according to BIP34. fn bip34_block_height(&self) -> Result { @@ -311,8 +317,8 @@ impl BlockCheckedExt for Block { return Err(Bip34Error::Unsupported); } - let cb = self.coinbase().ok_or(Bip34Error::NotPresent)?; - let input = cb.input.first().ok_or(Bip34Error::NotPresent)?; + let cb = self.coinbase(); + let input = cb.first_input(); let push = input .script_sig .instructions_minimal() @@ -539,7 +545,7 @@ mod tests { let block = block.assume_checked(None); let cb_txid = "d574f343976d8e70d91cb278d21044dd8a396019e6db70755a0a50e4783dba38"; - assert_eq!(block.coinbase().unwrap().compute_txid().to_string(), cb_txid); + assert_eq!(block.coinbase().compute_txid().to_string(), cb_txid); assert_eq!(block.bip34_block_height(), Ok(100_000)); diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index e77168025b..418b1c9a2a 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1179,6 +1179,14 @@ impl Coinbase { Self(tx) } + /// Returns the first input of this coinbase transaction. + /// + /// This method is infallible because a valid coinbase transaction is guaranteed + /// to have exactly one input. + pub fn first_input(&self) -> &TxIn { + &self.0.input[0] + } + /// Returns a reference to the underlying transaction. /// /// Warning: The coinbase input contains dummy prevouts that should not be treated as real prevouts. From 0edabd471fd7993bb94df0554497600022cc8ad2 Mon Sep 17 00:00:00 2001 From: jrakibi Date: Tue, 24 Jun 2025 17:51:12 +0800 Subject: [PATCH 168/857] Add coinbase validation to Block::validate() with new error variants Add validation checks to Block::validate() to ensure blocks have a valid coinbase: - Check for empty transaction list (NoTransactions error) - Verify first transaction is coinbase (InvalidCoinbase error) The validation now happens during Block::validate() rather than requiring every caller to check coinbase presence separately. --- bitcoin/src/blockdata/block.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index d41c3176a2..ff37ce51fc 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -118,6 +118,14 @@ impl BlockUncheckedExt for Block { fn validate(self) -> Result, InvalidBlockError> { let (header, transactions) = self.into_parts(); + if transactions.is_empty() { + return Err(InvalidBlockError::NoTransactions); + } + + if !transactions[0].is_coinbase() { + return Err(InvalidBlockError::InvalidCoinbase); + } + if !check_merkle_root(&header, &transactions) { return Err(InvalidBlockError::InvalidMerkleRoot); } @@ -405,6 +413,10 @@ pub enum InvalidBlockError { InvalidMerkleRoot, /// The witness commitment in coinbase transaction does not match the calculated witness_root. InvalidWitnessCommitment, + /// Block has no transactions (missing coinbase). + NoTransactions, + /// The first transaction is not a valid coinbase transaction. + InvalidCoinbase, } impl From for InvalidBlockError { @@ -418,6 +430,8 @@ impl fmt::Display for InvalidBlockError { match *self { InvalidMerkleRoot => write!(f, "header Merkle root does not match the calculated Merkle root"), InvalidWitnessCommitment => write!(f, "the witness commitment in coinbase transaction does not match the calculated witness_root"), + NoTransactions => write!(f, "block has no transactions (missing coinbase)"), + InvalidCoinbase => write!(f, "the first transaction is not a valid coinbase transaction"), } } } From 394fa537508674388f2cd4cdb23eccbc51d599ae Mon Sep 17 00:00:00 2001 From: jrakibi Date: Tue, 24 Jun 2025 17:59:29 +0800 Subject: [PATCH 169/857] Add comprehensive tests for Coinbase type and block validation Add thorough test coverage for the new Coinbase type and validation logic --- bitcoin/src/blockdata/block.rs | 137 +++++++++++++++++++++++++++ bitcoin/src/blockdata/transaction.rs | 19 ++++ 2 files changed, 156 insertions(+) diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index ff37ce51fc..f74ebfb15b 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -533,7 +533,10 @@ mod tests { use super::*; use crate::consensus::encode::{deserialize, serialize}; use crate::pow::test_utils::{u128_to_work, u64_to_work}; + use crate::script::ScriptBuf; + use crate::transaction::{OutPoint, Transaction, TxIn, TxOut, Txid}; use crate::{block, CompactTarget, Network, TestnetVersion}; + use crate::{Amount, Sequence, Witness}; #[test] fn static_vector() { @@ -781,6 +784,140 @@ mod tests { assert!(segwit_signal.is_signalling_soft_fork(1)); assert!(!segwit_signal.is_signalling_soft_fork(2)); } + + #[test] + fn block_validation_no_transactions() { + let header = header(); + let transactions = Vec::new(); // Empty transactions + + let block = Block::new_unchecked(header, transactions); + match block.validate() { + Err(InvalidBlockError::NoTransactions) => (), + other => panic!("Expected NoTransactions error, got: {:?}", other), + } + } + + #[test] + fn block_validation_invalid_coinbase() { + let header = header(); + + // Create a non-coinbase transaction (has a real previous output, not all zeros) + let non_coinbase_tx = Transaction { + version: primitives::transaction::Version::TWO, + lock_time: crate::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { + txid: Txid::from_byte_array([1; 32]), // Not all zeros + vout: 0, + }, + script_sig: ScriptBuf::new(), + sequence: Sequence::ENABLE_LOCKTIME_AND_RBF, + witness: Witness::new(), + }], + output: vec![TxOut { value: Amount::ONE_BTC, script_pubkey: ScriptBuf::new() }], + }; + + let transactions = vec![non_coinbase_tx]; + let block = Block::new_unchecked(header, transactions); + + match block.validate() { + Err(InvalidBlockError::InvalidCoinbase) => (), + other => panic!("Expected InvalidCoinbase error, got: {:?}", other), + } + } + + #[test] + fn block_validation_success_with_coinbase() { + use crate::constants; + + // Use the genesis block which has a valid coinbase + let genesis = constants::genesis_block(Network::Bitcoin); + + let header = *genesis.header(); + let transactions = genesis.transactions().to_vec(); + + let unchecked_block = Block::new_unchecked(header, transactions); + let validated_block = unchecked_block.validate(); + + assert!(validated_block.is_ok(), "Genesis block should validate successfully"); + } + + #[test] + fn checked_block_coinbase_method() { + use crate::constants; + + let genesis = constants::genesis_block(Network::Bitcoin); + let coinbase = genesis.coinbase(); + + // Test that coinbase method returns the expected transaction + let expected_txid = genesis.transactions()[0].compute_txid(); + assert_eq!(coinbase.compute_txid(), expected_txid); + assert_eq!(coinbase.wtxid(), Wtxid::COINBASE); + + // Test that as_inner() returns the correct transaction + assert_eq!(coinbase.as_transaction(), &genesis.transactions()[0]); + } + + #[test] + fn block_new_checked_validation() { + use crate::constants; + + // Test successful validation with genesis block + let genesis = constants::genesis_block(Network::Bitcoin); + let header = *genesis.header(); + let transactions = genesis.transactions().to_vec(); + + let checked_block = Block::new_checked(header, transactions.clone()); + assert!(checked_block.is_ok(), "Genesis block should validate via new_checked"); + + // Test validation failure with empty transactions + let empty_result = Block::new_checked(header, Vec::new()); + match empty_result { + Err(InvalidBlockError::NoTransactions) => (), + other => panic!("Expected NoTransactions error, got: {:?}", other), + } + + // Test validation failure with invalid coinbase + let non_coinbase_tx = Transaction { + version: primitives::transaction::Version::TWO, + lock_time: crate::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { + txid: Txid::from_byte_array([1; 32]), // Not all zeros + vout: 0, + }, + script_sig: ScriptBuf::new(), + sequence: Sequence::ENABLE_LOCKTIME_AND_RBF, + witness: Witness::new(), + }], + output: vec![TxOut { value: Amount::ONE_BTC, script_pubkey: ScriptBuf::new() }], + }; + + let invalid_coinbase_result = Block::new_checked(header, vec![non_coinbase_tx]); + match invalid_coinbase_result { + Err(InvalidBlockError::InvalidCoinbase) => (), + other => panic!("Expected InvalidCoinbase error, got: {:?}", other), + } + } + + #[test] + fn coinbase_bip34_height_with_coinbase_type() { + // testnet block 100,000 + const BLOCK_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3703a08601000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000"; + let block: Block = deserialize(&hex!(BLOCK_HEX)).unwrap(); + let block = block.assume_checked(None); + + // Test that BIP34 height extraction works with the Coinbase type + assert_eq!(block.bip34_block_height(), Ok(100_000)); + + // Test that coinbase method returns a Coinbase type + let coinbase = block.coinbase(); + assert!(coinbase.as_transaction().is_coinbase()); + + // Test that the coinbase transaction ID matches expected + let cb_txid = "d574f343976d8e70d91cb278d21044dd8a396019e6db70755a0a50e4783dba38"; + assert_eq!(coinbase.compute_txid().to_string(), cb_txid); + } } #[cfg(bench)] diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 418b1c9a2a..296dd213f7 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -2127,6 +2127,25 @@ mod tests { let pretty_txid = "0x0000000000000000000000000000000000000000000000000000000000000000"; assert_eq!(pretty_txid, format!("{:#}", &outpoint.txid)); } + + #[test] + fn coinbase_assume_methods() { + use crate::constants; + use crate::network::Network; + + let genesis = constants::genesis_block(Network::Bitcoin); + let coinbase_tx = &genesis.transactions()[0]; + + // Test that we can create a Coinbase reference using assume_coinbase_ref + let coinbase_ref = Coinbase::assume_coinbase_ref(coinbase_tx); + assert_eq!(coinbase_ref.compute_txid(), coinbase_tx.compute_txid()); + assert_eq!(coinbase_ref.wtxid(), Wtxid::COINBASE); + + // Test that we can create a Coinbase using assume_coinbase + let coinbase_owned = Coinbase::assume_coinbase(coinbase_tx.clone()); + assert_eq!(coinbase_owned.compute_txid(), coinbase_tx.compute_txid()); + assert_eq!(coinbase_owned.wtxid(), Wtxid::COINBASE); + } } #[cfg(bench)] From 80101afa2ac4fe5245c8c67a23c63298b2ddb8e7 Mon Sep 17 00:00:00 2001 From: geekvest Date: Tue, 15 Jul 2025 11:10:01 +0800 Subject: [PATCH 170/857] chore: add the missing backticks Signed-off-by: geekvest --- primitives/tests/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/tests/api.rs b/primitives/tests/api.rs index f020acf27c..4cedc5ec84 100644 --- a/primitives/tests/api.rs +++ b/primitives/tests/api.rs @@ -63,7 +63,7 @@ static SCRIPT: ScriptBuf = ScriptBuf::new(); static BYTES: [u8; 32] = [0x00; 32]; /// Public structs that derive common traits. -// C-COMMON-TRAITS excluding `Debug`, `Default`, `Display`, `Ord`, `PartialOrd, `Hash`. +// C-COMMON-TRAITS excluding `Debug`, `Default`, `Display`, `Ord`, `PartialOrd`, `Hash`. #[derive(Clone, PartialEq, Eq)] struct CommonTraits { a: block::Block, From bcc0f77ab9509c15f659277b1b7afcdf10fb307f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 15 Jul 2025 12:39:38 +1000 Subject: [PATCH 171/857] units: Enable cargo public-api Update the script to only build for `units` because it is the only crate currently in the 1.0 RC cycle. Add the output files generated by `cargo public-api` to `api/units`. --- api/units/all-features.txt | 2209 ++++++++++++++++++++++++++++++ api/units/alloc-only.txt | 2028 +++++++++++++++++++++++++++ api/units/no-features.txt | 1978 ++++++++++++++++++++++++++ contrib/check-for-api-changes.sh | 6 +- 4 files changed, 6217 insertions(+), 4 deletions(-) create mode 100644 api/units/all-features.txt create mode 100644 api/units/alloc-only.txt create mode 100644 api/units/no-features.txt diff --git a/api/units/all-features.txt b/api/units/all-features.txt new file mode 100644 index 0000000000..4f4be7971a --- /dev/null +++ b/api/units/all-features.txt @@ -0,0 +1,2209 @@ +#[non_exhaustive] pub enum bitcoin_units::MathOp +#[non_exhaustive] pub enum bitcoin_units::amount::Denomination +#[non_exhaustive] pub enum bitcoin_units::amount::ParseDenominationError +#[non_exhaustive] pub struct bitcoin_units::NumOpError(_) +#[non_exhaustive] pub struct bitcoin_units::amount::MissingDenominationError +#[non_exhaustive] pub struct bitcoin_units::amount::PossiblyConfusingDenominationError(_) +#[non_exhaustive] pub struct bitcoin_units::amount::UnknownDenominationError(_) +#[non_exhaustive] pub struct bitcoin_units::fee_rate::serde::OverflowError +#[non_exhaustive] pub struct bitcoin_units::locktime::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::parse::ParseIntError +impl bitcoin_units::Amount +impl bitcoin_units::BlockTime +impl bitcoin_units::FeeRate +impl bitcoin_units::MathOp +impl bitcoin_units::NumOpError +impl bitcoin_units::SignedAmount +impl bitcoin_units::Weight +impl bitcoin_units::amount::Denomination +impl bitcoin_units::amount::Display +impl bitcoin_units::amount::OutOfRangeError +impl bitcoin_units::amount::serde::SerdeAmount for bitcoin_units::Amount +impl bitcoin_units::amount::serde::SerdeAmount for bitcoin_units::SignedAmount +impl bitcoin_units::amount::serde::SerdeAmountForOpt for bitcoin_units::Amount +impl bitcoin_units::amount::serde::SerdeAmountForOpt for bitcoin_units::SignedAmount +impl bitcoin_units::block::BlockHeight +impl bitcoin_units::block::BlockHeightInterval +impl bitcoin_units::block::BlockMtp +impl bitcoin_units::block::BlockMtpInterval +impl bitcoin_units::locktime::absolute::Height +impl bitcoin_units::locktime::absolute::MedianTimePast +impl bitcoin_units::locktime::relative::NumberOf512Seconds +impl bitcoin_units::locktime::relative::NumberOfBlocks +impl bitcoin_units::parse::Integer for i128 +impl bitcoin_units::parse::Integer for i16 +impl bitcoin_units::parse::Integer for i32 +impl bitcoin_units::parse::Integer for i64 +impl bitcoin_units::parse::Integer for i8 +impl bitcoin_units::parse::Integer for u128 +impl bitcoin_units::parse::Integer for u16 +impl bitcoin_units::parse::Integer for u32 +impl bitcoin_units::parse::Integer for u64 +impl bitcoin_units::parse::Integer for u8 +impl core::clone::Clone for bitcoin_units::Amount +impl core::clone::Clone for bitcoin_units::BlockTime +impl core::clone::Clone for bitcoin_units::FeeRate +impl core::clone::Clone for bitcoin_units::MathOp +impl core::clone::Clone for bitcoin_units::NumOpError +impl core::clone::Clone for bitcoin_units::SignedAmount +impl core::clone::Clone for bitcoin_units::Weight +impl core::clone::Clone for bitcoin_units::amount::Denomination +impl core::clone::Clone for bitcoin_units::amount::Display +impl core::clone::Clone for bitcoin_units::amount::InputTooLargeError +impl core::clone::Clone for bitcoin_units::amount::InvalidCharacterError +impl core::clone::Clone for bitcoin_units::amount::MissingDenominationError +impl core::clone::Clone for bitcoin_units::amount::MissingDigitsError +impl core::clone::Clone for bitcoin_units::amount::OutOfRangeError +impl core::clone::Clone for bitcoin_units::amount::ParseAmountError +impl core::clone::Clone for bitcoin_units::amount::ParseDenominationError +impl core::clone::Clone for bitcoin_units::amount::ParseError +impl core::clone::Clone for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::clone::Clone for bitcoin_units::amount::TooPreciseError +impl core::clone::Clone for bitcoin_units::amount::UnknownDenominationError +impl core::clone::Clone for bitcoin_units::block::BlockHeight +impl core::clone::Clone for bitcoin_units::block::BlockHeightInterval +impl core::clone::Clone for bitcoin_units::block::BlockMtp +impl core::clone::Clone for bitcoin_units::block::BlockMtpInterval +impl core::clone::Clone for bitcoin_units::block::TooBigForRelativeHeightError +impl core::clone::Clone for bitcoin_units::fee_rate::serde::OverflowError +impl core::clone::Clone for bitcoin_units::locktime::absolute::ConversionError +impl core::clone::Clone for bitcoin_units::locktime::absolute::Height +impl core::clone::Clone for bitcoin_units::locktime::absolute::MedianTimePast +impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::clone::Clone for bitcoin_units::locktime::relative::TimeOverflowError +impl core::clone::Clone for bitcoin_units::parse::ParseIntError +impl core::clone::Clone for bitcoin_units::parse::PrefixedHexError +impl core::clone::Clone for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Eq for bitcoin_units::Amount +impl core::cmp::Eq for bitcoin_units::BlockTime +impl core::cmp::Eq for bitcoin_units::FeeRate +impl core::cmp::Eq for bitcoin_units::MathOp +impl core::cmp::Eq for bitcoin_units::NumOpError +impl core::cmp::Eq for bitcoin_units::SignedAmount +impl core::cmp::Eq for bitcoin_units::Weight +impl core::cmp::Eq for bitcoin_units::amount::Denomination +impl core::cmp::Eq for bitcoin_units::amount::InputTooLargeError +impl core::cmp::Eq for bitcoin_units::amount::InvalidCharacterError +impl core::cmp::Eq for bitcoin_units::amount::MissingDenominationError +impl core::cmp::Eq for bitcoin_units::amount::MissingDigitsError +impl core::cmp::Eq for bitcoin_units::amount::OutOfRangeError +impl core::cmp::Eq for bitcoin_units::amount::ParseAmountError +impl core::cmp::Eq for bitcoin_units::amount::ParseDenominationError +impl core::cmp::Eq for bitcoin_units::amount::ParseError +impl core::cmp::Eq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::cmp::Eq for bitcoin_units::amount::TooPreciseError +impl core::cmp::Eq for bitcoin_units::amount::UnknownDenominationError +impl core::cmp::Eq for bitcoin_units::block::BlockHeight +impl core::cmp::Eq for bitcoin_units::block::BlockHeightInterval +impl core::cmp::Eq for bitcoin_units::block::BlockMtp +impl core::cmp::Eq for bitcoin_units::block::BlockMtpInterval +impl core::cmp::Eq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::cmp::Eq for bitcoin_units::fee_rate::serde::OverflowError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ConversionError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::Height +impl core::cmp::Eq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::Eq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::Eq for bitcoin_units::parse::ParseIntError +impl core::cmp::Eq for bitcoin_units::parse::PrefixedHexError +impl core::cmp::Eq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Ord for bitcoin_units::Amount +impl core::cmp::Ord for bitcoin_units::BlockTime +impl core::cmp::Ord for bitcoin_units::FeeRate +impl core::cmp::Ord for bitcoin_units::SignedAmount +impl core::cmp::Ord for bitcoin_units::Weight +impl core::cmp::Ord for bitcoin_units::block::BlockHeight +impl core::cmp::Ord for bitcoin_units::block::BlockHeightInterval +impl core::cmp::Ord for bitcoin_units::block::BlockMtp +impl core::cmp::Ord for bitcoin_units::block::BlockMtpInterval +impl core::cmp::Ord for bitcoin_units::locktime::absolute::Height +impl core::cmp::Ord for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialEq for bitcoin_units::Amount +impl core::cmp::PartialEq for bitcoin_units::BlockTime +impl core::cmp::PartialEq for bitcoin_units::FeeRate +impl core::cmp::PartialEq for bitcoin_units::MathOp +impl core::cmp::PartialEq for bitcoin_units::NumOpError +impl core::cmp::PartialEq for bitcoin_units::SignedAmount +impl core::cmp::PartialEq for bitcoin_units::Weight +impl core::cmp::PartialEq for bitcoin_units::amount::Denomination +impl core::cmp::PartialEq for bitcoin_units::amount::InputTooLargeError +impl core::cmp::PartialEq for bitcoin_units::amount::InvalidCharacterError +impl core::cmp::PartialEq for bitcoin_units::amount::MissingDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::MissingDigitsError +impl core::cmp::PartialEq for bitcoin_units::amount::OutOfRangeError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseAmountError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseError +impl core::cmp::PartialEq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::TooPreciseError +impl core::cmp::PartialEq for bitcoin_units::amount::UnknownDenominationError +impl core::cmp::PartialEq for bitcoin_units::block::BlockHeight +impl core::cmp::PartialEq for bitcoin_units::block::BlockHeightInterval +impl core::cmp::PartialEq for bitcoin_units::block::BlockMtp +impl core::cmp::PartialEq for bitcoin_units::block::BlockMtpInterval +impl core::cmp::PartialEq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::cmp::PartialEq for bitcoin_units::fee_rate::serde::OverflowError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ConversionError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::PartialEq for bitcoin_units::parse::ParseIntError +impl core::cmp::PartialEq for bitcoin_units::parse::PrefixedHexError +impl core::cmp::PartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::PartialOrd for bitcoin_units::Amount +impl core::cmp::PartialOrd for bitcoin_units::BlockTime +impl core::cmp::PartialOrd for bitcoin_units::FeeRate +impl core::cmp::PartialOrd for bitcoin_units::SignedAmount +impl core::cmp::PartialOrd for bitcoin_units::Weight +impl core::cmp::PartialOrd for bitcoin_units::block::BlockHeight +impl core::cmp::PartialOrd for bitcoin_units::block::BlockHeightInterval +impl core::cmp::PartialOrd for bitcoin_units::block::BlockMtp +impl core::cmp::PartialOrd for bitcoin_units::block::BlockMtpInterval +impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::AsRef for bitcoin_units::parse::ParseIntError +impl core::convert::From<&bitcoin_units::Amount> for bitcoin_units::NumOpResult +impl core::convert::From<&bitcoin_units::SignedAmount> for bitcoin_units::NumOpResult +impl core::convert::From for bitcoin_units::NumOpResult +impl core::convert::From for bitcoin_units::SignedAmount +impl core::convert::From for u32 +impl core::convert::From for bitcoin_units::NumOpResult +impl core::convert::From for u64 +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::parse::PrefixedHexError +impl core::convert::From for bitcoin_units::parse::UnprefixedHexError +impl core::convert::From for core::num::error::ParseIntError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseDenominationError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::fee_rate::serde::OverflowError +impl core::convert::From for bitcoin_units::parse::PrefixedHexError +impl core::convert::From for bitcoin_units::parse::UnprefixedHexError +impl core::convert::From for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::From for bitcoin_units::BlockTime +impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom<&str> for bitcoin_units::Weight +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom> for bitcoin_units::Weight +impl core::convert::TryFrom> for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom> for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom> for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom> for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::Weight +impl core::convert::TryFrom for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::Amount +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::default::Default for bitcoin_units::Amount +impl core::default::Default for bitcoin_units::SignedAmount +impl core::default::Default for bitcoin_units::block::BlockHeightInterval +impl core::default::Default for bitcoin_units::block::BlockMtpInterval +impl core::default::Default for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::default::Default for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::error::Error for bitcoin_units::NumOpError +impl core::error::Error for bitcoin_units::amount::InputTooLargeError +impl core::error::Error for bitcoin_units::amount::InvalidCharacterError +impl core::error::Error for bitcoin_units::amount::MissingDigitsError +impl core::error::Error for bitcoin_units::amount::OutOfRangeError +impl core::error::Error for bitcoin_units::amount::ParseAmountError +impl core::error::Error for bitcoin_units::amount::ParseDenominationError +impl core::error::Error for bitcoin_units::amount::ParseError +impl core::error::Error for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::error::Error for bitcoin_units::amount::TooPreciseError +impl core::error::Error for bitcoin_units::amount::UnknownDenominationError +impl core::error::Error for bitcoin_units::block::TooBigForRelativeHeightError +impl core::error::Error for bitcoin_units::fee_rate::serde::OverflowError +impl core::error::Error for bitcoin_units::locktime::absolute::ConversionError +impl core::error::Error for bitcoin_units::locktime::absolute::ParseHeightError +impl core::error::Error for bitcoin_units::locktime::absolute::ParseTimeError +impl core::error::Error for bitcoin_units::locktime::relative::InvalidHeightError +impl core::error::Error for bitcoin_units::locktime::relative::InvalidTimeError +impl core::error::Error for bitcoin_units::locktime::relative::TimeOverflowError +impl core::error::Error for bitcoin_units::parse::ParseIntError +impl core::error::Error for bitcoin_units::parse::PrefixedHexError +impl core::error::Error for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Debug for bitcoin_units::Amount +impl core::fmt::Debug for bitcoin_units::BlockTime +impl core::fmt::Debug for bitcoin_units::FeeRate +impl core::fmt::Debug for bitcoin_units::MathOp +impl core::fmt::Debug for bitcoin_units::NumOpError +impl core::fmt::Debug for bitcoin_units::SignedAmount +impl core::fmt::Debug for bitcoin_units::Weight +impl core::fmt::Debug for bitcoin_units::amount::Denomination +impl core::fmt::Debug for bitcoin_units::amount::Display +impl core::fmt::Debug for bitcoin_units::amount::InputTooLargeError +impl core::fmt::Debug for bitcoin_units::amount::InvalidCharacterError +impl core::fmt::Debug for bitcoin_units::amount::MissingDenominationError +impl core::fmt::Debug for bitcoin_units::amount::MissingDigitsError +impl core::fmt::Debug for bitcoin_units::amount::OutOfRangeError +impl core::fmt::Debug for bitcoin_units::amount::ParseAmountError +impl core::fmt::Debug for bitcoin_units::amount::ParseDenominationError +impl core::fmt::Debug for bitcoin_units::amount::ParseError +impl core::fmt::Debug for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::fmt::Debug for bitcoin_units::amount::TooPreciseError +impl core::fmt::Debug for bitcoin_units::amount::UnknownDenominationError +impl core::fmt::Debug for bitcoin_units::block::BlockHeight +impl core::fmt::Debug for bitcoin_units::block::BlockHeightInterval +impl core::fmt::Debug for bitcoin_units::block::BlockMtp +impl core::fmt::Debug for bitcoin_units::block::BlockMtpInterval +impl core::fmt::Debug for bitcoin_units::block::TooBigForRelativeHeightError +impl core::fmt::Debug for bitcoin_units::fee_rate::serde::OverflowError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ConversionError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::Height +impl core::fmt::Debug for bitcoin_units::locktime::absolute::MedianTimePast +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Debug for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Debug for bitcoin_units::parse::ParseIntError +impl core::fmt::Debug for bitcoin_units::parse::PrefixedHexError +impl core::fmt::Debug for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Display for bitcoin_units::Amount +impl core::fmt::Display for bitcoin_units::MathOp +impl core::fmt::Display for bitcoin_units::NumOpError +impl core::fmt::Display for bitcoin_units::SignedAmount +impl core::fmt::Display for bitcoin_units::Weight +impl core::fmt::Display for bitcoin_units::amount::Denomination +impl core::fmt::Display for bitcoin_units::amount::Display +impl core::fmt::Display for bitcoin_units::amount::InputTooLargeError +impl core::fmt::Display for bitcoin_units::amount::InvalidCharacterError +impl core::fmt::Display for bitcoin_units::amount::MissingDigitsError +impl core::fmt::Display for bitcoin_units::amount::OutOfRangeError +impl core::fmt::Display for bitcoin_units::amount::ParseAmountError +impl core::fmt::Display for bitcoin_units::amount::ParseDenominationError +impl core::fmt::Display for bitcoin_units::amount::ParseError +impl core::fmt::Display for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::fmt::Display for bitcoin_units::amount::TooPreciseError +impl core::fmt::Display for bitcoin_units::amount::UnknownDenominationError +impl core::fmt::Display for bitcoin_units::block::BlockHeight +impl core::fmt::Display for bitcoin_units::block::BlockHeightInterval +impl core::fmt::Display for bitcoin_units::block::BlockMtp +impl core::fmt::Display for bitcoin_units::block::BlockMtpInterval +impl core::fmt::Display for bitcoin_units::block::TooBigForRelativeHeightError +impl core::fmt::Display for bitcoin_units::fee_rate::serde::OverflowError +impl core::fmt::Display for bitcoin_units::locktime::absolute::ConversionError +impl core::fmt::Display for bitcoin_units::locktime::absolute::Height +impl core::fmt::Display for bitcoin_units::locktime::absolute::MedianTimePast +impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Display for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Display for bitcoin_units::parse::ParseIntError +impl core::fmt::Display for bitcoin_units::parse::PrefixedHexError +impl core::fmt::Display for bitcoin_units::parse::UnprefixedHexError +impl core::hash::Hash for bitcoin_units::Amount +impl core::hash::Hash for bitcoin_units::BlockTime +impl core::hash::Hash for bitcoin_units::FeeRate +impl core::hash::Hash for bitcoin_units::SignedAmount +impl core::hash::Hash for bitcoin_units::Weight +impl core::hash::Hash for bitcoin_units::amount::Denomination +impl core::hash::Hash for bitcoin_units::block::BlockHeight +impl core::hash::Hash for bitcoin_units::block::BlockHeightInterval +impl core::hash::Hash for bitcoin_units::block::BlockMtp +impl core::hash::Hash for bitcoin_units::block::BlockMtpInterval +impl core::hash::Hash for bitcoin_units::locktime::absolute::Height +impl core::hash::Hash for bitcoin_units::locktime::absolute::MedianTimePast +impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::iter::traits::accum::Sum for bitcoin_units::FeeRate +impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult +impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult +impl core::iter::traits::accum::Sum for bitcoin_units::Weight +impl core::iter::traits::accum::Sum for bitcoin_units::block::BlockHeightInterval +impl core::iter::traits::accum::Sum for bitcoin_units::block::BlockMtpInterval +impl core::marker::Copy for bitcoin_units::Amount +impl core::marker::Copy for bitcoin_units::BlockTime +impl core::marker::Copy for bitcoin_units::FeeRate +impl core::marker::Copy for bitcoin_units::MathOp +impl core::marker::Copy for bitcoin_units::NumOpError +impl core::marker::Copy for bitcoin_units::SignedAmount +impl core::marker::Copy for bitcoin_units::Weight +impl core::marker::Copy for bitcoin_units::amount::Denomination +impl core::marker::Copy for bitcoin_units::amount::OutOfRangeError +impl core::marker::Copy for bitcoin_units::block::BlockHeight +impl core::marker::Copy for bitcoin_units::block::BlockHeightInterval +impl core::marker::Copy for bitcoin_units::block::BlockMtp +impl core::marker::Copy for bitcoin_units::block::BlockMtpInterval +impl core::marker::Copy for bitcoin_units::locktime::absolute::Height +impl core::marker::Copy for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Freeze for bitcoin_units::Amount +impl core::marker::Freeze for bitcoin_units::BlockTime +impl core::marker::Freeze for bitcoin_units::FeeRate +impl core::marker::Freeze for bitcoin_units::MathOp +impl core::marker::Freeze for bitcoin_units::NumOpError +impl core::marker::Freeze for bitcoin_units::SignedAmount +impl core::marker::Freeze for bitcoin_units::Weight +impl core::marker::Freeze for bitcoin_units::amount::Denomination +impl core::marker::Freeze for bitcoin_units::amount::Display +impl core::marker::Freeze for bitcoin_units::amount::InputTooLargeError +impl core::marker::Freeze for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Freeze for bitcoin_units::amount::MissingDenominationError +impl core::marker::Freeze for bitcoin_units::amount::MissingDigitsError +impl core::marker::Freeze for bitcoin_units::amount::OutOfRangeError +impl core::marker::Freeze for bitcoin_units::amount::ParseAmountError +impl core::marker::Freeze for bitcoin_units::amount::ParseDenominationError +impl core::marker::Freeze for bitcoin_units::amount::ParseError +impl core::marker::Freeze for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Freeze for bitcoin_units::amount::TooPreciseError +impl core::marker::Freeze for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Freeze for bitcoin_units::block::BlockHeight +impl core::marker::Freeze for bitcoin_units::block::BlockHeightInterval +impl core::marker::Freeze for bitcoin_units::block::BlockMtp +impl core::marker::Freeze for bitcoin_units::block::BlockMtpInterval +impl core::marker::Freeze for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Freeze for bitcoin_units::fee_rate::serde::OverflowError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::Height +impl core::marker::Freeze for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Freeze for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Freeze for bitcoin_units::parse::ParseIntError +impl core::marker::Freeze for bitcoin_units::parse::PrefixedHexError +impl core::marker::Freeze for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Send for bitcoin_units::Amount +impl core::marker::Send for bitcoin_units::BlockTime +impl core::marker::Send for bitcoin_units::FeeRate +impl core::marker::Send for bitcoin_units::MathOp +impl core::marker::Send for bitcoin_units::NumOpError +impl core::marker::Send for bitcoin_units::SignedAmount +impl core::marker::Send for bitcoin_units::Weight +impl core::marker::Send for bitcoin_units::amount::Denomination +impl core::marker::Send for bitcoin_units::amount::Display +impl core::marker::Send for bitcoin_units::amount::InputTooLargeError +impl core::marker::Send for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Send for bitcoin_units::amount::MissingDenominationError +impl core::marker::Send for bitcoin_units::amount::MissingDigitsError +impl core::marker::Send for bitcoin_units::amount::OutOfRangeError +impl core::marker::Send for bitcoin_units::amount::ParseAmountError +impl core::marker::Send for bitcoin_units::amount::ParseDenominationError +impl core::marker::Send for bitcoin_units::amount::ParseError +impl core::marker::Send for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Send for bitcoin_units::amount::TooPreciseError +impl core::marker::Send for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Send for bitcoin_units::block::BlockHeight +impl core::marker::Send for bitcoin_units::block::BlockHeightInterval +impl core::marker::Send for bitcoin_units::block::BlockMtp +impl core::marker::Send for bitcoin_units::block::BlockMtpInterval +impl core::marker::Send for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Send for bitcoin_units::fee_rate::serde::OverflowError +impl core::marker::Send for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Send for bitcoin_units::locktime::absolute::Height +impl core::marker::Send for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Send for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Send for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Send for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Send for bitcoin_units::parse::ParseIntError +impl core::marker::Send for bitcoin_units::parse::PrefixedHexError +impl core::marker::Send for bitcoin_units::parse::UnprefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::Amount +impl core::marker::StructuralPartialEq for bitcoin_units::BlockTime +impl core::marker::StructuralPartialEq for bitcoin_units::FeeRate +impl core::marker::StructuralPartialEq for bitcoin_units::MathOp +impl core::marker::StructuralPartialEq for bitcoin_units::NumOpError +impl core::marker::StructuralPartialEq for bitcoin_units::SignedAmount +impl core::marker::StructuralPartialEq for bitcoin_units::Weight +impl core::marker::StructuralPartialEq for bitcoin_units::amount::Denomination +impl core::marker::StructuralPartialEq for bitcoin_units::amount::InputTooLargeError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::InvalidCharacterError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::MissingDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::MissingDigitsError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::OutOfRangeError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseAmountError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::TooPreciseError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::UnknownDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeight +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeightInterval +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtp +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtpInterval +impl core::marker::StructuralPartialEq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::fee_rate::serde::OverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::Height +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::ParseIntError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::PrefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Sync for bitcoin_units::Amount +impl core::marker::Sync for bitcoin_units::BlockTime +impl core::marker::Sync for bitcoin_units::FeeRate +impl core::marker::Sync for bitcoin_units::MathOp +impl core::marker::Sync for bitcoin_units::NumOpError +impl core::marker::Sync for bitcoin_units::SignedAmount +impl core::marker::Sync for bitcoin_units::Weight +impl core::marker::Sync for bitcoin_units::amount::Denomination +impl core::marker::Sync for bitcoin_units::amount::Display +impl core::marker::Sync for bitcoin_units::amount::InputTooLargeError +impl core::marker::Sync for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Sync for bitcoin_units::amount::MissingDenominationError +impl core::marker::Sync for bitcoin_units::amount::MissingDigitsError +impl core::marker::Sync for bitcoin_units::amount::OutOfRangeError +impl core::marker::Sync for bitcoin_units::amount::ParseAmountError +impl core::marker::Sync for bitcoin_units::amount::ParseDenominationError +impl core::marker::Sync for bitcoin_units::amount::ParseError +impl core::marker::Sync for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Sync for bitcoin_units::amount::TooPreciseError +impl core::marker::Sync for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Sync for bitcoin_units::block::BlockHeight +impl core::marker::Sync for bitcoin_units::block::BlockHeightInterval +impl core::marker::Sync for bitcoin_units::block::BlockMtp +impl core::marker::Sync for bitcoin_units::block::BlockMtpInterval +impl core::marker::Sync for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Sync for bitcoin_units::fee_rate::serde::OverflowError +impl core::marker::Sync for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Sync for bitcoin_units::locktime::absolute::Height +impl core::marker::Sync for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Sync for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Sync for bitcoin_units::parse::ParseIntError +impl core::marker::Sync for bitcoin_units::parse::PrefixedHexError +impl core::marker::Sync for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Unpin for bitcoin_units::Amount +impl core::marker::Unpin for bitcoin_units::BlockTime +impl core::marker::Unpin for bitcoin_units::FeeRate +impl core::marker::Unpin for bitcoin_units::MathOp +impl core::marker::Unpin for bitcoin_units::NumOpError +impl core::marker::Unpin for bitcoin_units::SignedAmount +impl core::marker::Unpin for bitcoin_units::Weight +impl core::marker::Unpin for bitcoin_units::amount::Denomination +impl core::marker::Unpin for bitcoin_units::amount::Display +impl core::marker::Unpin for bitcoin_units::amount::InputTooLargeError +impl core::marker::Unpin for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Unpin for bitcoin_units::amount::MissingDenominationError +impl core::marker::Unpin for bitcoin_units::amount::MissingDigitsError +impl core::marker::Unpin for bitcoin_units::amount::OutOfRangeError +impl core::marker::Unpin for bitcoin_units::amount::ParseAmountError +impl core::marker::Unpin for bitcoin_units::amount::ParseDenominationError +impl core::marker::Unpin for bitcoin_units::amount::ParseError +impl core::marker::Unpin for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Unpin for bitcoin_units::amount::TooPreciseError +impl core::marker::Unpin for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Unpin for bitcoin_units::block::BlockHeight +impl core::marker::Unpin for bitcoin_units::block::BlockHeightInterval +impl core::marker::Unpin for bitcoin_units::block::BlockMtp +impl core::marker::Unpin for bitcoin_units::block::BlockMtpInterval +impl core::marker::Unpin for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Unpin for bitcoin_units::fee_rate::serde::OverflowError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::Height +impl core::marker::Unpin for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Unpin for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Unpin for bitcoin_units::parse::ParseIntError +impl core::marker::Unpin for bitcoin_units::parse::PrefixedHexError +impl core::marker::Unpin for bitcoin_units::parse::UnprefixedHexError +impl core::ops::arith::Add for bitcoin_units::Amount +impl core::ops::arith::Add for bitcoin_units::FeeRate +impl core::ops::arith::Add for bitcoin_units::SignedAmount +impl core::ops::arith::Add for bitcoin_units::Weight +impl core::ops::arith::Add for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Add<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::SignedAmount +impl core::ops::arith::Add<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Add<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Add<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Add<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Add<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add for &bitcoin_units::Amount +impl core::ops::arith::Add for &bitcoin_units::FeeRate +impl core::ops::arith::Add> for &bitcoin_units::Amount +impl core::ops::arith::Add> for bitcoin_units::Amount +impl core::ops::arith::Add> for &bitcoin_units::SignedAmount +impl core::ops::arith::Add> for bitcoin_units::SignedAmount +impl core::ops::arith::Add for &bitcoin_units::SignedAmount +impl core::ops::arith::Add for &bitcoin_units::Weight +impl core::ops::arith::Add for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Add for &bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockHeight +impl core::ops::arith::Add for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Add for &bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockMtp +impl core::ops::arith::AddAssign for bitcoin_units::FeeRate +impl core::ops::arith::AddAssign for bitcoin_units::Weight +impl core::ops::arith::AddAssign for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::AddAssign for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::AddAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::AddAssign<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::SignedAmount +impl core::ops::arith::Div for bitcoin_units::Weight +impl core::ops::arith::Div<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::FeeRate> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::FeeRate> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::Amount +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::FeeRate +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::Weight +impl core::ops::arith::Div<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&u64> for bitcoin_units::Amount +impl core::ops::arith::Div<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&u64> for bitcoin_units::Weight +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::NumOpResult +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::NumOpResult +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::SignedAmount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::Weight +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::SignedAmount +impl core::ops::arith::Div> for bitcoin_units::SignedAmount +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::FeeRate +impl core::ops::arith::Div> for &bitcoin_units::Weight +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::FeeRate +impl core::ops::arith::Div> for bitcoin_units::Weight +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::SignedAmount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::SignedAmount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::Weight +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::Weight +impl core::ops::arith::DivAssign<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::Amount> for u64 +impl core::ops::arith::Mul<&bitcoin_units::FeeRate> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::FeeRate> for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for u64 +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for i64 +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::FeeRate +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::SignedAmount> for i64 +impl core::ops::arith::Mul<&bitcoin_units::Weight> for bitcoin_units::FeeRate +impl core::ops::arith::Mul<&bitcoin_units::Weight> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::Weight> for u64 +impl core::ops::arith::Mul<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Mul<&u64> for bitcoin_units::Amount +impl core::ops::arith::Mul<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&u64> for bitcoin_units::Weight +impl core::ops::arith::Mul for &u64 +impl core::ops::arith::Mul for u64 +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::Weight +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::Weight +impl core::ops::arith::Mul> for &u64 +impl core::ops::arith::Mul> for u64 +impl core::ops::arith::Mul> for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for &bitcoin_units::Weight +impl core::ops::arith::Mul> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for bitcoin_units::Weight +impl core::ops::arith::Mul> for &i64 +impl core::ops::arith::Mul> for i64 +impl core::ops::arith::Mul> for &bitcoin_units::FeeRate +impl core::ops::arith::Mul> for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for bitcoin_units::FeeRate +impl core::ops::arith::Mul> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &i64 +impl core::ops::arith::Mul for i64 +impl core::ops::arith::Mul for &bitcoin_units::FeeRate +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &u64 +impl core::ops::arith::Mul for bitcoin_units::FeeRate +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for u64 +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::SignedAmount +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::SignedAmount +impl core::ops::arith::Mul for &bitcoin_units::Amount +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::Weight +impl core::ops::arith::Mul for bitcoin_units::Amount +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::Weight +impl core::ops::arith::MulAssign<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::Weight +impl core::ops::arith::Neg for bitcoin_units::SignedAmount +impl core::ops::arith::Rem for bitcoin_units::Weight +impl core::ops::arith::Rem<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Rem<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Rem<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Rem<&u64> for bitcoin_units::Amount +impl core::ops::arith::Rem<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Rem<&u64> for bitcoin_units::Weight +impl core::ops::arith::Rem for &bitcoin_units::Weight +impl core::ops::arith::Rem for &bitcoin_units::NumOpResult +impl core::ops::arith::Rem for &bitcoin_units::SignedAmount +impl core::ops::arith::Rem for bitcoin_units::NumOpResult +impl core::ops::arith::Rem for bitcoin_units::SignedAmount +impl core::ops::arith::Rem for &bitcoin_units::Amount +impl core::ops::arith::Rem for &bitcoin_units::NumOpResult +impl core::ops::arith::Rem for &bitcoin_units::Weight +impl core::ops::arith::Rem for bitcoin_units::Amount +impl core::ops::arith::Rem for bitcoin_units::NumOpResult +impl core::ops::arith::Rem for bitcoin_units::Weight +impl core::ops::arith::RemAssign for bitcoin_units::Weight +impl core::ops::arith::Sub for bitcoin_units::Amount +impl core::ops::arith::Sub for bitcoin_units::FeeRate +impl core::ops::arith::Sub for bitcoin_units::SignedAmount +impl core::ops::arith::Sub for bitcoin_units::Weight +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Sub<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeight> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtp> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub for &bitcoin_units::Amount +impl core::ops::arith::Sub for &bitcoin_units::FeeRate +impl core::ops::arith::Sub> for &bitcoin_units::Amount +impl core::ops::arith::Sub> for bitcoin_units::Amount +impl core::ops::arith::Sub> for &bitcoin_units::SignedAmount +impl core::ops::arith::Sub> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub for &bitcoin_units::SignedAmount +impl core::ops::arith::Sub for &bitcoin_units::Weight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtp +impl core::ops::arith::SubAssign for bitcoin_units::FeeRate +impl core::ops::arith::SubAssign for bitcoin_units::Weight +impl core::ops::arith::SubAssign for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::SubAssign for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::SubAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::SubAssign<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Amount +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::BlockTime +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::FeeRate +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::MathOp +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::NumOpError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::SignedAmount +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Weight +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::Denomination +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::Display +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::InputTooLargeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::InvalidCharacterError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::MissingDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::MissingDigitsError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::OutOfRangeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseAmountError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::TooPreciseError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::UnknownDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeight +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeightInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtp +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::fee_rate::serde::OverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ConversionError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::ParseIntError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::PrefixedHexError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Amount +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::BlockTime +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::FeeRate +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::MathOp +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::NumOpError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::SignedAmount +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Weight +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::Denomination +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::Display +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::InputTooLargeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::InvalidCharacterError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::MissingDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::MissingDigitsError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::OutOfRangeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseAmountError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::TooPreciseError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::UnknownDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeight +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeightInterval +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtp +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::fee_rate::serde::OverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ConversionError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::ParseIntError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::PrefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::str::traits::FromStr for bitcoin_units::Amount +impl core::str::traits::FromStr for bitcoin_units::SignedAmount +impl core::str::traits::FromStr for bitcoin_units::Weight +impl core::str::traits::FromStr for bitcoin_units::amount::Denomination +impl core::str::traits::FromStr for bitcoin_units::block::BlockHeight +impl core::str::traits::FromStr for bitcoin_units::block::BlockHeightInterval +impl core::str::traits::FromStr for bitcoin_units::block::BlockMtp +impl core::str::traits::FromStr for bitcoin_units::block::BlockMtpInterval +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::Height +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::MedianTimePast +impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOfBlocks +impl serde::ser::Serialize for bitcoin_units::BlockTime +impl serde::ser::Serialize for bitcoin_units::Weight +impl serde::ser::Serialize for bitcoin_units::block::BlockHeight +impl serde::ser::Serialize for bitcoin_units::block::BlockHeightInterval +impl serde::ser::Serialize for bitcoin_units::block::BlockMtp +impl serde::ser::Serialize for bitcoin_units::block::BlockMtpInterval +impl<'a, T: arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for bitcoin_units::NumOpResult +impl<'a, T> core::ops::arith::Add<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl<'a, T> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl<'a, T> core::ops::arith::Sub<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl<'a, T> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::Amount +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::BlockTime +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::FeeRate +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::MathOp +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::SignedAmount +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::Weight +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::amount::Denomination +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockHeight +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockHeightInterval +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockMtp +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockMtpInterval +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::Height +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::MedianTimePast +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::relative::NumberOf512Seconds +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::relative::NumberOfBlocks +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::Weight> for bitcoin_units::Weight +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl<'a> core::ops::arith::Add<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::FeeRate> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeightInterval +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtpInterval +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::FeeRate> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::FeeRate> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Div<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Amount> for &u64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::FeeRate> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::FeeRate> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &u64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &i64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::SignedAmount> for &i64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &u64 +impl<'a> core::ops::arith::Mul<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Rem<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Rem<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Rem<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::FeeRate> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeight> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeightInterval +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtp> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtpInterval +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::BlockTime +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::Weight +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockHeight +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockHeightInterval +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockMtp +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockMtpInterval +impl core::clone::Clone for bitcoin_units::NumOpResult +impl core::cmp::Eq for bitcoin_units::NumOpResult +impl core::cmp::PartialEq for bitcoin_units::NumOpResult +impl bitcoin_units::NumOpResult +impl core::fmt::Debug for bitcoin_units::NumOpResult +impl core::marker::Copy for bitcoin_units::NumOpResult +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::NumOpResult +impl core::marker::Freeze for bitcoin_units::NumOpResult where T: core::marker::Freeze +impl core::marker::Send for bitcoin_units::NumOpResult where T: core::marker::Send +impl core::marker::StructuralPartialEq for bitcoin_units::NumOpResult +impl core::marker::Sync for bitcoin_units::NumOpResult where T: core::marker::Sync +impl core::marker::Unpin for bitcoin_units::NumOpResult where T: core::marker::Unpin +impl core::ops::arith::Add for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Add<&T> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Add for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Sub for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub<&T> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::NumOpResult where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::NumOpResult where T: core::panic::unwind_safe::UnwindSafe +pub bitcoin_units::MathOp::Add +pub bitcoin_units::MathOp::Div +pub bitcoin_units::MathOp::Mul +pub bitcoin_units::MathOp::Neg +pub bitcoin_units::MathOp::Rem +pub bitcoin_units::MathOp::Sub +pub bitcoin_units::NumOpResult::Error(bitcoin_units::NumOpError) +pub bitcoin_units::NumOpResult::Valid(T) +pub bitcoin_units::amount::Denomination::Bit +pub bitcoin_units::amount::Denomination::Bitcoin +pub bitcoin_units::amount::Denomination::CentiBitcoin +pub bitcoin_units::amount::Denomination::MicroBitcoin +pub bitcoin_units::amount::Denomination::MilliBitcoin +pub bitcoin_units::amount::Denomination::Satoshi +pub bitcoin_units::amount::ParseDenominationError::PossiblyConfusing(bitcoin_units::amount::PossiblyConfusingDenominationError) +pub bitcoin_units::amount::ParseDenominationError::Unknown(bitcoin_units::amount::UnknownDenominationError) +pub const bitcoin_units::Amount::FIFTY_BTC: Self +pub const bitcoin_units::Amount::MAX: Self +pub const bitcoin_units::Amount::MAX_MONEY: Self +pub const bitcoin_units::Amount::MIN: Self +pub const bitcoin_units::Amount::ONE_BTC: Self +pub const bitcoin_units::Amount::ONE_SAT: Self +pub const bitcoin_units::Amount::SIZE: usize +pub const bitcoin_units::Amount::ZERO: Self +pub const bitcoin_units::FeeRate::BROADCAST_MIN: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::DUST: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::MAX: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::MIN: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::ZERO: bitcoin_units::FeeRate +pub const bitcoin_units::SignedAmount::FIFTY_BTC: Self +pub const bitcoin_units::SignedAmount::MAX: Self +pub const bitcoin_units::SignedAmount::MAX_MONEY: Self +pub const bitcoin_units::SignedAmount::MIN: Self +pub const bitcoin_units::SignedAmount::ONE_BTC: Self +pub const bitcoin_units::SignedAmount::ONE_SAT: Self +pub const bitcoin_units::SignedAmount::ZERO: Self +pub const bitcoin_units::Weight::MAX: bitcoin_units::Weight +pub const bitcoin_units::Weight::MAX_BLOCK: bitcoin_units::Weight +pub const bitcoin_units::Weight::MIN: bitcoin_units::Weight +pub const bitcoin_units::Weight::MIN_TRANSACTION: bitcoin_units::Weight +pub const bitcoin_units::Weight::WITNESS_SCALE_FACTOR: u64 +pub const bitcoin_units::Weight::ZERO: bitcoin_units::Weight +pub const bitcoin_units::amount::Denomination::BTC: Self +pub const bitcoin_units::amount::Denomination::SAT: Self +pub const bitcoin_units::block::BlockHeight::MAX: Self +pub const bitcoin_units::block::BlockHeight::MIN: Self +pub const bitcoin_units::block::BlockHeight::ZERO: Self +pub const bitcoin_units::block::BlockHeightInterval::MAX: Self +pub const bitcoin_units::block::BlockHeightInterval::MIN: Self +pub const bitcoin_units::block::BlockHeightInterval::ZERO: Self +pub const bitcoin_units::block::BlockMtp::MAX: Self +pub const bitcoin_units::block::BlockMtp::MIN: Self +pub const bitcoin_units::block::BlockMtp::ZERO: Self +pub const bitcoin_units::block::BlockMtpInterval::MAX: Self +pub const bitcoin_units::block::BlockMtpInterval::MIN: Self +pub const bitcoin_units::block::BlockMtpInterval::ZERO: Self +pub const bitcoin_units::locktime::absolute::Height::MAX: Self +pub const bitcoin_units::locktime::absolute::Height::MIN: Self +pub const bitcoin_units::locktime::absolute::Height::ZERO: Self +pub const bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD: u32 +pub const bitcoin_units::locktime::absolute::MedianTimePast::MAX: Self +pub const bitcoin_units::locktime::absolute::MedianTimePast::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MAX: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::ZERO: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::MAX: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::ZERO: Self +pub const bitcoin_units::weight::WITNESS_SCALE_FACTOR: usize +pub const fn bitcoin_units::Amount::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_rem(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Amount::div_by_fee_rate_ceil(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_fee_rate_floor(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_weight_ceil(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_weight_floor(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::from_btc_u16(whole_bitcoin: u16) -> Self +pub const fn bitcoin_units::Amount::from_sat(satoshi: u64) -> core::result::Result +pub const fn bitcoin_units::Amount::from_sat_u32(satoshi: u32) -> Self +pub const fn bitcoin_units::Amount::to_sat(self) -> u64 +pub const fn bitcoin_units::BlockTime::from_u32(t: u32) -> Self +pub const fn bitcoin_units::BlockTime::to_u32(self) -> u32 +pub const fn bitcoin_units::FeeRate::checked_add(self, rhs: bitcoin_units::FeeRate) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_sub(self, rhs: bitcoin_units::FeeRate) -> core::option::Option +pub const fn bitcoin_units::FeeRate::from_per_kvb(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_per_kwu(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_per_vb(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_sat_per_kvb(sat_kvb: u32) -> Self +pub const fn bitcoin_units::FeeRate::from_sat_per_kwu(sat_kwu: u32) -> Self +pub const fn bitcoin_units::FeeRate::from_sat_per_vb(sat_vb: u32) -> Self +pub const fn bitcoin_units::FeeRate::mul_by_weight(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::to_fee(self, weight: bitcoin_units::Weight) -> bitcoin_units::Amount +pub const fn bitcoin_units::FeeRate::to_sat_per_kvb_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kvb_floor(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kwu_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kwu_floor(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_vb_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_vb_floor(self) -> u64 +pub const fn bitcoin_units::SignedAmount::abs(self) -> Self +pub const fn bitcoin_units::SignedAmount::checked_abs(self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_div(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_mul(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_rem(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::from_btc_i16(whole_bitcoin: i16) -> Self +pub const fn bitcoin_units::SignedAmount::from_sat(satoshi: i64) -> core::result::Result +pub const fn bitcoin_units::SignedAmount::from_sat_i32(satoshi: i32) -> Self +pub const fn bitcoin_units::SignedAmount::to_sat(self) -> i64 +pub const fn bitcoin_units::Weight::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Weight::from_kwu(wu: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::from_non_witness_data_size(non_witness_size: u64) -> Self +pub const fn bitcoin_units::Weight::from_vb(vb: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::from_vb_unchecked(vb: u64) -> Self +pub const fn bitcoin_units::Weight::from_vb_unwrap(vb: u64) -> bitcoin_units::Weight +pub const fn bitcoin_units::Weight::from_witness_data_size(witness_size: u64) -> Self +pub const fn bitcoin_units::Weight::from_wu(wu: u64) -> Self +pub const fn bitcoin_units::Weight::mul_by_fee_rate(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Weight::to_kwu_ceil(self) -> u64 +pub const fn bitcoin_units::Weight::to_kwu_floor(self) -> u64 +pub const fn bitcoin_units::Weight::to_vbytes_ceil(self) -> u64 +pub const fn bitcoin_units::Weight::to_vbytes_floor(self) -> u64 +pub const fn bitcoin_units::Weight::to_wu(self) -> u64 +pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockHeightInterval::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockHeightInterval::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockMtp::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockMtp::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockMtpInterval::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::Height::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::is_block_height(n: u32) -> bool +pub const fn bitcoin_units::locktime::absolute::is_block_time(n: u32) -> bool +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_512_second_intervals(intervals: u16) -> Self +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_512_second_intervals(self) -> u16 +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_consensus_u32(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_seconds(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::from_height(blocks: u16) -> Self +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_consensus_u32(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_height(self) -> u16 +pub enum bitcoin_units::NumOpResult +pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::FeeRate::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::FeeRate::sub(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::sub(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: &T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: &T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &core::num::nonzero::NonZeroI64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: core::num::nonzero::NonZeroI64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::mul(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::mul(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::rem(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::sub(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::sub(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtp) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtp) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &i64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &i64::mul(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn T::checked_sum(self) -> core::option::Option +pub fn T::checked_sum(self) -> core::option::Option +pub fn T::checked_sum(self) -> core::option::Option +pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::Amount::clone(&self) -> bitcoin_units::Amount +pub fn bitcoin_units::Amount::cmp(&self, other: &bitcoin_units::Amount) -> core::cmp::Ordering +pub fn bitcoin_units::Amount::default() -> Self +pub fn bitcoin_units::Amount::des_btc<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::Amount::des_sat<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::Amount::des_str<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::Amount::display_dynamic(self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::Amount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Amount::eq(&self, other: &bitcoin_units::Amount) -> bool +pub fn bitcoin_units::Amount::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::Amount::from_btc(btc: f64) -> core::result::Result +pub fn bitcoin_units::Amount::from_float_in(value: f64, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::Amount::from_int_btc>(whole_bitcoin: T) -> Self +pub fn bitcoin_units::Amount::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::Amount::from_str_in(s: &str, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::Amount::from_str_with_denomination(s: &str) -> core::result::Result +pub fn bitcoin_units::Amount::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::Amount::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option +pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output +pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::ser_btc(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::Amount::ser_btc_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::Amount::ser_sat(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::Amount::ser_sat_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::Amount::ser_str(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::Amount::ser_str_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::to_btc(self) -> f64 +pub fn bitcoin_units::Amount::to_float_in(self, denom: bitcoin_units::amount::Denomination) -> f64 +pub fn bitcoin_units::Amount::to_signed(self) -> bitcoin_units::SignedAmount +pub fn bitcoin_units::Amount::to_string_in(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::Amount::to_string_with_denomination(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::Amount::try_from(value: bitcoin_units::SignedAmount) -> core::result::Result +pub fn bitcoin_units::Amount::type_prefix(_: bitcoin_units::amount::serde::private::Token) -> &'static str +pub fn bitcoin_units::BlockTime::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::BlockTime::clone(&self) -> bitcoin_units::BlockTime +pub fn bitcoin_units::BlockTime::cmp(&self, other: &bitcoin_units::BlockTime) -> core::cmp::Ordering +pub fn bitcoin_units::BlockTime::deserialize(d: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::BlockTime::eq(&self, other: &bitcoin_units::BlockTime) -> bool +pub fn bitcoin_units::BlockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::BlockTime::from(t: u32) -> Self +pub fn bitcoin_units::BlockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::BlockTime::partial_cmp(&self, other: &bitcoin_units::BlockTime) -> core::option::Option +pub fn bitcoin_units::BlockTime::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::CheckedSum::checked_sum(self) -> core::option::Option +pub fn bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: &bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::FeeRate::clone(&self) -> bitcoin_units::FeeRate +pub fn bitcoin_units::FeeRate::cmp(&self, other: &bitcoin_units::FeeRate) -> core::cmp::Ordering +pub fn bitcoin_units::FeeRate::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::FeeRate::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::FeeRate::eq(&self, other: &bitcoin_units::FeeRate) -> bool +pub fn bitcoin_units::FeeRate::fee_vb(self, vb: u64) -> core::option::Option +pub fn bitcoin_units::FeeRate::fee_wu(self, weight: bitcoin_units::Weight) -> core::option::Option +pub fn bitcoin_units::FeeRate::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::FeeRate::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::FeeRate::partial_cmp(&self, other: &bitcoin_units::FeeRate) -> core::option::Option +pub fn bitcoin_units::FeeRate::sub(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::sub(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::sub_assign(&mut self, rhs: &bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::sub_assign(&mut self, rhs: bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::FeeRate::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::MathOp::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::MathOp::clone(&self) -> bitcoin_units::MathOp +pub fn bitcoin_units::MathOp::eq(&self, other: &bitcoin_units::MathOp) -> bool +pub fn bitcoin_units::MathOp::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::MathOp::is_addition(self) -> bool +pub fn bitcoin_units::MathOp::is_div_by_zero(self) -> bool +pub fn bitcoin_units::MathOp::is_multiplication(self) -> bool +pub fn bitcoin_units::MathOp::is_negation(self) -> bool +pub fn bitcoin_units::MathOp::is_overflow(self) -> bool +pub fn bitcoin_units::MathOp::is_subtraction(self) -> bool +pub fn bitcoin_units::NumOpError::clone(&self) -> bitcoin_units::NumOpError +pub fn bitcoin_units::NumOpError::eq(&self, other: &bitcoin_units::NumOpError) -> bool +pub fn bitcoin_units::NumOpError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::NumOpError::is_div_by_zero(self) -> bool +pub fn bitcoin_units::NumOpError::is_overflow(self) -> bool +pub fn bitcoin_units::NumOpError::operation(self) -> bitcoin_units::MathOp +pub fn bitcoin_units::NumOpResult::add(self, rhs: &T) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: Self) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: T) -> Self::Output +pub fn bitcoin_units::NumOpResult::and_then(self, op: F) -> bitcoin_units::NumOpResult where F: core::ops::function::FnOnce(T) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::NumOpResult::clone(&self) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::eq(&self, other: &bitcoin_units::NumOpResult) -> bool +pub fn bitcoin_units::NumOpResult::expect(self, msg: &str) -> T +pub fn bitcoin_units::NumOpResult::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::NumOpResult::into_result(self) -> core::result::Result +pub fn bitcoin_units::NumOpResult::is_error(&self) -> bool +pub fn bitcoin_units::NumOpResult::is_valid(&self) -> bool +pub fn bitcoin_units::NumOpResult::map U>(self, op: F) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::ok(self) -> core::option::Option +pub fn bitcoin_units::NumOpResult::sub(self, rhs: &T) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: Self) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: T) -> Self::Output +pub fn bitcoin_units::NumOpResult::unwrap(self) -> T +pub fn bitcoin_units::NumOpResult::unwrap_err(self) -> bitcoin_units::NumOpError +pub fn bitcoin_units::NumOpResult::unwrap_or(self, default: T) -> T +pub fn bitcoin_units::NumOpResult::unwrap_or_else(self, f: F) -> T where F: core::ops::function::FnOnce() -> T +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: &u64) +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: u64) +pub fn bitcoin_units::NumOpResult::from(a: &bitcoin_units::Amount) -> Self +pub fn bitcoin_units::NumOpResult::from(a: bitcoin_units::Amount) -> Self +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: &u64) +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: u64) +pub fn bitcoin_units::NumOpResult::rem(self, modulus: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: &i64) +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: i64) +pub fn bitcoin_units::NumOpResult::from(a: &bitcoin_units::SignedAmount) -> Self +pub fn bitcoin_units::NumOpResult::from(a: bitcoin_units::SignedAmount) -> Self +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: &i64) +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: i64) +pub fn bitcoin_units::NumOpResult::rem(self, modulus: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::rem(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::SignedAmount::clone(&self) -> bitcoin_units::SignedAmount +pub fn bitcoin_units::SignedAmount::cmp(&self, other: &bitcoin_units::SignedAmount) -> core::cmp::Ordering +pub fn bitcoin_units::SignedAmount::default() -> Self +pub fn bitcoin_units::SignedAmount::des_btc<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::SignedAmount::des_sat<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::SignedAmount::des_str<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::SignedAmount::display_dynamic(self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::SignedAmount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display +pub fn bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: &core::num::nonzero::NonZeroI64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: core::num::nonzero::NonZeroI64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::eq(&self, other: &bitcoin_units::SignedAmount) -> bool +pub fn bitcoin_units::SignedAmount::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::SignedAmount::from(value: bitcoin_units::Amount) -> Self +pub fn bitcoin_units::SignedAmount::from_btc(btc: f64) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_float_in(value: f64, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_int_btc>(whole_bitcoin: T) -> Self +pub fn bitcoin_units::SignedAmount::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_str_in(s: &str, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_str_with_denomination(s: &str) -> core::result::Result +pub fn bitcoin_units::SignedAmount::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::SignedAmount::is_negative(self) -> bool +pub fn bitcoin_units::SignedAmount::is_positive(self) -> bool +pub fn bitcoin_units::SignedAmount::mul(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::mul(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::neg(self) -> Self::Output +pub fn bitcoin_units::SignedAmount::partial_cmp(&self, other: &bitcoin_units::SignedAmount) -> core::option::Option +pub fn bitcoin_units::SignedAmount::positive_sub(self, rhs: Self) -> core::option::Option +pub fn bitcoin_units::SignedAmount::rem(self, modulus: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::ser_btc(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::SignedAmount::ser_btc_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::SignedAmount::ser_sat(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::SignedAmount::ser_sat_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::SignedAmount::ser_str(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::SignedAmount::ser_str_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::SignedAmount::signum(self) -> i64 +pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::to_btc(self) -> f64 +pub fn bitcoin_units::SignedAmount::to_float_in(self, denom: bitcoin_units::amount::Denomination) -> f64 +pub fn bitcoin_units::SignedAmount::to_string_in(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::SignedAmount::to_string_with_denomination(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::SignedAmount::to_unsigned(self) -> core::result::Result +pub fn bitcoin_units::SignedAmount::type_prefix(_: bitcoin_units::amount::serde::private::Token) -> &'static str +pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount +pub fn bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::add_assign(&mut self, rhs: &bitcoin_units::Weight) +pub fn bitcoin_units::Weight::add_assign(&mut self, rhs: bitcoin_units::Weight) +pub fn bitcoin_units::Weight::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::Weight::clone(&self) -> bitcoin_units::Weight +pub fn bitcoin_units::Weight::cmp(&self, other: &bitcoin_units::Weight) -> core::cmp::Ordering +pub fn bitcoin_units::Weight::deserialize(d: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::Weight::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::div_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::eq(&self, other: &bitcoin_units::Weight) -> bool +pub fn bitcoin_units::Weight::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::Weight::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::Weight::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::mul_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::partial_cmp(&self, other: &bitcoin_units::Weight) -> core::option::Option +pub fn bitcoin_units::Weight::rem(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::rem_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::Weight::sub(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::sub(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::sub_assign(&mut self, rhs: &bitcoin_units::Weight) +pub fn bitcoin_units::Weight::sub_assign(&mut self, rhs: bitcoin_units::Weight) +pub fn bitcoin_units::Weight::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::Weight::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::Weight::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::Weight::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::Weight::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::amount::Denomination::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::amount::Denomination::clone(&self) -> bitcoin_units::amount::Denomination +pub fn bitcoin_units::amount::Denomination::eq(&self, other: &bitcoin_units::amount::Denomination) -> bool +pub fn bitcoin_units::amount::Denomination::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::Denomination::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::amount::Denomination::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::amount::Display::clone(&self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::amount::Display::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::Display::show_denomination(self) -> Self +pub fn bitcoin_units::amount::InputTooLargeError::clone(&self) -> bitcoin_units::amount::InputTooLargeError +pub fn bitcoin_units::amount::InputTooLargeError::eq(&self, other: &bitcoin_units::amount::InputTooLargeError) -> bool +pub fn bitcoin_units::amount::InputTooLargeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::InvalidCharacterError::clone(&self) -> bitcoin_units::amount::InvalidCharacterError +pub fn bitcoin_units::amount::InvalidCharacterError::eq(&self, other: &bitcoin_units::amount::InvalidCharacterError) -> bool +pub fn bitcoin_units::amount::InvalidCharacterError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::MissingDenominationError::clone(&self) -> bitcoin_units::amount::MissingDenominationError +pub fn bitcoin_units::amount::MissingDenominationError::eq(&self, other: &bitcoin_units::amount::MissingDenominationError) -> bool +pub fn bitcoin_units::amount::MissingDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::MissingDigitsError::clone(&self) -> bitcoin_units::amount::MissingDigitsError +pub fn bitcoin_units::amount::MissingDigitsError::eq(&self, other: &bitcoin_units::amount::MissingDigitsError) -> bool +pub fn bitcoin_units::amount::MissingDigitsError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::OutOfRangeError::clone(&self) -> bitcoin_units::amount::OutOfRangeError +pub fn bitcoin_units::amount::OutOfRangeError::eq(&self, other: &bitcoin_units::amount::OutOfRangeError) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::OutOfRangeError::is_above_max(self) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::is_below_min(self) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::valid_range(self) -> (i64, u64) +pub fn bitcoin_units::amount::ParseAmountError::clone(&self) -> bitcoin_units::amount::ParseAmountError +pub fn bitcoin_units::amount::ParseAmountError::eq(&self, other: &bitcoin_units::amount::ParseAmountError) -> bool +pub fn bitcoin_units::amount::ParseAmountError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseAmountError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::InputTooLargeError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::InvalidCharacterError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::MissingDigitsError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::OutOfRangeError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::TooPreciseError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::amount::ParseDenominationError::clone(&self) -> bitcoin_units::amount::ParseDenominationError +pub fn bitcoin_units::amount::ParseDenominationError::eq(&self, other: &bitcoin_units::amount::ParseDenominationError) -> bool +pub fn bitcoin_units::amount::ParseDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseDenominationError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseDenominationError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::amount::ParseError::clone(&self) -> bitcoin_units::amount::ParseError +pub fn bitcoin_units::amount::ParseError::eq(&self, other: &bitcoin_units::amount::ParseError) -> bool +pub fn bitcoin_units::amount::ParseError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::InputTooLargeError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::InvalidCharacterError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::MissingDigitsError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::OutOfRangeError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::ParseAmountError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::ParseDenominationError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::TooPreciseError) -> Self +pub fn bitcoin_units::amount::ParseError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::clone(&self) -> bitcoin_units::amount::PossiblyConfusingDenominationError +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::eq(&self, other: &bitcoin_units::amount::PossiblyConfusingDenominationError) -> bool +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::amount::TooPreciseError::clone(&self) -> bitcoin_units::amount::TooPreciseError +pub fn bitcoin_units::amount::TooPreciseError::eq(&self, other: &bitcoin_units::amount::TooPreciseError) -> bool +pub fn bitcoin_units::amount::TooPreciseError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::UnknownDenominationError::clone(&self) -> bitcoin_units::amount::UnknownDenominationError +pub fn bitcoin_units::amount::UnknownDenominationError::eq(&self, other: &bitcoin_units::amount::UnknownDenominationError) -> bool +pub fn bitcoin_units::amount::UnknownDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::UnknownDenominationError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::amount::serde::SerdeAmount::des_btc<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::amount::serde::SerdeAmount::des_sat<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::amount::serde::SerdeAmount::des_str<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> +pub fn bitcoin_units::amount::serde::SerdeAmount::ser_btc(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::SerdeAmount::ser_sat(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::SerdeAmount::ser_str(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::ser_btc_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::ser_sat_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::ser_str_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::type_prefix(_: bitcoin_units::amount::serde::private::Token) -> &'static str +pub fn bitcoin_units::amount::serde::as_btc::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmount, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> +pub fn bitcoin_units::amount::serde::as_btc::opt::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmountForOpt, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> +pub fn bitcoin_units::amount::serde::as_btc::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::as_btc::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::as_sat::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmount, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> +pub fn bitcoin_units::amount::serde::as_sat::opt::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmountForOpt, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> +pub fn bitcoin_units::amount::serde::as_sat::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::as_sat::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::as_str::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmount, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> +pub fn bitcoin_units::amount::serde::as_str::opt::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmountForOpt, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> +pub fn bitcoin_units::amount::serde::as_str::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::as_str::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::block::BlockHeight::checked_add(self, other: bitcoin_units::block::BlockHeightInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::clone(&self) -> bitcoin_units::block::BlockHeight +pub fn bitcoin_units::block::BlockHeight::cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockHeight::deserialize(d: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::block::BlockHeight::eq(&self, other: &bitcoin_units::block::BlockHeight) -> bool +pub fn bitcoin_units::block::BlockHeight::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeight::from(h: bitcoin_units::locktime::absolute::Height) -> Self +pub fn bitcoin_units::block::BlockHeight::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockHeight::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockHeight::partial_cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeight) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeight) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::add_assign(&mut self, rhs: &bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::block::BlockHeightInterval::checked_add(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::clone(&self) -> bitcoin_units::block::BlockHeightInterval +pub fn bitcoin_units::block::BlockHeightInterval::cmp(&self, other: &bitcoin_units::block::BlockHeightInterval) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockHeightInterval::default() -> bitcoin_units::block::BlockHeightInterval +pub fn bitcoin_units::block::BlockHeightInterval::deserialize(d: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::block::BlockHeightInterval::eq(&self, other: &bitcoin_units::block::BlockHeightInterval) -> bool +pub fn bitcoin_units::block::BlockHeightInterval::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeightInterval::from(h: bitcoin_units::locktime::relative::NumberOfBlocks) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockHeightInterval::partial_cmp(&self, other: &bitcoin_units::block::BlockHeightInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::block::BlockHeightInterval::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::sub_assign(&mut self, rhs: &bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::sub_assign(&mut self, rhs: bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::sum>(iter: I) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::block::BlockMtp::checked_add(self, other: bitcoin_units::block::BlockMtpInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::clone(&self) -> bitcoin_units::block::BlockMtp +pub fn bitcoin_units::block::BlockMtp::cmp(&self, other: &bitcoin_units::block::BlockMtp) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockMtp::deserialize(d: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::block::BlockMtp::eq(&self, other: &bitcoin_units::block::BlockMtp) -> bool +pub fn bitcoin_units::block::BlockMtp::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockMtp::from(h: bitcoin_units::locktime::absolute::MedianTimePast) -> Self +pub fn bitcoin_units::block::BlockMtp::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockMtp::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockMtp::new(timestamps: [bitcoin_units::BlockTime; 11]) -> Self +pub fn bitcoin_units::block::BlockMtp::partial_cmp(&self, other: &bitcoin_units::block::BlockMtp) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtp) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtp) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::add_assign(&mut self, rhs: &bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::block::BlockMtpInterval::checked_add(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::clone(&self) -> bitcoin_units::block::BlockMtpInterval +pub fn bitcoin_units::block::BlockMtpInterval::cmp(&self, other: &bitcoin_units::block::BlockMtpInterval) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockMtpInterval::default() -> bitcoin_units::block::BlockMtpInterval +pub fn bitcoin_units::block::BlockMtpInterval::deserialize(d: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::block::BlockMtpInterval::eq(&self, other: &bitcoin_units::block::BlockMtpInterval) -> bool +pub fn bitcoin_units::block::BlockMtpInterval::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockMtpInterval::from(h: bitcoin_units::locktime::relative::NumberOf512Seconds) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockMtpInterval::partial_cmp(&self, other: &bitcoin_units::block::BlockMtpInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::block::BlockMtpInterval::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::sub_assign(&mut self, rhs: &bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::sub_assign(&mut self, rhs: bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::sum>(iter: I) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::TooBigForRelativeHeightError::clone(&self) -> bitcoin_units::block::TooBigForRelativeHeightError +pub fn bitcoin_units::block::TooBigForRelativeHeightError::eq(&self, other: &bitcoin_units::block::TooBigForRelativeHeightError) -> bool +pub fn bitcoin_units::block::TooBigForRelativeHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::fee_rate::serde::OverflowError::clone(&self) -> bitcoin_units::fee_rate::serde::OverflowError +pub fn bitcoin_units::fee_rate::serde::OverflowError::eq(&self, other: &bitcoin_units::fee_rate::serde::OverflowError) -> bool +pub fn bitcoin_units::fee_rate::serde::OverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::fee_rate::serde::OverflowError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::fee_rate::serde::as_sat_per_kwu_floor::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_kwu_floor::opt::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_kwu_floor::opt::serialize(f: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_kwu_floor::serialize(f: &bitcoin_units::FeeRate, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_ceil::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_ceil::opt::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_ceil::opt::serialize(f: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_ceil::serialize(f: &bitcoin_units::FeeRate, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::opt::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::opt::serialize(f: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::serialize(f: &bitcoin_units::FeeRate, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::ConversionError +pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool +pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ConversionError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::absolute::Height::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::absolute::Height::eq(&self, other: &bitcoin_units::locktime::absolute::Height) -> bool +pub fn bitcoin_units::locktime::absolute::Height::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::Height::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height) -> bool +pub fn bitcoin_units::locktime::absolute::Height::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::option::Option +pub fn bitcoin_units::locktime::absolute::Height::try_from(h: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::clone(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::MedianTimePast::cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::absolute::MedianTimePast::eq(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::MedianTimePast::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::MedianTimePast::is_satisfied_by(self, time: bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::option::Option +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(h: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::ParseHeightError +pub fn bitcoin_units::locktime::absolute::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ParseHeightError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::ParseTimeError +pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ParseTimeError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::relative::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::InvalidHeightError +pub fn bitcoin_units::locktime::relative::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidHeightError) -> bool +pub fn bitcoin_units::locktime::relative::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::InvalidTimeError +pub fn bitcoin_units::locktime::relative::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidTimeError) -> bool +pub fn bitcoin_units::locktime::relative::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::clone(&self) -> bitcoin_units::locktime::relative::NumberOf512Seconds +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::default() -> bitcoin_units::locktime::relative::NumberOf512Seconds +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::eq(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> bool +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::option::Option +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::clone(&self) -> bitcoin_units::locktime::relative::NumberOfBlocks +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::default() -> bitcoin_units::locktime::relative::NumberOfBlocks +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::eq(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> bool +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from(value: u16) -> Self +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::option::Option +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(h: bitcoin_units::block::BlockHeightInterval) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::relative::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::TimeOverflowError +pub fn bitcoin_units::locktime::relative::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::TimeOverflowError) -> bool +pub fn bitcoin_units::locktime::relative::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::ParseIntError::as_ref(&self) -> &core::num::error::ParseIntError +pub fn bitcoin_units::parse::ParseIntError::clone(&self) -> bitcoin_units::parse::ParseIntError +pub fn bitcoin_units::parse::ParseIntError::eq(&self, other: &bitcoin_units::parse::ParseIntError) -> bool +pub fn bitcoin_units::parse::ParseIntError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::ParseIntError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::parse::PrefixedHexError::clone(&self) -> bitcoin_units::parse::PrefixedHexError +pub fn bitcoin_units::parse::PrefixedHexError::eq(&self, other: &bitcoin_units::parse::PrefixedHexError) -> bool +pub fn bitcoin_units::parse::PrefixedHexError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::PrefixedHexError::from(e: bitcoin_units::parse::ParseIntError) -> Self +pub fn bitcoin_units::parse::PrefixedHexError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::parse::PrefixedHexError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::parse::UnprefixedHexError::clone(&self) -> bitcoin_units::parse::UnprefixedHexError +pub fn bitcoin_units::parse::UnprefixedHexError::eq(&self, other: &bitcoin_units::parse::UnprefixedHexError) -> bool +pub fn bitcoin_units::parse::UnprefixedHexError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::UnprefixedHexError::from(e: bitcoin_units::parse::ParseIntError) -> Self +pub fn bitcoin_units::parse::UnprefixedHexError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::parse::UnprefixedHexError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::parse::hex_check_unprefixed(s: &str) -> core::result::Result<&str, bitcoin_units::parse::UnprefixedHexError> +pub fn bitcoin_units::parse::hex_remove_prefix(s: &str) -> core::result::Result<&str, bitcoin_units::parse::PrefixedHexError> +pub fn bitcoin_units::parse::hex_u128(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_prefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_unchecked(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_unprefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::int_from_box(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::parse::int_from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::int_from_string(s: alloc::string::String) -> core::result::Result +pub fn core::num::error::ParseIntError::from(value: bitcoin_units::parse::ParseIntError) -> Self +pub fn i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn i64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn i64::mul(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn u32::from(height: bitcoin_units::block::BlockHeight) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockHeightInterval) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockMtp) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockMtpInterval) -> Self +pub fn u32::from(t: bitcoin_units::BlockTime) -> Self +pub fn u64::from(value: bitcoin_units::Weight) -> Self +pub fn u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn u64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub mod bitcoin_units +pub mod bitcoin_units::amount +pub mod bitcoin_units::amount::serde +pub mod bitcoin_units::amount::serde::as_btc +pub mod bitcoin_units::amount::serde::as_btc::opt +pub mod bitcoin_units::amount::serde::as_sat +pub mod bitcoin_units::amount::serde::as_sat::opt +pub mod bitcoin_units::amount::serde::as_str +pub mod bitcoin_units::amount::serde::as_str::opt +pub mod bitcoin_units::block +pub mod bitcoin_units::fee +pub mod bitcoin_units::fee_rate +pub mod bitcoin_units::fee_rate::serde +pub mod bitcoin_units::fee_rate::serde::as_sat_per_kwu_floor +pub mod bitcoin_units::fee_rate::serde::as_sat_per_kwu_floor::opt +pub mod bitcoin_units::fee_rate::serde::as_sat_per_vb_ceil +pub mod bitcoin_units::fee_rate::serde::as_sat_per_vb_ceil::opt +pub mod bitcoin_units::fee_rate::serde::as_sat_per_vb_floor +pub mod bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::opt +pub mod bitcoin_units::locktime +pub mod bitcoin_units::locktime::absolute +pub mod bitcoin_units::locktime::relative +pub mod bitcoin_units::parse +pub mod bitcoin_units::time +pub mod bitcoin_units::weight +pub struct bitcoin_units::Amount(_) +pub struct bitcoin_units::BlockHeight(_) +pub struct bitcoin_units::BlockHeightInterval(_) +pub struct bitcoin_units::BlockMtp(_) +pub struct bitcoin_units::BlockMtpInterval(_) +pub struct bitcoin_units::BlockTime(_) +pub struct bitcoin_units::FeeRate(_) +pub struct bitcoin_units::SignedAmount(_) +pub struct bitcoin_units::Weight(_) +pub struct bitcoin_units::amount::Amount(_) +pub struct bitcoin_units::amount::Display +pub struct bitcoin_units::amount::InputTooLargeError +pub struct bitcoin_units::amount::InvalidCharacterError +pub struct bitcoin_units::amount::MissingDigitsError +pub struct bitcoin_units::amount::OutOfRangeError +pub struct bitcoin_units::amount::ParseAmountError(_) +pub struct bitcoin_units::amount::ParseError(_) +pub struct bitcoin_units::amount::SignedAmount(_) +pub struct bitcoin_units::amount::TooPreciseError +pub struct bitcoin_units::block::BlockHeight(_) +pub struct bitcoin_units::block::BlockHeightInterval(_) +pub struct bitcoin_units::block::BlockMtp(_) +pub struct bitcoin_units::block::BlockMtpInterval(_) +pub struct bitcoin_units::block::TooBigForRelativeHeightError(_) +pub struct bitcoin_units::fee_rate::FeeRate(_) +pub struct bitcoin_units::locktime::absolute::Height(_) +pub struct bitcoin_units::locktime::absolute::MedianTimePast(_) +pub struct bitcoin_units::locktime::absolute::ParseHeightError(_) +pub struct bitcoin_units::locktime::absolute::ParseTimeError(_) +pub struct bitcoin_units::locktime::relative::InvalidHeightError +pub struct bitcoin_units::locktime::relative::InvalidTimeError +pub struct bitcoin_units::locktime::relative::NumberOf512Seconds(_) +pub struct bitcoin_units::locktime::relative::NumberOfBlocks(_) +pub struct bitcoin_units::locktime::relative::TimeOverflowError +pub struct bitcoin_units::parse::PrefixedHexError(_) +pub struct bitcoin_units::parse::UnprefixedHexError(_) +pub struct bitcoin_units::time::BlockTime(_) +pub struct bitcoin_units::weight::Weight(_) +pub trait bitcoin_units::CheckedSum: bitcoin_units::sealed::Sealed +pub trait bitcoin_units::amount::serde::SerdeAmount: core::marker::Copy + core::marker::Sized +pub trait bitcoin_units::amount::serde::SerdeAmountForOpt: core::marker::Copy + core::marker::Sized + bitcoin_units::amount::serde::SerdeAmount +pub trait bitcoin_units::parse::Integer: core::str::traits::FromStr + core::convert::TryFrom + core::marker::Sized + bitcoin_units::parse::sealed::Sealed +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::FeeRate::Output = ::Output +pub type &bitcoin_units::FeeRate::Output = >>::Output +pub type &bitcoin_units::FeeRate::Output = >>::Output +pub type &bitcoin_units::FeeRate::Output = >::Output +pub type &bitcoin_units::FeeRate::Output = ::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = >>::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = >>::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::block::BlockHeight::Output = >::Output +pub type &bitcoin_units::block::BlockHeight::Output = >::Output +pub type &bitcoin_units::block::BlockHeight::Output = ::Output +pub type &bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type &bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type &bitcoin_units::block::BlockMtp::Output = >::Output +pub type &bitcoin_units::block::BlockMtp::Output = >::Output +pub type &bitcoin_units::block::BlockMtp::Output = ::Output +pub type &bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type &bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type &i64::Output = >>::Output +pub type &i64::Output = >::Output +pub type &u64::Output = >::Output +pub type &u64::Output = >>::Output +pub type &u64::Output = >::Output +pub type bitcoin_units::Amount::Err = bitcoin_units::amount::ParseError +pub type bitcoin_units::Amount::Error = bitcoin_units::amount::OutOfRangeError +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = bitcoin_units::Amount +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::FeeRate::Output = ::Output +pub type bitcoin_units::FeeRate::Output = >>::Output +pub type bitcoin_units::FeeRate::Output = >>::Output +pub type bitcoin_units::FeeRate::Output = >::Output +pub type bitcoin_units::FeeRate::Output = ::Output +pub type bitcoin_units::FeeRate::Output = bitcoin_units::FeeRate +pub type bitcoin_units::FeeRate::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Err = bitcoin_units::amount::ParseError +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::SignedAmount +pub type bitcoin_units::Weight::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::Weight::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = >>::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = >>::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Weight::Output = bitcoin_units::Weight +pub type bitcoin_units::Weight::Output = u64 +pub type bitcoin_units::amount::Denomination::Err = bitcoin_units::amount::ParseDenominationError +pub type bitcoin_units::block::BlockHeight::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeight::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeight::Output = >::Output +pub type bitcoin_units::block::BlockHeight::Output = >::Output +pub type bitcoin_units::block::BlockHeight::Output = ::Output +pub type bitcoin_units::block::BlockHeight::Output = bitcoin_units::block::BlockHeight +pub type bitcoin_units::block::BlockHeight::Output = bitcoin_units::block::BlockHeightInterval +pub type bitcoin_units::block::BlockHeightInterval::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeightInterval::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type bitcoin_units::block::BlockHeightInterval::Output = bitcoin_units::block::BlockHeightInterval +pub type bitcoin_units::block::BlockMtp::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtp::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtp::Output = >::Output +pub type bitcoin_units::block::BlockMtp::Output = >::Output +pub type bitcoin_units::block::BlockMtp::Output = ::Output +pub type bitcoin_units::block::BlockMtp::Output = bitcoin_units::block::BlockMtp +pub type bitcoin_units::block::BlockMtp::Output = bitcoin_units::block::BlockMtpInterval +pub type bitcoin_units::block::BlockMtpInterval::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtpInterval::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type bitcoin_units::block::BlockMtpInterval::Output = bitcoin_units::block::BlockMtpInterval +pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::ParseHeightError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ConversionError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ParseHeightError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ConversionError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::block::TooBigForRelativeHeightError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::parse::ParseIntError +pub type i64::Output = >>::Output +pub type i64::Output = >::Output +pub type i64::Output = bitcoin_units::NumOpResult +pub type u64::Output = >::Output +pub type u64::Output = >>::Output +pub type u64::Output = >::Output +pub type u64::Output = bitcoin_units::NumOpResult +pub type u64::Output = bitcoin_units::Weight diff --git a/api/units/alloc-only.txt b/api/units/alloc-only.txt new file mode 100644 index 0000000000..55fd6ef2b5 --- /dev/null +++ b/api/units/alloc-only.txt @@ -0,0 +1,2028 @@ +#[non_exhaustive] pub enum bitcoin_units::MathOp +#[non_exhaustive] pub enum bitcoin_units::amount::Denomination +#[non_exhaustive] pub enum bitcoin_units::amount::ParseDenominationError +#[non_exhaustive] pub struct bitcoin_units::NumOpError(_) +#[non_exhaustive] pub struct bitcoin_units::amount::MissingDenominationError +#[non_exhaustive] pub struct bitcoin_units::amount::PossiblyConfusingDenominationError(_) +#[non_exhaustive] pub struct bitcoin_units::amount::UnknownDenominationError(_) +#[non_exhaustive] pub struct bitcoin_units::locktime::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::parse::ParseIntError +impl bitcoin_units::Amount +impl bitcoin_units::BlockTime +impl bitcoin_units::FeeRate +impl bitcoin_units::MathOp +impl bitcoin_units::NumOpError +impl bitcoin_units::SignedAmount +impl bitcoin_units::Weight +impl bitcoin_units::amount::Denomination +impl bitcoin_units::amount::Display +impl bitcoin_units::amount::OutOfRangeError +impl bitcoin_units::block::BlockHeight +impl bitcoin_units::block::BlockHeightInterval +impl bitcoin_units::block::BlockMtp +impl bitcoin_units::block::BlockMtpInterval +impl bitcoin_units::locktime::absolute::Height +impl bitcoin_units::locktime::absolute::MedianTimePast +impl bitcoin_units::locktime::relative::NumberOf512Seconds +impl bitcoin_units::locktime::relative::NumberOfBlocks +impl bitcoin_units::parse::Integer for i128 +impl bitcoin_units::parse::Integer for i16 +impl bitcoin_units::parse::Integer for i32 +impl bitcoin_units::parse::Integer for i64 +impl bitcoin_units::parse::Integer for i8 +impl bitcoin_units::parse::Integer for u128 +impl bitcoin_units::parse::Integer for u16 +impl bitcoin_units::parse::Integer for u32 +impl bitcoin_units::parse::Integer for u64 +impl bitcoin_units::parse::Integer for u8 +impl core::clone::Clone for bitcoin_units::Amount +impl core::clone::Clone for bitcoin_units::BlockTime +impl core::clone::Clone for bitcoin_units::FeeRate +impl core::clone::Clone for bitcoin_units::MathOp +impl core::clone::Clone for bitcoin_units::NumOpError +impl core::clone::Clone for bitcoin_units::SignedAmount +impl core::clone::Clone for bitcoin_units::Weight +impl core::clone::Clone for bitcoin_units::amount::Denomination +impl core::clone::Clone for bitcoin_units::amount::Display +impl core::clone::Clone for bitcoin_units::amount::InputTooLargeError +impl core::clone::Clone for bitcoin_units::amount::InvalidCharacterError +impl core::clone::Clone for bitcoin_units::amount::MissingDenominationError +impl core::clone::Clone for bitcoin_units::amount::MissingDigitsError +impl core::clone::Clone for bitcoin_units::amount::OutOfRangeError +impl core::clone::Clone for bitcoin_units::amount::ParseAmountError +impl core::clone::Clone for bitcoin_units::amount::ParseDenominationError +impl core::clone::Clone for bitcoin_units::amount::ParseError +impl core::clone::Clone for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::clone::Clone for bitcoin_units::amount::TooPreciseError +impl core::clone::Clone for bitcoin_units::amount::UnknownDenominationError +impl core::clone::Clone for bitcoin_units::block::BlockHeight +impl core::clone::Clone for bitcoin_units::block::BlockHeightInterval +impl core::clone::Clone for bitcoin_units::block::BlockMtp +impl core::clone::Clone for bitcoin_units::block::BlockMtpInterval +impl core::clone::Clone for bitcoin_units::block::TooBigForRelativeHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::ConversionError +impl core::clone::Clone for bitcoin_units::locktime::absolute::Height +impl core::clone::Clone for bitcoin_units::locktime::absolute::MedianTimePast +impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::clone::Clone for bitcoin_units::locktime::relative::TimeOverflowError +impl core::clone::Clone for bitcoin_units::parse::ParseIntError +impl core::clone::Clone for bitcoin_units::parse::PrefixedHexError +impl core::clone::Clone for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Eq for bitcoin_units::Amount +impl core::cmp::Eq for bitcoin_units::BlockTime +impl core::cmp::Eq for bitcoin_units::FeeRate +impl core::cmp::Eq for bitcoin_units::MathOp +impl core::cmp::Eq for bitcoin_units::NumOpError +impl core::cmp::Eq for bitcoin_units::SignedAmount +impl core::cmp::Eq for bitcoin_units::Weight +impl core::cmp::Eq for bitcoin_units::amount::Denomination +impl core::cmp::Eq for bitcoin_units::amount::InputTooLargeError +impl core::cmp::Eq for bitcoin_units::amount::InvalidCharacterError +impl core::cmp::Eq for bitcoin_units::amount::MissingDenominationError +impl core::cmp::Eq for bitcoin_units::amount::MissingDigitsError +impl core::cmp::Eq for bitcoin_units::amount::OutOfRangeError +impl core::cmp::Eq for bitcoin_units::amount::ParseAmountError +impl core::cmp::Eq for bitcoin_units::amount::ParseDenominationError +impl core::cmp::Eq for bitcoin_units::amount::ParseError +impl core::cmp::Eq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::cmp::Eq for bitcoin_units::amount::TooPreciseError +impl core::cmp::Eq for bitcoin_units::amount::UnknownDenominationError +impl core::cmp::Eq for bitcoin_units::block::BlockHeight +impl core::cmp::Eq for bitcoin_units::block::BlockHeightInterval +impl core::cmp::Eq for bitcoin_units::block::BlockMtp +impl core::cmp::Eq for bitcoin_units::block::BlockMtpInterval +impl core::cmp::Eq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ConversionError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::Height +impl core::cmp::Eq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::Eq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::Eq for bitcoin_units::parse::ParseIntError +impl core::cmp::Eq for bitcoin_units::parse::PrefixedHexError +impl core::cmp::Eq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Ord for bitcoin_units::Amount +impl core::cmp::Ord for bitcoin_units::BlockTime +impl core::cmp::Ord for bitcoin_units::FeeRate +impl core::cmp::Ord for bitcoin_units::SignedAmount +impl core::cmp::Ord for bitcoin_units::Weight +impl core::cmp::Ord for bitcoin_units::block::BlockHeight +impl core::cmp::Ord for bitcoin_units::block::BlockHeightInterval +impl core::cmp::Ord for bitcoin_units::block::BlockMtp +impl core::cmp::Ord for bitcoin_units::block::BlockMtpInterval +impl core::cmp::Ord for bitcoin_units::locktime::absolute::Height +impl core::cmp::Ord for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialEq for bitcoin_units::Amount +impl core::cmp::PartialEq for bitcoin_units::BlockTime +impl core::cmp::PartialEq for bitcoin_units::FeeRate +impl core::cmp::PartialEq for bitcoin_units::MathOp +impl core::cmp::PartialEq for bitcoin_units::NumOpError +impl core::cmp::PartialEq for bitcoin_units::SignedAmount +impl core::cmp::PartialEq for bitcoin_units::Weight +impl core::cmp::PartialEq for bitcoin_units::amount::Denomination +impl core::cmp::PartialEq for bitcoin_units::amount::InputTooLargeError +impl core::cmp::PartialEq for bitcoin_units::amount::InvalidCharacterError +impl core::cmp::PartialEq for bitcoin_units::amount::MissingDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::MissingDigitsError +impl core::cmp::PartialEq for bitcoin_units::amount::OutOfRangeError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseAmountError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseError +impl core::cmp::PartialEq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::TooPreciseError +impl core::cmp::PartialEq for bitcoin_units::amount::UnknownDenominationError +impl core::cmp::PartialEq for bitcoin_units::block::BlockHeight +impl core::cmp::PartialEq for bitcoin_units::block::BlockHeightInterval +impl core::cmp::PartialEq for bitcoin_units::block::BlockMtp +impl core::cmp::PartialEq for bitcoin_units::block::BlockMtpInterval +impl core::cmp::PartialEq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ConversionError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::PartialEq for bitcoin_units::parse::ParseIntError +impl core::cmp::PartialEq for bitcoin_units::parse::PrefixedHexError +impl core::cmp::PartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::PartialOrd for bitcoin_units::Amount +impl core::cmp::PartialOrd for bitcoin_units::BlockTime +impl core::cmp::PartialOrd for bitcoin_units::FeeRate +impl core::cmp::PartialOrd for bitcoin_units::SignedAmount +impl core::cmp::PartialOrd for bitcoin_units::Weight +impl core::cmp::PartialOrd for bitcoin_units::block::BlockHeight +impl core::cmp::PartialOrd for bitcoin_units::block::BlockHeightInterval +impl core::cmp::PartialOrd for bitcoin_units::block::BlockMtp +impl core::cmp::PartialOrd for bitcoin_units::block::BlockMtpInterval +impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::AsRef for bitcoin_units::parse::ParseIntError +impl core::convert::From<&bitcoin_units::Amount> for bitcoin_units::NumOpResult +impl core::convert::From<&bitcoin_units::SignedAmount> for bitcoin_units::NumOpResult +impl core::convert::From for bitcoin_units::NumOpResult +impl core::convert::From for bitcoin_units::SignedAmount +impl core::convert::From for u32 +impl core::convert::From for bitcoin_units::NumOpResult +impl core::convert::From for u64 +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::parse::PrefixedHexError +impl core::convert::From for bitcoin_units::parse::UnprefixedHexError +impl core::convert::From for core::num::error::ParseIntError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseDenominationError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::parse::PrefixedHexError +impl core::convert::From for bitcoin_units::parse::UnprefixedHexError +impl core::convert::From for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::From for bitcoin_units::BlockTime +impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom<&str> for bitcoin_units::Weight +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom> for bitcoin_units::Weight +impl core::convert::TryFrom> for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom> for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom> for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom> for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::Weight +impl core::convert::TryFrom for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::Amount +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::default::Default for bitcoin_units::Amount +impl core::default::Default for bitcoin_units::SignedAmount +impl core::default::Default for bitcoin_units::block::BlockHeightInterval +impl core::default::Default for bitcoin_units::block::BlockMtpInterval +impl core::default::Default for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::default::Default for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Debug for bitcoin_units::Amount +impl core::fmt::Debug for bitcoin_units::BlockTime +impl core::fmt::Debug for bitcoin_units::FeeRate +impl core::fmt::Debug for bitcoin_units::MathOp +impl core::fmt::Debug for bitcoin_units::NumOpError +impl core::fmt::Debug for bitcoin_units::SignedAmount +impl core::fmt::Debug for bitcoin_units::Weight +impl core::fmt::Debug for bitcoin_units::amount::Denomination +impl core::fmt::Debug for bitcoin_units::amount::Display +impl core::fmt::Debug for bitcoin_units::amount::InputTooLargeError +impl core::fmt::Debug for bitcoin_units::amount::InvalidCharacterError +impl core::fmt::Debug for bitcoin_units::amount::MissingDenominationError +impl core::fmt::Debug for bitcoin_units::amount::MissingDigitsError +impl core::fmt::Debug for bitcoin_units::amount::OutOfRangeError +impl core::fmt::Debug for bitcoin_units::amount::ParseAmountError +impl core::fmt::Debug for bitcoin_units::amount::ParseDenominationError +impl core::fmt::Debug for bitcoin_units::amount::ParseError +impl core::fmt::Debug for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::fmt::Debug for bitcoin_units::amount::TooPreciseError +impl core::fmt::Debug for bitcoin_units::amount::UnknownDenominationError +impl core::fmt::Debug for bitcoin_units::block::BlockHeight +impl core::fmt::Debug for bitcoin_units::block::BlockHeightInterval +impl core::fmt::Debug for bitcoin_units::block::BlockMtp +impl core::fmt::Debug for bitcoin_units::block::BlockMtpInterval +impl core::fmt::Debug for bitcoin_units::block::TooBigForRelativeHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ConversionError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::Height +impl core::fmt::Debug for bitcoin_units::locktime::absolute::MedianTimePast +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Debug for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Debug for bitcoin_units::parse::ParseIntError +impl core::fmt::Debug for bitcoin_units::parse::PrefixedHexError +impl core::fmt::Debug for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Display for bitcoin_units::Amount +impl core::fmt::Display for bitcoin_units::MathOp +impl core::fmt::Display for bitcoin_units::NumOpError +impl core::fmt::Display for bitcoin_units::SignedAmount +impl core::fmt::Display for bitcoin_units::Weight +impl core::fmt::Display for bitcoin_units::amount::Denomination +impl core::fmt::Display for bitcoin_units::amount::Display +impl core::fmt::Display for bitcoin_units::amount::InputTooLargeError +impl core::fmt::Display for bitcoin_units::amount::InvalidCharacterError +impl core::fmt::Display for bitcoin_units::amount::MissingDigitsError +impl core::fmt::Display for bitcoin_units::amount::OutOfRangeError +impl core::fmt::Display for bitcoin_units::amount::ParseAmountError +impl core::fmt::Display for bitcoin_units::amount::ParseDenominationError +impl core::fmt::Display for bitcoin_units::amount::ParseError +impl core::fmt::Display for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::fmt::Display for bitcoin_units::amount::TooPreciseError +impl core::fmt::Display for bitcoin_units::amount::UnknownDenominationError +impl core::fmt::Display for bitcoin_units::block::BlockHeight +impl core::fmt::Display for bitcoin_units::block::BlockHeightInterval +impl core::fmt::Display for bitcoin_units::block::BlockMtp +impl core::fmt::Display for bitcoin_units::block::BlockMtpInterval +impl core::fmt::Display for bitcoin_units::block::TooBigForRelativeHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::ConversionError +impl core::fmt::Display for bitcoin_units::locktime::absolute::Height +impl core::fmt::Display for bitcoin_units::locktime::absolute::MedianTimePast +impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Display for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Display for bitcoin_units::parse::ParseIntError +impl core::fmt::Display for bitcoin_units::parse::PrefixedHexError +impl core::fmt::Display for bitcoin_units::parse::UnprefixedHexError +impl core::hash::Hash for bitcoin_units::Amount +impl core::hash::Hash for bitcoin_units::BlockTime +impl core::hash::Hash for bitcoin_units::FeeRate +impl core::hash::Hash for bitcoin_units::SignedAmount +impl core::hash::Hash for bitcoin_units::Weight +impl core::hash::Hash for bitcoin_units::amount::Denomination +impl core::hash::Hash for bitcoin_units::block::BlockHeight +impl core::hash::Hash for bitcoin_units::block::BlockHeightInterval +impl core::hash::Hash for bitcoin_units::block::BlockMtp +impl core::hash::Hash for bitcoin_units::block::BlockMtpInterval +impl core::hash::Hash for bitcoin_units::locktime::absolute::Height +impl core::hash::Hash for bitcoin_units::locktime::absolute::MedianTimePast +impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::iter::traits::accum::Sum for bitcoin_units::FeeRate +impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult +impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult +impl core::iter::traits::accum::Sum for bitcoin_units::Weight +impl core::iter::traits::accum::Sum for bitcoin_units::block::BlockHeightInterval +impl core::iter::traits::accum::Sum for bitcoin_units::block::BlockMtpInterval +impl core::marker::Copy for bitcoin_units::Amount +impl core::marker::Copy for bitcoin_units::BlockTime +impl core::marker::Copy for bitcoin_units::FeeRate +impl core::marker::Copy for bitcoin_units::MathOp +impl core::marker::Copy for bitcoin_units::NumOpError +impl core::marker::Copy for bitcoin_units::SignedAmount +impl core::marker::Copy for bitcoin_units::Weight +impl core::marker::Copy for bitcoin_units::amount::Denomination +impl core::marker::Copy for bitcoin_units::amount::OutOfRangeError +impl core::marker::Copy for bitcoin_units::block::BlockHeight +impl core::marker::Copy for bitcoin_units::block::BlockHeightInterval +impl core::marker::Copy for bitcoin_units::block::BlockMtp +impl core::marker::Copy for bitcoin_units::block::BlockMtpInterval +impl core::marker::Copy for bitcoin_units::locktime::absolute::Height +impl core::marker::Copy for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Freeze for bitcoin_units::Amount +impl core::marker::Freeze for bitcoin_units::BlockTime +impl core::marker::Freeze for bitcoin_units::FeeRate +impl core::marker::Freeze for bitcoin_units::MathOp +impl core::marker::Freeze for bitcoin_units::NumOpError +impl core::marker::Freeze for bitcoin_units::SignedAmount +impl core::marker::Freeze for bitcoin_units::Weight +impl core::marker::Freeze for bitcoin_units::amount::Denomination +impl core::marker::Freeze for bitcoin_units::amount::Display +impl core::marker::Freeze for bitcoin_units::amount::InputTooLargeError +impl core::marker::Freeze for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Freeze for bitcoin_units::amount::MissingDenominationError +impl core::marker::Freeze for bitcoin_units::amount::MissingDigitsError +impl core::marker::Freeze for bitcoin_units::amount::OutOfRangeError +impl core::marker::Freeze for bitcoin_units::amount::ParseAmountError +impl core::marker::Freeze for bitcoin_units::amount::ParseDenominationError +impl core::marker::Freeze for bitcoin_units::amount::ParseError +impl core::marker::Freeze for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Freeze for bitcoin_units::amount::TooPreciseError +impl core::marker::Freeze for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Freeze for bitcoin_units::block::BlockHeight +impl core::marker::Freeze for bitcoin_units::block::BlockHeightInterval +impl core::marker::Freeze for bitcoin_units::block::BlockMtp +impl core::marker::Freeze for bitcoin_units::block::BlockMtpInterval +impl core::marker::Freeze for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::Height +impl core::marker::Freeze for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Freeze for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Freeze for bitcoin_units::parse::ParseIntError +impl core::marker::Freeze for bitcoin_units::parse::PrefixedHexError +impl core::marker::Freeze for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Send for bitcoin_units::Amount +impl core::marker::Send for bitcoin_units::BlockTime +impl core::marker::Send for bitcoin_units::FeeRate +impl core::marker::Send for bitcoin_units::MathOp +impl core::marker::Send for bitcoin_units::NumOpError +impl core::marker::Send for bitcoin_units::SignedAmount +impl core::marker::Send for bitcoin_units::Weight +impl core::marker::Send for bitcoin_units::amount::Denomination +impl core::marker::Send for bitcoin_units::amount::Display +impl core::marker::Send for bitcoin_units::amount::InputTooLargeError +impl core::marker::Send for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Send for bitcoin_units::amount::MissingDenominationError +impl core::marker::Send for bitcoin_units::amount::MissingDigitsError +impl core::marker::Send for bitcoin_units::amount::OutOfRangeError +impl core::marker::Send for bitcoin_units::amount::ParseAmountError +impl core::marker::Send for bitcoin_units::amount::ParseDenominationError +impl core::marker::Send for bitcoin_units::amount::ParseError +impl core::marker::Send for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Send for bitcoin_units::amount::TooPreciseError +impl core::marker::Send for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Send for bitcoin_units::block::BlockHeight +impl core::marker::Send for bitcoin_units::block::BlockHeightInterval +impl core::marker::Send for bitcoin_units::block::BlockMtp +impl core::marker::Send for bitcoin_units::block::BlockMtpInterval +impl core::marker::Send for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Send for bitcoin_units::locktime::absolute::Height +impl core::marker::Send for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Send for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Send for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Send for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Send for bitcoin_units::parse::ParseIntError +impl core::marker::Send for bitcoin_units::parse::PrefixedHexError +impl core::marker::Send for bitcoin_units::parse::UnprefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::Amount +impl core::marker::StructuralPartialEq for bitcoin_units::BlockTime +impl core::marker::StructuralPartialEq for bitcoin_units::FeeRate +impl core::marker::StructuralPartialEq for bitcoin_units::MathOp +impl core::marker::StructuralPartialEq for bitcoin_units::NumOpError +impl core::marker::StructuralPartialEq for bitcoin_units::SignedAmount +impl core::marker::StructuralPartialEq for bitcoin_units::Weight +impl core::marker::StructuralPartialEq for bitcoin_units::amount::Denomination +impl core::marker::StructuralPartialEq for bitcoin_units::amount::InputTooLargeError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::InvalidCharacterError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::MissingDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::MissingDigitsError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::OutOfRangeError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseAmountError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::TooPreciseError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::UnknownDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeight +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeightInterval +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtp +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtpInterval +impl core::marker::StructuralPartialEq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::Height +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::ParseIntError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::PrefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Sync for bitcoin_units::Amount +impl core::marker::Sync for bitcoin_units::BlockTime +impl core::marker::Sync for bitcoin_units::FeeRate +impl core::marker::Sync for bitcoin_units::MathOp +impl core::marker::Sync for bitcoin_units::NumOpError +impl core::marker::Sync for bitcoin_units::SignedAmount +impl core::marker::Sync for bitcoin_units::Weight +impl core::marker::Sync for bitcoin_units::amount::Denomination +impl core::marker::Sync for bitcoin_units::amount::Display +impl core::marker::Sync for bitcoin_units::amount::InputTooLargeError +impl core::marker::Sync for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Sync for bitcoin_units::amount::MissingDenominationError +impl core::marker::Sync for bitcoin_units::amount::MissingDigitsError +impl core::marker::Sync for bitcoin_units::amount::OutOfRangeError +impl core::marker::Sync for bitcoin_units::amount::ParseAmountError +impl core::marker::Sync for bitcoin_units::amount::ParseDenominationError +impl core::marker::Sync for bitcoin_units::amount::ParseError +impl core::marker::Sync for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Sync for bitcoin_units::amount::TooPreciseError +impl core::marker::Sync for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Sync for bitcoin_units::block::BlockHeight +impl core::marker::Sync for bitcoin_units::block::BlockHeightInterval +impl core::marker::Sync for bitcoin_units::block::BlockMtp +impl core::marker::Sync for bitcoin_units::block::BlockMtpInterval +impl core::marker::Sync for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Sync for bitcoin_units::locktime::absolute::Height +impl core::marker::Sync for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Sync for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Sync for bitcoin_units::parse::ParseIntError +impl core::marker::Sync for bitcoin_units::parse::PrefixedHexError +impl core::marker::Sync for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Unpin for bitcoin_units::Amount +impl core::marker::Unpin for bitcoin_units::BlockTime +impl core::marker::Unpin for bitcoin_units::FeeRate +impl core::marker::Unpin for bitcoin_units::MathOp +impl core::marker::Unpin for bitcoin_units::NumOpError +impl core::marker::Unpin for bitcoin_units::SignedAmount +impl core::marker::Unpin for bitcoin_units::Weight +impl core::marker::Unpin for bitcoin_units::amount::Denomination +impl core::marker::Unpin for bitcoin_units::amount::Display +impl core::marker::Unpin for bitcoin_units::amount::InputTooLargeError +impl core::marker::Unpin for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Unpin for bitcoin_units::amount::MissingDenominationError +impl core::marker::Unpin for bitcoin_units::amount::MissingDigitsError +impl core::marker::Unpin for bitcoin_units::amount::OutOfRangeError +impl core::marker::Unpin for bitcoin_units::amount::ParseAmountError +impl core::marker::Unpin for bitcoin_units::amount::ParseDenominationError +impl core::marker::Unpin for bitcoin_units::amount::ParseError +impl core::marker::Unpin for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Unpin for bitcoin_units::amount::TooPreciseError +impl core::marker::Unpin for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Unpin for bitcoin_units::block::BlockHeight +impl core::marker::Unpin for bitcoin_units::block::BlockHeightInterval +impl core::marker::Unpin for bitcoin_units::block::BlockMtp +impl core::marker::Unpin for bitcoin_units::block::BlockMtpInterval +impl core::marker::Unpin for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::Height +impl core::marker::Unpin for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Unpin for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Unpin for bitcoin_units::parse::ParseIntError +impl core::marker::Unpin for bitcoin_units::parse::PrefixedHexError +impl core::marker::Unpin for bitcoin_units::parse::UnprefixedHexError +impl core::ops::arith::Add for bitcoin_units::Amount +impl core::ops::arith::Add for bitcoin_units::FeeRate +impl core::ops::arith::Add for bitcoin_units::SignedAmount +impl core::ops::arith::Add for bitcoin_units::Weight +impl core::ops::arith::Add for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Add<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::SignedAmount +impl core::ops::arith::Add<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Add<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Add<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Add<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Add<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add for &bitcoin_units::Amount +impl core::ops::arith::Add for &bitcoin_units::FeeRate +impl core::ops::arith::Add> for &bitcoin_units::Amount +impl core::ops::arith::Add> for bitcoin_units::Amount +impl core::ops::arith::Add> for &bitcoin_units::SignedAmount +impl core::ops::arith::Add> for bitcoin_units::SignedAmount +impl core::ops::arith::Add for &bitcoin_units::SignedAmount +impl core::ops::arith::Add for &bitcoin_units::Weight +impl core::ops::arith::Add for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Add for &bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockHeight +impl core::ops::arith::Add for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Add for &bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockMtp +impl core::ops::arith::AddAssign for bitcoin_units::FeeRate +impl core::ops::arith::AddAssign for bitcoin_units::Weight +impl core::ops::arith::AddAssign for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::AddAssign for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::AddAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::AddAssign<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::SignedAmount +impl core::ops::arith::Div for bitcoin_units::Weight +impl core::ops::arith::Div<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::FeeRate> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::FeeRate> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::Amount +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::FeeRate +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::Weight +impl core::ops::arith::Div<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&u64> for bitcoin_units::Amount +impl core::ops::arith::Div<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&u64> for bitcoin_units::Weight +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::NumOpResult +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::NumOpResult +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::SignedAmount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::Weight +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::SignedAmount +impl core::ops::arith::Div> for bitcoin_units::SignedAmount +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::FeeRate +impl core::ops::arith::Div> for &bitcoin_units::Weight +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::FeeRate +impl core::ops::arith::Div> for bitcoin_units::Weight +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::SignedAmount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::SignedAmount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::Weight +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::Weight +impl core::ops::arith::DivAssign<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::Amount> for u64 +impl core::ops::arith::Mul<&bitcoin_units::FeeRate> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::FeeRate> for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for u64 +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for i64 +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::FeeRate +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::SignedAmount> for i64 +impl core::ops::arith::Mul<&bitcoin_units::Weight> for bitcoin_units::FeeRate +impl core::ops::arith::Mul<&bitcoin_units::Weight> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::Weight> for u64 +impl core::ops::arith::Mul<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Mul<&u64> for bitcoin_units::Amount +impl core::ops::arith::Mul<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&u64> for bitcoin_units::Weight +impl core::ops::arith::Mul for &u64 +impl core::ops::arith::Mul for u64 +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::Weight +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::Weight +impl core::ops::arith::Mul> for &u64 +impl core::ops::arith::Mul> for u64 +impl core::ops::arith::Mul> for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for &bitcoin_units::Weight +impl core::ops::arith::Mul> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for bitcoin_units::Weight +impl core::ops::arith::Mul> for &i64 +impl core::ops::arith::Mul> for i64 +impl core::ops::arith::Mul> for &bitcoin_units::FeeRate +impl core::ops::arith::Mul> for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for bitcoin_units::FeeRate +impl core::ops::arith::Mul> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &i64 +impl core::ops::arith::Mul for i64 +impl core::ops::arith::Mul for &bitcoin_units::FeeRate +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &u64 +impl core::ops::arith::Mul for bitcoin_units::FeeRate +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for u64 +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::SignedAmount +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::SignedAmount +impl core::ops::arith::Mul for &bitcoin_units::Amount +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::Weight +impl core::ops::arith::Mul for bitcoin_units::Amount +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::Weight +impl core::ops::arith::MulAssign<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::Weight +impl core::ops::arith::Neg for bitcoin_units::SignedAmount +impl core::ops::arith::Rem for bitcoin_units::Weight +impl core::ops::arith::Rem<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Rem<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Rem<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Rem<&u64> for bitcoin_units::Amount +impl core::ops::arith::Rem<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Rem<&u64> for bitcoin_units::Weight +impl core::ops::arith::Rem for &bitcoin_units::Weight +impl core::ops::arith::Rem for &bitcoin_units::NumOpResult +impl core::ops::arith::Rem for &bitcoin_units::SignedAmount +impl core::ops::arith::Rem for bitcoin_units::NumOpResult +impl core::ops::arith::Rem for bitcoin_units::SignedAmount +impl core::ops::arith::Rem for &bitcoin_units::Amount +impl core::ops::arith::Rem for &bitcoin_units::NumOpResult +impl core::ops::arith::Rem for &bitcoin_units::Weight +impl core::ops::arith::Rem for bitcoin_units::Amount +impl core::ops::arith::Rem for bitcoin_units::NumOpResult +impl core::ops::arith::Rem for bitcoin_units::Weight +impl core::ops::arith::RemAssign for bitcoin_units::Weight +impl core::ops::arith::Sub for bitcoin_units::Amount +impl core::ops::arith::Sub for bitcoin_units::FeeRate +impl core::ops::arith::Sub for bitcoin_units::SignedAmount +impl core::ops::arith::Sub for bitcoin_units::Weight +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Sub<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeight> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtp> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub for &bitcoin_units::Amount +impl core::ops::arith::Sub for &bitcoin_units::FeeRate +impl core::ops::arith::Sub> for &bitcoin_units::Amount +impl core::ops::arith::Sub> for bitcoin_units::Amount +impl core::ops::arith::Sub> for &bitcoin_units::SignedAmount +impl core::ops::arith::Sub> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub for &bitcoin_units::SignedAmount +impl core::ops::arith::Sub for &bitcoin_units::Weight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtp +impl core::ops::arith::SubAssign for bitcoin_units::FeeRate +impl core::ops::arith::SubAssign for bitcoin_units::Weight +impl core::ops::arith::SubAssign for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::SubAssign for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::SubAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::SubAssign<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Amount +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::BlockTime +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::FeeRate +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::MathOp +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::NumOpError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::SignedAmount +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Weight +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::Denomination +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::Display +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::InputTooLargeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::InvalidCharacterError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::MissingDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::MissingDigitsError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::OutOfRangeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseAmountError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::TooPreciseError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::UnknownDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeight +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeightInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtp +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ConversionError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::ParseIntError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::PrefixedHexError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Amount +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::BlockTime +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::FeeRate +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::MathOp +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::NumOpError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::SignedAmount +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Weight +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::Denomination +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::Display +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::InputTooLargeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::InvalidCharacterError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::MissingDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::MissingDigitsError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::OutOfRangeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseAmountError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::TooPreciseError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::UnknownDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeight +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeightInterval +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtp +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ConversionError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::ParseIntError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::PrefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::str::traits::FromStr for bitcoin_units::Amount +impl core::str::traits::FromStr for bitcoin_units::SignedAmount +impl core::str::traits::FromStr for bitcoin_units::Weight +impl core::str::traits::FromStr for bitcoin_units::amount::Denomination +impl core::str::traits::FromStr for bitcoin_units::block::BlockHeight +impl core::str::traits::FromStr for bitcoin_units::block::BlockHeightInterval +impl core::str::traits::FromStr for bitcoin_units::block::BlockMtp +impl core::str::traits::FromStr for bitcoin_units::block::BlockMtpInterval +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::Height +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::MedianTimePast +impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOfBlocks +impl<'a, T> core::ops::arith::Add<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl<'a, T> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl<'a, T> core::ops::arith::Sub<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl<'a, T> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::Weight> for bitcoin_units::Weight +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl<'a> core::ops::arith::Add<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::FeeRate> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeightInterval +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtpInterval +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::FeeRate> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::FeeRate> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Div<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Amount> for &u64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::FeeRate> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::FeeRate> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &u64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &i64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::SignedAmount> for &i64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &u64 +impl<'a> core::ops::arith::Mul<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Rem<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Rem<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Rem<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::FeeRate> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeight> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeightInterval +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtp> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtpInterval +impl core::clone::Clone for bitcoin_units::NumOpResult +impl core::cmp::Eq for bitcoin_units::NumOpResult +impl core::cmp::PartialEq for bitcoin_units::NumOpResult +impl bitcoin_units::NumOpResult +impl core::fmt::Debug for bitcoin_units::NumOpResult +impl core::marker::Copy for bitcoin_units::NumOpResult +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::NumOpResult +impl core::marker::Freeze for bitcoin_units::NumOpResult where T: core::marker::Freeze +impl core::marker::Send for bitcoin_units::NumOpResult where T: core::marker::Send +impl core::marker::StructuralPartialEq for bitcoin_units::NumOpResult +impl core::marker::Sync for bitcoin_units::NumOpResult where T: core::marker::Sync +impl core::marker::Unpin for bitcoin_units::NumOpResult where T: core::marker::Unpin +impl core::ops::arith::Add for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Add<&T> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Add for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Sub for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub<&T> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::NumOpResult where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::NumOpResult where T: core::panic::unwind_safe::UnwindSafe +pub bitcoin_units::MathOp::Add +pub bitcoin_units::MathOp::Div +pub bitcoin_units::MathOp::Mul +pub bitcoin_units::MathOp::Neg +pub bitcoin_units::MathOp::Rem +pub bitcoin_units::MathOp::Sub +pub bitcoin_units::NumOpResult::Error(bitcoin_units::NumOpError) +pub bitcoin_units::NumOpResult::Valid(T) +pub bitcoin_units::amount::Denomination::Bit +pub bitcoin_units::amount::Denomination::Bitcoin +pub bitcoin_units::amount::Denomination::CentiBitcoin +pub bitcoin_units::amount::Denomination::MicroBitcoin +pub bitcoin_units::amount::Denomination::MilliBitcoin +pub bitcoin_units::amount::Denomination::Satoshi +pub bitcoin_units::amount::ParseDenominationError::PossiblyConfusing(bitcoin_units::amount::PossiblyConfusingDenominationError) +pub bitcoin_units::amount::ParseDenominationError::Unknown(bitcoin_units::amount::UnknownDenominationError) +pub const bitcoin_units::Amount::FIFTY_BTC: Self +pub const bitcoin_units::Amount::MAX: Self +pub const bitcoin_units::Amount::MAX_MONEY: Self +pub const bitcoin_units::Amount::MIN: Self +pub const bitcoin_units::Amount::ONE_BTC: Self +pub const bitcoin_units::Amount::ONE_SAT: Self +pub const bitcoin_units::Amount::SIZE: usize +pub const bitcoin_units::Amount::ZERO: Self +pub const bitcoin_units::FeeRate::BROADCAST_MIN: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::DUST: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::MAX: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::MIN: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::ZERO: bitcoin_units::FeeRate +pub const bitcoin_units::SignedAmount::FIFTY_BTC: Self +pub const bitcoin_units::SignedAmount::MAX: Self +pub const bitcoin_units::SignedAmount::MAX_MONEY: Self +pub const bitcoin_units::SignedAmount::MIN: Self +pub const bitcoin_units::SignedAmount::ONE_BTC: Self +pub const bitcoin_units::SignedAmount::ONE_SAT: Self +pub const bitcoin_units::SignedAmount::ZERO: Self +pub const bitcoin_units::Weight::MAX: bitcoin_units::Weight +pub const bitcoin_units::Weight::MAX_BLOCK: bitcoin_units::Weight +pub const bitcoin_units::Weight::MIN: bitcoin_units::Weight +pub const bitcoin_units::Weight::MIN_TRANSACTION: bitcoin_units::Weight +pub const bitcoin_units::Weight::WITNESS_SCALE_FACTOR: u64 +pub const bitcoin_units::Weight::ZERO: bitcoin_units::Weight +pub const bitcoin_units::amount::Denomination::BTC: Self +pub const bitcoin_units::amount::Denomination::SAT: Self +pub const bitcoin_units::block::BlockHeight::MAX: Self +pub const bitcoin_units::block::BlockHeight::MIN: Self +pub const bitcoin_units::block::BlockHeight::ZERO: Self +pub const bitcoin_units::block::BlockHeightInterval::MAX: Self +pub const bitcoin_units::block::BlockHeightInterval::MIN: Self +pub const bitcoin_units::block::BlockHeightInterval::ZERO: Self +pub const bitcoin_units::block::BlockMtp::MAX: Self +pub const bitcoin_units::block::BlockMtp::MIN: Self +pub const bitcoin_units::block::BlockMtp::ZERO: Self +pub const bitcoin_units::block::BlockMtpInterval::MAX: Self +pub const bitcoin_units::block::BlockMtpInterval::MIN: Self +pub const bitcoin_units::block::BlockMtpInterval::ZERO: Self +pub const bitcoin_units::locktime::absolute::Height::MAX: Self +pub const bitcoin_units::locktime::absolute::Height::MIN: Self +pub const bitcoin_units::locktime::absolute::Height::ZERO: Self +pub const bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD: u32 +pub const bitcoin_units::locktime::absolute::MedianTimePast::MAX: Self +pub const bitcoin_units::locktime::absolute::MedianTimePast::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MAX: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::ZERO: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::MAX: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::ZERO: Self +pub const bitcoin_units::weight::WITNESS_SCALE_FACTOR: usize +pub const fn bitcoin_units::Amount::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_rem(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Amount::div_by_fee_rate_ceil(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_fee_rate_floor(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_weight_ceil(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_weight_floor(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::from_btc_u16(whole_bitcoin: u16) -> Self +pub const fn bitcoin_units::Amount::from_sat(satoshi: u64) -> core::result::Result +pub const fn bitcoin_units::Amount::from_sat_u32(satoshi: u32) -> Self +pub const fn bitcoin_units::Amount::to_sat(self) -> u64 +pub const fn bitcoin_units::BlockTime::from_u32(t: u32) -> Self +pub const fn bitcoin_units::BlockTime::to_u32(self) -> u32 +pub const fn bitcoin_units::FeeRate::checked_add(self, rhs: bitcoin_units::FeeRate) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_sub(self, rhs: bitcoin_units::FeeRate) -> core::option::Option +pub const fn bitcoin_units::FeeRate::from_per_kvb(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_per_kwu(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_per_vb(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_sat_per_kvb(sat_kvb: u32) -> Self +pub const fn bitcoin_units::FeeRate::from_sat_per_kwu(sat_kwu: u32) -> Self +pub const fn bitcoin_units::FeeRate::from_sat_per_vb(sat_vb: u32) -> Self +pub const fn bitcoin_units::FeeRate::mul_by_weight(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::to_fee(self, weight: bitcoin_units::Weight) -> bitcoin_units::Amount +pub const fn bitcoin_units::FeeRate::to_sat_per_kvb_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kvb_floor(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kwu_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kwu_floor(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_vb_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_vb_floor(self) -> u64 +pub const fn bitcoin_units::SignedAmount::abs(self) -> Self +pub const fn bitcoin_units::SignedAmount::checked_abs(self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_div(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_mul(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_rem(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::from_btc_i16(whole_bitcoin: i16) -> Self +pub const fn bitcoin_units::SignedAmount::from_sat(satoshi: i64) -> core::result::Result +pub const fn bitcoin_units::SignedAmount::from_sat_i32(satoshi: i32) -> Self +pub const fn bitcoin_units::SignedAmount::to_sat(self) -> i64 +pub const fn bitcoin_units::Weight::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Weight::from_kwu(wu: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::from_non_witness_data_size(non_witness_size: u64) -> Self +pub const fn bitcoin_units::Weight::from_vb(vb: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::from_vb_unchecked(vb: u64) -> Self +pub const fn bitcoin_units::Weight::from_vb_unwrap(vb: u64) -> bitcoin_units::Weight +pub const fn bitcoin_units::Weight::from_witness_data_size(witness_size: u64) -> Self +pub const fn bitcoin_units::Weight::from_wu(wu: u64) -> Self +pub const fn bitcoin_units::Weight::mul_by_fee_rate(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Weight::to_kwu_ceil(self) -> u64 +pub const fn bitcoin_units::Weight::to_kwu_floor(self) -> u64 +pub const fn bitcoin_units::Weight::to_vbytes_ceil(self) -> u64 +pub const fn bitcoin_units::Weight::to_vbytes_floor(self) -> u64 +pub const fn bitcoin_units::Weight::to_wu(self) -> u64 +pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockHeightInterval::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockHeightInterval::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockMtp::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockMtp::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockMtpInterval::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::Height::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::is_block_height(n: u32) -> bool +pub const fn bitcoin_units::locktime::absolute::is_block_time(n: u32) -> bool +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_512_second_intervals(intervals: u16) -> Self +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_512_second_intervals(self) -> u16 +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_consensus_u32(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_seconds(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::from_height(blocks: u16) -> Self +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_consensus_u32(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_height(self) -> u16 +pub enum bitcoin_units::NumOpResult +pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::FeeRate::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::FeeRate::sub(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::sub(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: &T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: &T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &core::num::nonzero::NonZeroI64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: core::num::nonzero::NonZeroI64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::mul(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::mul(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::rem(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::sub(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::sub(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtp) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtp) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &i64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &i64::mul(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn T::checked_sum(self) -> core::option::Option +pub fn T::checked_sum(self) -> core::option::Option +pub fn T::checked_sum(self) -> core::option::Option +pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::clone(&self) -> bitcoin_units::Amount +pub fn bitcoin_units::Amount::cmp(&self, other: &bitcoin_units::Amount) -> core::cmp::Ordering +pub fn bitcoin_units::Amount::default() -> Self +pub fn bitcoin_units::Amount::display_dynamic(self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::Amount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Amount::eq(&self, other: &bitcoin_units::Amount) -> bool +pub fn bitcoin_units::Amount::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::Amount::from_btc(btc: f64) -> core::result::Result +pub fn bitcoin_units::Amount::from_float_in(value: f64, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::Amount::from_int_btc>(whole_bitcoin: T) -> Self +pub fn bitcoin_units::Amount::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::Amount::from_str_in(s: &str, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::Amount::from_str_with_denomination(s: &str) -> core::result::Result +pub fn bitcoin_units::Amount::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::Amount::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option +pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output +pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::to_btc(self) -> f64 +pub fn bitcoin_units::Amount::to_float_in(self, denom: bitcoin_units::amount::Denomination) -> f64 +pub fn bitcoin_units::Amount::to_signed(self) -> bitcoin_units::SignedAmount +pub fn bitcoin_units::Amount::to_string_in(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::Amount::to_string_with_denomination(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::Amount::try_from(value: bitcoin_units::SignedAmount) -> core::result::Result +pub fn bitcoin_units::BlockTime::clone(&self) -> bitcoin_units::BlockTime +pub fn bitcoin_units::BlockTime::cmp(&self, other: &bitcoin_units::BlockTime) -> core::cmp::Ordering +pub fn bitcoin_units::BlockTime::eq(&self, other: &bitcoin_units::BlockTime) -> bool +pub fn bitcoin_units::BlockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::BlockTime::from(t: u32) -> Self +pub fn bitcoin_units::BlockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::BlockTime::partial_cmp(&self, other: &bitcoin_units::BlockTime) -> core::option::Option +pub fn bitcoin_units::CheckedSum::checked_sum(self) -> core::option::Option +pub fn bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: &bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::clone(&self) -> bitcoin_units::FeeRate +pub fn bitcoin_units::FeeRate::cmp(&self, other: &bitcoin_units::FeeRate) -> core::cmp::Ordering +pub fn bitcoin_units::FeeRate::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::FeeRate::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::FeeRate::eq(&self, other: &bitcoin_units::FeeRate) -> bool +pub fn bitcoin_units::FeeRate::fee_vb(self, vb: u64) -> core::option::Option +pub fn bitcoin_units::FeeRate::fee_wu(self, weight: bitcoin_units::Weight) -> core::option::Option +pub fn bitcoin_units::FeeRate::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::FeeRate::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::FeeRate::partial_cmp(&self, other: &bitcoin_units::FeeRate) -> core::option::Option +pub fn bitcoin_units::FeeRate::sub(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::sub(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::sub_assign(&mut self, rhs: &bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::sub_assign(&mut self, rhs: bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::FeeRate::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::MathOp::clone(&self) -> bitcoin_units::MathOp +pub fn bitcoin_units::MathOp::eq(&self, other: &bitcoin_units::MathOp) -> bool +pub fn bitcoin_units::MathOp::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::MathOp::is_addition(self) -> bool +pub fn bitcoin_units::MathOp::is_div_by_zero(self) -> bool +pub fn bitcoin_units::MathOp::is_multiplication(self) -> bool +pub fn bitcoin_units::MathOp::is_negation(self) -> bool +pub fn bitcoin_units::MathOp::is_overflow(self) -> bool +pub fn bitcoin_units::MathOp::is_subtraction(self) -> bool +pub fn bitcoin_units::NumOpError::clone(&self) -> bitcoin_units::NumOpError +pub fn bitcoin_units::NumOpError::eq(&self, other: &bitcoin_units::NumOpError) -> bool +pub fn bitcoin_units::NumOpError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::NumOpError::is_div_by_zero(self) -> bool +pub fn bitcoin_units::NumOpError::is_overflow(self) -> bool +pub fn bitcoin_units::NumOpError::operation(self) -> bitcoin_units::MathOp +pub fn bitcoin_units::NumOpResult::add(self, rhs: &T) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: Self) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: T) -> Self::Output +pub fn bitcoin_units::NumOpResult::and_then(self, op: F) -> bitcoin_units::NumOpResult where F: core::ops::function::FnOnce(T) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::clone(&self) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::eq(&self, other: &bitcoin_units::NumOpResult) -> bool +pub fn bitcoin_units::NumOpResult::expect(self, msg: &str) -> T +pub fn bitcoin_units::NumOpResult::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::NumOpResult::into_result(self) -> core::result::Result +pub fn bitcoin_units::NumOpResult::is_error(&self) -> bool +pub fn bitcoin_units::NumOpResult::is_valid(&self) -> bool +pub fn bitcoin_units::NumOpResult::map U>(self, op: F) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::ok(self) -> core::option::Option +pub fn bitcoin_units::NumOpResult::sub(self, rhs: &T) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: Self) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: T) -> Self::Output +pub fn bitcoin_units::NumOpResult::unwrap(self) -> T +pub fn bitcoin_units::NumOpResult::unwrap_err(self) -> bitcoin_units::NumOpError +pub fn bitcoin_units::NumOpResult::unwrap_or(self, default: T) -> T +pub fn bitcoin_units::NumOpResult::unwrap_or_else(self, f: F) -> T where F: core::ops::function::FnOnce() -> T +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: &u64) +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: u64) +pub fn bitcoin_units::NumOpResult::from(a: &bitcoin_units::Amount) -> Self +pub fn bitcoin_units::NumOpResult::from(a: bitcoin_units::Amount) -> Self +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: &u64) +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: u64) +pub fn bitcoin_units::NumOpResult::rem(self, modulus: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: &i64) +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: i64) +pub fn bitcoin_units::NumOpResult::from(a: &bitcoin_units::SignedAmount) -> Self +pub fn bitcoin_units::NumOpResult::from(a: bitcoin_units::SignedAmount) -> Self +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: &i64) +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: i64) +pub fn bitcoin_units::NumOpResult::rem(self, modulus: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::rem(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::clone(&self) -> bitcoin_units::SignedAmount +pub fn bitcoin_units::SignedAmount::cmp(&self, other: &bitcoin_units::SignedAmount) -> core::cmp::Ordering +pub fn bitcoin_units::SignedAmount::default() -> Self +pub fn bitcoin_units::SignedAmount::display_dynamic(self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::SignedAmount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display +pub fn bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: &core::num::nonzero::NonZeroI64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: core::num::nonzero::NonZeroI64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::eq(&self, other: &bitcoin_units::SignedAmount) -> bool +pub fn bitcoin_units::SignedAmount::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::SignedAmount::from(value: bitcoin_units::Amount) -> Self +pub fn bitcoin_units::SignedAmount::from_btc(btc: f64) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_float_in(value: f64, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_int_btc>(whole_bitcoin: T) -> Self +pub fn bitcoin_units::SignedAmount::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_str_in(s: &str, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_str_with_denomination(s: &str) -> core::result::Result +pub fn bitcoin_units::SignedAmount::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::SignedAmount::is_negative(self) -> bool +pub fn bitcoin_units::SignedAmount::is_positive(self) -> bool +pub fn bitcoin_units::SignedAmount::mul(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::mul(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::neg(self) -> Self::Output +pub fn bitcoin_units::SignedAmount::partial_cmp(&self, other: &bitcoin_units::SignedAmount) -> core::option::Option +pub fn bitcoin_units::SignedAmount::positive_sub(self, rhs: Self) -> core::option::Option +pub fn bitcoin_units::SignedAmount::rem(self, modulus: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::signum(self) -> i64 +pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::to_btc(self) -> f64 +pub fn bitcoin_units::SignedAmount::to_float_in(self, denom: bitcoin_units::amount::Denomination) -> f64 +pub fn bitcoin_units::SignedAmount::to_string_in(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::SignedAmount::to_string_with_denomination(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String +pub fn bitcoin_units::SignedAmount::to_unsigned(self) -> core::result::Result +pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount +pub fn bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::add_assign(&mut self, rhs: &bitcoin_units::Weight) +pub fn bitcoin_units::Weight::add_assign(&mut self, rhs: bitcoin_units::Weight) +pub fn bitcoin_units::Weight::clone(&self) -> bitcoin_units::Weight +pub fn bitcoin_units::Weight::cmp(&self, other: &bitcoin_units::Weight) -> core::cmp::Ordering +pub fn bitcoin_units::Weight::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::div_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::eq(&self, other: &bitcoin_units::Weight) -> bool +pub fn bitcoin_units::Weight::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::Weight::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::Weight::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::mul_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::partial_cmp(&self, other: &bitcoin_units::Weight) -> core::option::Option +pub fn bitcoin_units::Weight::rem(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::rem_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::sub(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::sub(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::sub_assign(&mut self, rhs: &bitcoin_units::Weight) +pub fn bitcoin_units::Weight::sub_assign(&mut self, rhs: bitcoin_units::Weight) +pub fn bitcoin_units::Weight::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::Weight::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::Weight::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::Weight::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::Weight::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::amount::Denomination::clone(&self) -> bitcoin_units::amount::Denomination +pub fn bitcoin_units::amount::Denomination::eq(&self, other: &bitcoin_units::amount::Denomination) -> bool +pub fn bitcoin_units::amount::Denomination::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::Denomination::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::amount::Denomination::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::amount::Display::clone(&self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::amount::Display::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::Display::show_denomination(self) -> Self +pub fn bitcoin_units::amount::InputTooLargeError::clone(&self) -> bitcoin_units::amount::InputTooLargeError +pub fn bitcoin_units::amount::InputTooLargeError::eq(&self, other: &bitcoin_units::amount::InputTooLargeError) -> bool +pub fn bitcoin_units::amount::InputTooLargeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::InvalidCharacterError::clone(&self) -> bitcoin_units::amount::InvalidCharacterError +pub fn bitcoin_units::amount::InvalidCharacterError::eq(&self, other: &bitcoin_units::amount::InvalidCharacterError) -> bool +pub fn bitcoin_units::amount::InvalidCharacterError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::MissingDenominationError::clone(&self) -> bitcoin_units::amount::MissingDenominationError +pub fn bitcoin_units::amount::MissingDenominationError::eq(&self, other: &bitcoin_units::amount::MissingDenominationError) -> bool +pub fn bitcoin_units::amount::MissingDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::MissingDigitsError::clone(&self) -> bitcoin_units::amount::MissingDigitsError +pub fn bitcoin_units::amount::MissingDigitsError::eq(&self, other: &bitcoin_units::amount::MissingDigitsError) -> bool +pub fn bitcoin_units::amount::MissingDigitsError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::OutOfRangeError::clone(&self) -> bitcoin_units::amount::OutOfRangeError +pub fn bitcoin_units::amount::OutOfRangeError::eq(&self, other: &bitcoin_units::amount::OutOfRangeError) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::OutOfRangeError::is_above_max(self) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::is_below_min(self) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::valid_range(self) -> (i64, u64) +pub fn bitcoin_units::amount::ParseAmountError::clone(&self) -> bitcoin_units::amount::ParseAmountError +pub fn bitcoin_units::amount::ParseAmountError::eq(&self, other: &bitcoin_units::amount::ParseAmountError) -> bool +pub fn bitcoin_units::amount::ParseAmountError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseAmountError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::InputTooLargeError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::InvalidCharacterError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::MissingDigitsError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::OutOfRangeError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::TooPreciseError) -> Self +pub fn bitcoin_units::amount::ParseDenominationError::clone(&self) -> bitcoin_units::amount::ParseDenominationError +pub fn bitcoin_units::amount::ParseDenominationError::eq(&self, other: &bitcoin_units::amount::ParseDenominationError) -> bool +pub fn bitcoin_units::amount::ParseDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseDenominationError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseError::clone(&self) -> bitcoin_units::amount::ParseError +pub fn bitcoin_units::amount::ParseError::eq(&self, other: &bitcoin_units::amount::ParseError) -> bool +pub fn bitcoin_units::amount::ParseError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::InputTooLargeError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::InvalidCharacterError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::MissingDigitsError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::OutOfRangeError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::ParseAmountError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::ParseDenominationError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::TooPreciseError) -> Self +pub fn bitcoin_units::amount::ParseError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::clone(&self) -> bitcoin_units::amount::PossiblyConfusingDenominationError +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::eq(&self, other: &bitcoin_units::amount::PossiblyConfusingDenominationError) -> bool +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::TooPreciseError::clone(&self) -> bitcoin_units::amount::TooPreciseError +pub fn bitcoin_units::amount::TooPreciseError::eq(&self, other: &bitcoin_units::amount::TooPreciseError) -> bool +pub fn bitcoin_units::amount::TooPreciseError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::UnknownDenominationError::clone(&self) -> bitcoin_units::amount::UnknownDenominationError +pub fn bitcoin_units::amount::UnknownDenominationError::eq(&self, other: &bitcoin_units::amount::UnknownDenominationError) -> bool +pub fn bitcoin_units::amount::UnknownDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::checked_add(self, other: bitcoin_units::block::BlockHeightInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::clone(&self) -> bitcoin_units::block::BlockHeight +pub fn bitcoin_units::block::BlockHeight::cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockHeight::eq(&self, other: &bitcoin_units::block::BlockHeight) -> bool +pub fn bitcoin_units::block::BlockHeight::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeight::from(h: bitcoin_units::locktime::absolute::Height) -> Self +pub fn bitcoin_units::block::BlockHeight::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockHeight::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockHeight::partial_cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeight) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeight) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::add_assign(&mut self, rhs: &bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::checked_add(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::clone(&self) -> bitcoin_units::block::BlockHeightInterval +pub fn bitcoin_units::block::BlockHeightInterval::cmp(&self, other: &bitcoin_units::block::BlockHeightInterval) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockHeightInterval::default() -> bitcoin_units::block::BlockHeightInterval +pub fn bitcoin_units::block::BlockHeightInterval::eq(&self, other: &bitcoin_units::block::BlockHeightInterval) -> bool +pub fn bitcoin_units::block::BlockHeightInterval::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeightInterval::from(h: bitcoin_units::locktime::relative::NumberOfBlocks) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockHeightInterval::partial_cmp(&self, other: &bitcoin_units::block::BlockHeightInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::sub_assign(&mut self, rhs: &bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::sub_assign(&mut self, rhs: bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::sum>(iter: I) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::checked_add(self, other: bitcoin_units::block::BlockMtpInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::clone(&self) -> bitcoin_units::block::BlockMtp +pub fn bitcoin_units::block::BlockMtp::cmp(&self, other: &bitcoin_units::block::BlockMtp) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockMtp::eq(&self, other: &bitcoin_units::block::BlockMtp) -> bool +pub fn bitcoin_units::block::BlockMtp::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockMtp::from(h: bitcoin_units::locktime::absolute::MedianTimePast) -> Self +pub fn bitcoin_units::block::BlockMtp::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockMtp::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockMtp::new(timestamps: [bitcoin_units::BlockTime; 11]) -> Self +pub fn bitcoin_units::block::BlockMtp::partial_cmp(&self, other: &bitcoin_units::block::BlockMtp) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtp) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtp) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::add_assign(&mut self, rhs: &bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::checked_add(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::clone(&self) -> bitcoin_units::block::BlockMtpInterval +pub fn bitcoin_units::block::BlockMtpInterval::cmp(&self, other: &bitcoin_units::block::BlockMtpInterval) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockMtpInterval::default() -> bitcoin_units::block::BlockMtpInterval +pub fn bitcoin_units::block::BlockMtpInterval::eq(&self, other: &bitcoin_units::block::BlockMtpInterval) -> bool +pub fn bitcoin_units::block::BlockMtpInterval::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockMtpInterval::from(h: bitcoin_units::locktime::relative::NumberOf512Seconds) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockMtpInterval::partial_cmp(&self, other: &bitcoin_units::block::BlockMtpInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::sub_assign(&mut self, rhs: &bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::sub_assign(&mut self, rhs: bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::sum>(iter: I) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::block::TooBigForRelativeHeightError::clone(&self) -> bitcoin_units::block::TooBigForRelativeHeightError +pub fn bitcoin_units::block::TooBigForRelativeHeightError::eq(&self, other: &bitcoin_units::block::TooBigForRelativeHeightError) -> bool +pub fn bitcoin_units::block::TooBigForRelativeHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::ConversionError +pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool +pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::absolute::Height::eq(&self, other: &bitcoin_units::locktime::absolute::Height) -> bool +pub fn bitcoin_units::locktime::absolute::Height::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::Height::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height) -> bool +pub fn bitcoin_units::locktime::absolute::Height::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::option::Option +pub fn bitcoin_units::locktime::absolute::Height::try_from(h: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::clone(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::MedianTimePast::cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::absolute::MedianTimePast::eq(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::MedianTimePast::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::MedianTimePast::is_satisfied_by(self, time: bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::option::Option +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(h: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::ParseHeightError +pub fn bitcoin_units::locktime::absolute::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::ParseTimeError +pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::InvalidHeightError +pub fn bitcoin_units::locktime::relative::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidHeightError) -> bool +pub fn bitcoin_units::locktime::relative::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::InvalidTimeError +pub fn bitcoin_units::locktime::relative::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidTimeError) -> bool +pub fn bitcoin_units::locktime::relative::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::clone(&self) -> bitcoin_units::locktime::relative::NumberOf512Seconds +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::default() -> bitcoin_units::locktime::relative::NumberOf512Seconds +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::eq(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> bool +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::option::Option +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::clone(&self) -> bitcoin_units::locktime::relative::NumberOfBlocks +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::default() -> bitcoin_units::locktime::relative::NumberOfBlocks +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::eq(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> bool +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from(value: u16) -> Self +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::option::Option +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(h: bitcoin_units::block::BlockHeightInterval) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::relative::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::TimeOverflowError +pub fn bitcoin_units::locktime::relative::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::TimeOverflowError) -> bool +pub fn bitcoin_units::locktime::relative::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::ParseIntError::as_ref(&self) -> &core::num::error::ParseIntError +pub fn bitcoin_units::parse::ParseIntError::clone(&self) -> bitcoin_units::parse::ParseIntError +pub fn bitcoin_units::parse::ParseIntError::eq(&self, other: &bitcoin_units::parse::ParseIntError) -> bool +pub fn bitcoin_units::parse::ParseIntError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::PrefixedHexError::clone(&self) -> bitcoin_units::parse::PrefixedHexError +pub fn bitcoin_units::parse::PrefixedHexError::eq(&self, other: &bitcoin_units::parse::PrefixedHexError) -> bool +pub fn bitcoin_units::parse::PrefixedHexError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::PrefixedHexError::from(e: bitcoin_units::parse::ParseIntError) -> Self +pub fn bitcoin_units::parse::PrefixedHexError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::parse::UnprefixedHexError::clone(&self) -> bitcoin_units::parse::UnprefixedHexError +pub fn bitcoin_units::parse::UnprefixedHexError::eq(&self, other: &bitcoin_units::parse::UnprefixedHexError) -> bool +pub fn bitcoin_units::parse::UnprefixedHexError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::UnprefixedHexError::from(e: bitcoin_units::parse::ParseIntError) -> Self +pub fn bitcoin_units::parse::UnprefixedHexError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::parse::hex_check_unprefixed(s: &str) -> core::result::Result<&str, bitcoin_units::parse::UnprefixedHexError> +pub fn bitcoin_units::parse::hex_remove_prefix(s: &str) -> core::result::Result<&str, bitcoin_units::parse::PrefixedHexError> +pub fn bitcoin_units::parse::hex_u128(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_prefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_unchecked(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_unprefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::int_from_box(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::parse::int_from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::int_from_string(s: alloc::string::String) -> core::result::Result +pub fn core::num::error::ParseIntError::from(value: bitcoin_units::parse::ParseIntError) -> Self +pub fn i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn i64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn i64::mul(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn u32::from(height: bitcoin_units::block::BlockHeight) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockHeightInterval) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockMtp) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockMtpInterval) -> Self +pub fn u32::from(t: bitcoin_units::BlockTime) -> Self +pub fn u64::from(value: bitcoin_units::Weight) -> Self +pub fn u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn u64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub mod bitcoin_units +pub mod bitcoin_units::amount +pub mod bitcoin_units::block +pub mod bitcoin_units::fee +pub mod bitcoin_units::fee_rate +pub mod bitcoin_units::locktime +pub mod bitcoin_units::locktime::absolute +pub mod bitcoin_units::locktime::relative +pub mod bitcoin_units::parse +pub mod bitcoin_units::time +pub mod bitcoin_units::weight +pub struct bitcoin_units::Amount(_) +pub struct bitcoin_units::BlockHeight(_) +pub struct bitcoin_units::BlockHeightInterval(_) +pub struct bitcoin_units::BlockMtp(_) +pub struct bitcoin_units::BlockMtpInterval(_) +pub struct bitcoin_units::BlockTime(_) +pub struct bitcoin_units::FeeRate(_) +pub struct bitcoin_units::SignedAmount(_) +pub struct bitcoin_units::Weight(_) +pub struct bitcoin_units::amount::Amount(_) +pub struct bitcoin_units::amount::Display +pub struct bitcoin_units::amount::InputTooLargeError +pub struct bitcoin_units::amount::InvalidCharacterError +pub struct bitcoin_units::amount::MissingDigitsError +pub struct bitcoin_units::amount::OutOfRangeError +pub struct bitcoin_units::amount::ParseAmountError(_) +pub struct bitcoin_units::amount::ParseError(_) +pub struct bitcoin_units::amount::SignedAmount(_) +pub struct bitcoin_units::amount::TooPreciseError +pub struct bitcoin_units::block::BlockHeight(_) +pub struct bitcoin_units::block::BlockHeightInterval(_) +pub struct bitcoin_units::block::BlockMtp(_) +pub struct bitcoin_units::block::BlockMtpInterval(_) +pub struct bitcoin_units::block::TooBigForRelativeHeightError(_) +pub struct bitcoin_units::fee_rate::FeeRate(_) +pub struct bitcoin_units::locktime::absolute::Height(_) +pub struct bitcoin_units::locktime::absolute::MedianTimePast(_) +pub struct bitcoin_units::locktime::absolute::ParseHeightError(_) +pub struct bitcoin_units::locktime::absolute::ParseTimeError(_) +pub struct bitcoin_units::locktime::relative::InvalidHeightError +pub struct bitcoin_units::locktime::relative::InvalidTimeError +pub struct bitcoin_units::locktime::relative::NumberOf512Seconds(_) +pub struct bitcoin_units::locktime::relative::NumberOfBlocks(_) +pub struct bitcoin_units::locktime::relative::TimeOverflowError +pub struct bitcoin_units::parse::PrefixedHexError(_) +pub struct bitcoin_units::parse::UnprefixedHexError(_) +pub struct bitcoin_units::time::BlockTime(_) +pub struct bitcoin_units::weight::Weight(_) +pub trait bitcoin_units::CheckedSum: bitcoin_units::sealed::Sealed +pub trait bitcoin_units::parse::Integer: core::str::traits::FromStr + core::convert::TryFrom + core::marker::Sized + bitcoin_units::parse::sealed::Sealed +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::FeeRate::Output = ::Output +pub type &bitcoin_units::FeeRate::Output = >>::Output +pub type &bitcoin_units::FeeRate::Output = >>::Output +pub type &bitcoin_units::FeeRate::Output = >::Output +pub type &bitcoin_units::FeeRate::Output = ::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = >>::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = >>::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::block::BlockHeight::Output = >::Output +pub type &bitcoin_units::block::BlockHeight::Output = >::Output +pub type &bitcoin_units::block::BlockHeight::Output = ::Output +pub type &bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type &bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type &bitcoin_units::block::BlockMtp::Output = >::Output +pub type &bitcoin_units::block::BlockMtp::Output = >::Output +pub type &bitcoin_units::block::BlockMtp::Output = ::Output +pub type &bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type &bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type &i64::Output = >>::Output +pub type &i64::Output = >::Output +pub type &u64::Output = >::Output +pub type &u64::Output = >>::Output +pub type &u64::Output = >::Output +pub type bitcoin_units::Amount::Err = bitcoin_units::amount::ParseError +pub type bitcoin_units::Amount::Error = bitcoin_units::amount::OutOfRangeError +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = bitcoin_units::Amount +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::FeeRate::Output = ::Output +pub type bitcoin_units::FeeRate::Output = >>::Output +pub type bitcoin_units::FeeRate::Output = >>::Output +pub type bitcoin_units::FeeRate::Output = >::Output +pub type bitcoin_units::FeeRate::Output = ::Output +pub type bitcoin_units::FeeRate::Output = bitcoin_units::FeeRate +pub type bitcoin_units::FeeRate::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Err = bitcoin_units::amount::ParseError +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::SignedAmount +pub type bitcoin_units::Weight::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::Weight::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = >>::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = >>::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Weight::Output = bitcoin_units::Weight +pub type bitcoin_units::Weight::Output = u64 +pub type bitcoin_units::amount::Denomination::Err = bitcoin_units::amount::ParseDenominationError +pub type bitcoin_units::block::BlockHeight::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeight::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeight::Output = >::Output +pub type bitcoin_units::block::BlockHeight::Output = >::Output +pub type bitcoin_units::block::BlockHeight::Output = ::Output +pub type bitcoin_units::block::BlockHeight::Output = bitcoin_units::block::BlockHeight +pub type bitcoin_units::block::BlockHeight::Output = bitcoin_units::block::BlockHeightInterval +pub type bitcoin_units::block::BlockHeightInterval::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeightInterval::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type bitcoin_units::block::BlockHeightInterval::Output = bitcoin_units::block::BlockHeightInterval +pub type bitcoin_units::block::BlockMtp::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtp::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtp::Output = >::Output +pub type bitcoin_units::block::BlockMtp::Output = >::Output +pub type bitcoin_units::block::BlockMtp::Output = ::Output +pub type bitcoin_units::block::BlockMtp::Output = bitcoin_units::block::BlockMtp +pub type bitcoin_units::block::BlockMtp::Output = bitcoin_units::block::BlockMtpInterval +pub type bitcoin_units::block::BlockMtpInterval::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtpInterval::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type bitcoin_units::block::BlockMtpInterval::Output = bitcoin_units::block::BlockMtpInterval +pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::ParseHeightError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ConversionError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ParseHeightError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ConversionError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::block::TooBigForRelativeHeightError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::parse::ParseIntError +pub type i64::Output = >>::Output +pub type i64::Output = >::Output +pub type i64::Output = bitcoin_units::NumOpResult +pub type u64::Output = >::Output +pub type u64::Output = >>::Output +pub type u64::Output = >::Output +pub type u64::Output = bitcoin_units::NumOpResult +pub type u64::Output = bitcoin_units::Weight diff --git a/api/units/no-features.txt b/api/units/no-features.txt new file mode 100644 index 0000000000..483c305a5d --- /dev/null +++ b/api/units/no-features.txt @@ -0,0 +1,1978 @@ +#[non_exhaustive] pub enum bitcoin_units::MathOp +#[non_exhaustive] pub enum bitcoin_units::amount::Denomination +#[non_exhaustive] pub enum bitcoin_units::amount::ParseDenominationError +#[non_exhaustive] pub struct bitcoin_units::NumOpError(_) +#[non_exhaustive] pub struct bitcoin_units::amount::MissingDenominationError +#[non_exhaustive] pub struct bitcoin_units::amount::PossiblyConfusingDenominationError(_) +#[non_exhaustive] pub struct bitcoin_units::amount::UnknownDenominationError(_) +#[non_exhaustive] pub struct bitcoin_units::locktime::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::parse::ParseIntError +impl bitcoin_units::Amount +impl bitcoin_units::BlockTime +impl bitcoin_units::FeeRate +impl bitcoin_units::MathOp +impl bitcoin_units::NumOpError +impl bitcoin_units::SignedAmount +impl bitcoin_units::Weight +impl bitcoin_units::amount::Denomination +impl bitcoin_units::amount::Display +impl bitcoin_units::amount::OutOfRangeError +impl bitcoin_units::block::BlockHeight +impl bitcoin_units::block::BlockHeightInterval +impl bitcoin_units::block::BlockMtp +impl bitcoin_units::block::BlockMtpInterval +impl bitcoin_units::locktime::absolute::Height +impl bitcoin_units::locktime::absolute::MedianTimePast +impl bitcoin_units::locktime::relative::NumberOf512Seconds +impl bitcoin_units::locktime::relative::NumberOfBlocks +impl bitcoin_units::parse::Integer for i128 +impl bitcoin_units::parse::Integer for i16 +impl bitcoin_units::parse::Integer for i32 +impl bitcoin_units::parse::Integer for i64 +impl bitcoin_units::parse::Integer for i8 +impl bitcoin_units::parse::Integer for u128 +impl bitcoin_units::parse::Integer for u16 +impl bitcoin_units::parse::Integer for u32 +impl bitcoin_units::parse::Integer for u64 +impl bitcoin_units::parse::Integer for u8 +impl core::clone::Clone for bitcoin_units::Amount +impl core::clone::Clone for bitcoin_units::BlockTime +impl core::clone::Clone for bitcoin_units::FeeRate +impl core::clone::Clone for bitcoin_units::MathOp +impl core::clone::Clone for bitcoin_units::NumOpError +impl core::clone::Clone for bitcoin_units::SignedAmount +impl core::clone::Clone for bitcoin_units::Weight +impl core::clone::Clone for bitcoin_units::amount::Denomination +impl core::clone::Clone for bitcoin_units::amount::Display +impl core::clone::Clone for bitcoin_units::amount::InputTooLargeError +impl core::clone::Clone for bitcoin_units::amount::InvalidCharacterError +impl core::clone::Clone for bitcoin_units::amount::MissingDenominationError +impl core::clone::Clone for bitcoin_units::amount::MissingDigitsError +impl core::clone::Clone for bitcoin_units::amount::OutOfRangeError +impl core::clone::Clone for bitcoin_units::amount::ParseAmountError +impl core::clone::Clone for bitcoin_units::amount::ParseDenominationError +impl core::clone::Clone for bitcoin_units::amount::ParseError +impl core::clone::Clone for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::clone::Clone for bitcoin_units::amount::TooPreciseError +impl core::clone::Clone for bitcoin_units::amount::UnknownDenominationError +impl core::clone::Clone for bitcoin_units::block::BlockHeight +impl core::clone::Clone for bitcoin_units::block::BlockHeightInterval +impl core::clone::Clone for bitcoin_units::block::BlockMtp +impl core::clone::Clone for bitcoin_units::block::BlockMtpInterval +impl core::clone::Clone for bitcoin_units::block::TooBigForRelativeHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::ConversionError +impl core::clone::Clone for bitcoin_units::locktime::absolute::Height +impl core::clone::Clone for bitcoin_units::locktime::absolute::MedianTimePast +impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::clone::Clone for bitcoin_units::locktime::relative::TimeOverflowError +impl core::clone::Clone for bitcoin_units::parse::ParseIntError +impl core::clone::Clone for bitcoin_units::parse::PrefixedHexError +impl core::clone::Clone for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Eq for bitcoin_units::Amount +impl core::cmp::Eq for bitcoin_units::BlockTime +impl core::cmp::Eq for bitcoin_units::FeeRate +impl core::cmp::Eq for bitcoin_units::MathOp +impl core::cmp::Eq for bitcoin_units::NumOpError +impl core::cmp::Eq for bitcoin_units::SignedAmount +impl core::cmp::Eq for bitcoin_units::Weight +impl core::cmp::Eq for bitcoin_units::amount::Denomination +impl core::cmp::Eq for bitcoin_units::amount::InputTooLargeError +impl core::cmp::Eq for bitcoin_units::amount::InvalidCharacterError +impl core::cmp::Eq for bitcoin_units::amount::MissingDenominationError +impl core::cmp::Eq for bitcoin_units::amount::MissingDigitsError +impl core::cmp::Eq for bitcoin_units::amount::OutOfRangeError +impl core::cmp::Eq for bitcoin_units::amount::ParseAmountError +impl core::cmp::Eq for bitcoin_units::amount::ParseDenominationError +impl core::cmp::Eq for bitcoin_units::amount::ParseError +impl core::cmp::Eq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::cmp::Eq for bitcoin_units::amount::TooPreciseError +impl core::cmp::Eq for bitcoin_units::amount::UnknownDenominationError +impl core::cmp::Eq for bitcoin_units::block::BlockHeight +impl core::cmp::Eq for bitcoin_units::block::BlockHeightInterval +impl core::cmp::Eq for bitcoin_units::block::BlockMtp +impl core::cmp::Eq for bitcoin_units::block::BlockMtpInterval +impl core::cmp::Eq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ConversionError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::Height +impl core::cmp::Eq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::Eq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::Eq for bitcoin_units::parse::ParseIntError +impl core::cmp::Eq for bitcoin_units::parse::PrefixedHexError +impl core::cmp::Eq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Ord for bitcoin_units::Amount +impl core::cmp::Ord for bitcoin_units::BlockTime +impl core::cmp::Ord for bitcoin_units::FeeRate +impl core::cmp::Ord for bitcoin_units::SignedAmount +impl core::cmp::Ord for bitcoin_units::Weight +impl core::cmp::Ord for bitcoin_units::block::BlockHeight +impl core::cmp::Ord for bitcoin_units::block::BlockHeightInterval +impl core::cmp::Ord for bitcoin_units::block::BlockMtp +impl core::cmp::Ord for bitcoin_units::block::BlockMtpInterval +impl core::cmp::Ord for bitcoin_units::locktime::absolute::Height +impl core::cmp::Ord for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialEq for bitcoin_units::Amount +impl core::cmp::PartialEq for bitcoin_units::BlockTime +impl core::cmp::PartialEq for bitcoin_units::FeeRate +impl core::cmp::PartialEq for bitcoin_units::MathOp +impl core::cmp::PartialEq for bitcoin_units::NumOpError +impl core::cmp::PartialEq for bitcoin_units::SignedAmount +impl core::cmp::PartialEq for bitcoin_units::Weight +impl core::cmp::PartialEq for bitcoin_units::amount::Denomination +impl core::cmp::PartialEq for bitcoin_units::amount::InputTooLargeError +impl core::cmp::PartialEq for bitcoin_units::amount::InvalidCharacterError +impl core::cmp::PartialEq for bitcoin_units::amount::MissingDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::MissingDigitsError +impl core::cmp::PartialEq for bitcoin_units::amount::OutOfRangeError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseAmountError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::ParseError +impl core::cmp::PartialEq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::cmp::PartialEq for bitcoin_units::amount::TooPreciseError +impl core::cmp::PartialEq for bitcoin_units::amount::UnknownDenominationError +impl core::cmp::PartialEq for bitcoin_units::block::BlockHeight +impl core::cmp::PartialEq for bitcoin_units::block::BlockHeightInterval +impl core::cmp::PartialEq for bitcoin_units::block::BlockMtp +impl core::cmp::PartialEq for bitcoin_units::block::BlockMtpInterval +impl core::cmp::PartialEq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ConversionError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::PartialEq for bitcoin_units::parse::ParseIntError +impl core::cmp::PartialEq for bitcoin_units::parse::PrefixedHexError +impl core::cmp::PartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::PartialOrd for bitcoin_units::Amount +impl core::cmp::PartialOrd for bitcoin_units::BlockTime +impl core::cmp::PartialOrd for bitcoin_units::FeeRate +impl core::cmp::PartialOrd for bitcoin_units::SignedAmount +impl core::cmp::PartialOrd for bitcoin_units::Weight +impl core::cmp::PartialOrd for bitcoin_units::block::BlockHeight +impl core::cmp::PartialOrd for bitcoin_units::block::BlockHeightInterval +impl core::cmp::PartialOrd for bitcoin_units::block::BlockMtp +impl core::cmp::PartialOrd for bitcoin_units::block::BlockMtpInterval +impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::MedianTimePast +impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::AsRef for bitcoin_units::parse::ParseIntError +impl core::convert::From<&bitcoin_units::Amount> for bitcoin_units::NumOpResult +impl core::convert::From<&bitcoin_units::SignedAmount> for bitcoin_units::NumOpResult +impl core::convert::From for bitcoin_units::NumOpResult +impl core::convert::From for bitcoin_units::SignedAmount +impl core::convert::From for u32 +impl core::convert::From for bitcoin_units::NumOpResult +impl core::convert::From for u64 +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for u32 +impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::parse::PrefixedHexError +impl core::convert::From for bitcoin_units::parse::UnprefixedHexError +impl core::convert::From for core::num::error::ParseIntError +impl core::convert::From for bitcoin_units::amount::ParseAmountError +impl core::convert::From for bitcoin_units::amount::ParseDenominationError +impl core::convert::From for bitcoin_units::amount::ParseError +impl core::convert::From for bitcoin_units::parse::PrefixedHexError +impl core::convert::From for bitcoin_units::parse::UnprefixedHexError +impl core::convert::From for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::From for bitcoin_units::BlockTime +impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom<&str> for bitcoin_units::Weight +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeight +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeightInterval +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtp +impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtpInterval +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::Amount +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::default::Default for bitcoin_units::Amount +impl core::default::Default for bitcoin_units::SignedAmount +impl core::default::Default for bitcoin_units::block::BlockHeightInterval +impl core::default::Default for bitcoin_units::block::BlockMtpInterval +impl core::default::Default for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::default::Default for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Debug for bitcoin_units::Amount +impl core::fmt::Debug for bitcoin_units::BlockTime +impl core::fmt::Debug for bitcoin_units::FeeRate +impl core::fmt::Debug for bitcoin_units::MathOp +impl core::fmt::Debug for bitcoin_units::NumOpError +impl core::fmt::Debug for bitcoin_units::SignedAmount +impl core::fmt::Debug for bitcoin_units::Weight +impl core::fmt::Debug for bitcoin_units::amount::Denomination +impl core::fmt::Debug for bitcoin_units::amount::Display +impl core::fmt::Debug for bitcoin_units::amount::InputTooLargeError +impl core::fmt::Debug for bitcoin_units::amount::InvalidCharacterError +impl core::fmt::Debug for bitcoin_units::amount::MissingDenominationError +impl core::fmt::Debug for bitcoin_units::amount::MissingDigitsError +impl core::fmt::Debug for bitcoin_units::amount::OutOfRangeError +impl core::fmt::Debug for bitcoin_units::amount::ParseAmountError +impl core::fmt::Debug for bitcoin_units::amount::ParseDenominationError +impl core::fmt::Debug for bitcoin_units::amount::ParseError +impl core::fmt::Debug for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::fmt::Debug for bitcoin_units::amount::TooPreciseError +impl core::fmt::Debug for bitcoin_units::amount::UnknownDenominationError +impl core::fmt::Debug for bitcoin_units::block::BlockHeight +impl core::fmt::Debug for bitcoin_units::block::BlockHeightInterval +impl core::fmt::Debug for bitcoin_units::block::BlockMtp +impl core::fmt::Debug for bitcoin_units::block::BlockMtpInterval +impl core::fmt::Debug for bitcoin_units::block::TooBigForRelativeHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ConversionError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::Height +impl core::fmt::Debug for bitcoin_units::locktime::absolute::MedianTimePast +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Debug for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Debug for bitcoin_units::parse::ParseIntError +impl core::fmt::Debug for bitcoin_units::parse::PrefixedHexError +impl core::fmt::Debug for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Display for bitcoin_units::Amount +impl core::fmt::Display for bitcoin_units::MathOp +impl core::fmt::Display for bitcoin_units::NumOpError +impl core::fmt::Display for bitcoin_units::SignedAmount +impl core::fmt::Display for bitcoin_units::Weight +impl core::fmt::Display for bitcoin_units::amount::Denomination +impl core::fmt::Display for bitcoin_units::amount::Display +impl core::fmt::Display for bitcoin_units::amount::InputTooLargeError +impl core::fmt::Display for bitcoin_units::amount::InvalidCharacterError +impl core::fmt::Display for bitcoin_units::amount::MissingDigitsError +impl core::fmt::Display for bitcoin_units::amount::OutOfRangeError +impl core::fmt::Display for bitcoin_units::amount::ParseAmountError +impl core::fmt::Display for bitcoin_units::amount::ParseDenominationError +impl core::fmt::Display for bitcoin_units::amount::ParseError +impl core::fmt::Display for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::fmt::Display for bitcoin_units::amount::TooPreciseError +impl core::fmt::Display for bitcoin_units::amount::UnknownDenominationError +impl core::fmt::Display for bitcoin_units::block::BlockHeight +impl core::fmt::Display for bitcoin_units::block::BlockHeightInterval +impl core::fmt::Display for bitcoin_units::block::BlockMtp +impl core::fmt::Display for bitcoin_units::block::BlockMtpInterval +impl core::fmt::Display for bitcoin_units::block::TooBigForRelativeHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::ConversionError +impl core::fmt::Display for bitcoin_units::locktime::absolute::Height +impl core::fmt::Display for bitcoin_units::locktime::absolute::MedianTimePast +impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::fmt::Display for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Display for bitcoin_units::parse::ParseIntError +impl core::fmt::Display for bitcoin_units::parse::PrefixedHexError +impl core::fmt::Display for bitcoin_units::parse::UnprefixedHexError +impl core::hash::Hash for bitcoin_units::Amount +impl core::hash::Hash for bitcoin_units::BlockTime +impl core::hash::Hash for bitcoin_units::FeeRate +impl core::hash::Hash for bitcoin_units::SignedAmount +impl core::hash::Hash for bitcoin_units::Weight +impl core::hash::Hash for bitcoin_units::amount::Denomination +impl core::hash::Hash for bitcoin_units::block::BlockHeight +impl core::hash::Hash for bitcoin_units::block::BlockHeightInterval +impl core::hash::Hash for bitcoin_units::block::BlockMtp +impl core::hash::Hash for bitcoin_units::block::BlockMtpInterval +impl core::hash::Hash for bitcoin_units::locktime::absolute::Height +impl core::hash::Hash for bitcoin_units::locktime::absolute::MedianTimePast +impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::iter::traits::accum::Sum for bitcoin_units::FeeRate +impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult +impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult +impl core::iter::traits::accum::Sum for bitcoin_units::Weight +impl core::iter::traits::accum::Sum for bitcoin_units::block::BlockHeightInterval +impl core::iter::traits::accum::Sum for bitcoin_units::block::BlockMtpInterval +impl core::marker::Copy for bitcoin_units::Amount +impl core::marker::Copy for bitcoin_units::BlockTime +impl core::marker::Copy for bitcoin_units::FeeRate +impl core::marker::Copy for bitcoin_units::MathOp +impl core::marker::Copy for bitcoin_units::NumOpError +impl core::marker::Copy for bitcoin_units::SignedAmount +impl core::marker::Copy for bitcoin_units::Weight +impl core::marker::Copy for bitcoin_units::amount::Denomination +impl core::marker::Copy for bitcoin_units::amount::OutOfRangeError +impl core::marker::Copy for bitcoin_units::block::BlockHeight +impl core::marker::Copy for bitcoin_units::block::BlockHeightInterval +impl core::marker::Copy for bitcoin_units::block::BlockMtp +impl core::marker::Copy for bitcoin_units::block::BlockMtpInterval +impl core::marker::Copy for bitcoin_units::locktime::absolute::Height +impl core::marker::Copy for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Freeze for bitcoin_units::Amount +impl core::marker::Freeze for bitcoin_units::BlockTime +impl core::marker::Freeze for bitcoin_units::FeeRate +impl core::marker::Freeze for bitcoin_units::MathOp +impl core::marker::Freeze for bitcoin_units::NumOpError +impl core::marker::Freeze for bitcoin_units::SignedAmount +impl core::marker::Freeze for bitcoin_units::Weight +impl core::marker::Freeze for bitcoin_units::amount::Denomination +impl core::marker::Freeze for bitcoin_units::amount::Display +impl core::marker::Freeze for bitcoin_units::amount::InputTooLargeError +impl core::marker::Freeze for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Freeze for bitcoin_units::amount::MissingDenominationError +impl core::marker::Freeze for bitcoin_units::amount::MissingDigitsError +impl core::marker::Freeze for bitcoin_units::amount::OutOfRangeError +impl core::marker::Freeze for bitcoin_units::amount::ParseAmountError +impl core::marker::Freeze for bitcoin_units::amount::ParseDenominationError +impl core::marker::Freeze for bitcoin_units::amount::ParseError +impl core::marker::Freeze for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Freeze for bitcoin_units::amount::TooPreciseError +impl core::marker::Freeze for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Freeze for bitcoin_units::block::BlockHeight +impl core::marker::Freeze for bitcoin_units::block::BlockHeightInterval +impl core::marker::Freeze for bitcoin_units::block::BlockMtp +impl core::marker::Freeze for bitcoin_units::block::BlockMtpInterval +impl core::marker::Freeze for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::Height +impl core::marker::Freeze for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Freeze for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Freeze for bitcoin_units::parse::ParseIntError +impl core::marker::Freeze for bitcoin_units::parse::PrefixedHexError +impl core::marker::Freeze for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Send for bitcoin_units::Amount +impl core::marker::Send for bitcoin_units::BlockTime +impl core::marker::Send for bitcoin_units::FeeRate +impl core::marker::Send for bitcoin_units::MathOp +impl core::marker::Send for bitcoin_units::NumOpError +impl core::marker::Send for bitcoin_units::SignedAmount +impl core::marker::Send for bitcoin_units::Weight +impl core::marker::Send for bitcoin_units::amount::Denomination +impl core::marker::Send for bitcoin_units::amount::Display +impl core::marker::Send for bitcoin_units::amount::InputTooLargeError +impl core::marker::Send for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Send for bitcoin_units::amount::MissingDenominationError +impl core::marker::Send for bitcoin_units::amount::MissingDigitsError +impl core::marker::Send for bitcoin_units::amount::OutOfRangeError +impl core::marker::Send for bitcoin_units::amount::ParseAmountError +impl core::marker::Send for bitcoin_units::amount::ParseDenominationError +impl core::marker::Send for bitcoin_units::amount::ParseError +impl core::marker::Send for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Send for bitcoin_units::amount::TooPreciseError +impl core::marker::Send for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Send for bitcoin_units::block::BlockHeight +impl core::marker::Send for bitcoin_units::block::BlockHeightInterval +impl core::marker::Send for bitcoin_units::block::BlockMtp +impl core::marker::Send for bitcoin_units::block::BlockMtpInterval +impl core::marker::Send for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Send for bitcoin_units::locktime::absolute::Height +impl core::marker::Send for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Send for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Send for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Send for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Send for bitcoin_units::parse::ParseIntError +impl core::marker::Send for bitcoin_units::parse::PrefixedHexError +impl core::marker::Send for bitcoin_units::parse::UnprefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::Amount +impl core::marker::StructuralPartialEq for bitcoin_units::BlockTime +impl core::marker::StructuralPartialEq for bitcoin_units::FeeRate +impl core::marker::StructuralPartialEq for bitcoin_units::MathOp +impl core::marker::StructuralPartialEq for bitcoin_units::NumOpError +impl core::marker::StructuralPartialEq for bitcoin_units::SignedAmount +impl core::marker::StructuralPartialEq for bitcoin_units::Weight +impl core::marker::StructuralPartialEq for bitcoin_units::amount::Denomination +impl core::marker::StructuralPartialEq for bitcoin_units::amount::InputTooLargeError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::InvalidCharacterError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::MissingDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::MissingDigitsError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::OutOfRangeError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseAmountError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::ParseError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::TooPreciseError +impl core::marker::StructuralPartialEq for bitcoin_units::amount::UnknownDenominationError +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeight +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeightInterval +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtp +impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtpInterval +impl core::marker::StructuralPartialEq for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::Height +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::ParseIntError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::PrefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Sync for bitcoin_units::Amount +impl core::marker::Sync for bitcoin_units::BlockTime +impl core::marker::Sync for bitcoin_units::FeeRate +impl core::marker::Sync for bitcoin_units::MathOp +impl core::marker::Sync for bitcoin_units::NumOpError +impl core::marker::Sync for bitcoin_units::SignedAmount +impl core::marker::Sync for bitcoin_units::Weight +impl core::marker::Sync for bitcoin_units::amount::Denomination +impl core::marker::Sync for bitcoin_units::amount::Display +impl core::marker::Sync for bitcoin_units::amount::InputTooLargeError +impl core::marker::Sync for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Sync for bitcoin_units::amount::MissingDenominationError +impl core::marker::Sync for bitcoin_units::amount::MissingDigitsError +impl core::marker::Sync for bitcoin_units::amount::OutOfRangeError +impl core::marker::Sync for bitcoin_units::amount::ParseAmountError +impl core::marker::Sync for bitcoin_units::amount::ParseDenominationError +impl core::marker::Sync for bitcoin_units::amount::ParseError +impl core::marker::Sync for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Sync for bitcoin_units::amount::TooPreciseError +impl core::marker::Sync for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Sync for bitcoin_units::block::BlockHeight +impl core::marker::Sync for bitcoin_units::block::BlockHeightInterval +impl core::marker::Sync for bitcoin_units::block::BlockMtp +impl core::marker::Sync for bitcoin_units::block::BlockMtpInterval +impl core::marker::Sync for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Sync for bitcoin_units::locktime::absolute::Height +impl core::marker::Sync for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Sync for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Sync for bitcoin_units::parse::ParseIntError +impl core::marker::Sync for bitcoin_units::parse::PrefixedHexError +impl core::marker::Sync for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Unpin for bitcoin_units::Amount +impl core::marker::Unpin for bitcoin_units::BlockTime +impl core::marker::Unpin for bitcoin_units::FeeRate +impl core::marker::Unpin for bitcoin_units::MathOp +impl core::marker::Unpin for bitcoin_units::NumOpError +impl core::marker::Unpin for bitcoin_units::SignedAmount +impl core::marker::Unpin for bitcoin_units::Weight +impl core::marker::Unpin for bitcoin_units::amount::Denomination +impl core::marker::Unpin for bitcoin_units::amount::Display +impl core::marker::Unpin for bitcoin_units::amount::InputTooLargeError +impl core::marker::Unpin for bitcoin_units::amount::InvalidCharacterError +impl core::marker::Unpin for bitcoin_units::amount::MissingDenominationError +impl core::marker::Unpin for bitcoin_units::amount::MissingDigitsError +impl core::marker::Unpin for bitcoin_units::amount::OutOfRangeError +impl core::marker::Unpin for bitcoin_units::amount::ParseAmountError +impl core::marker::Unpin for bitcoin_units::amount::ParseDenominationError +impl core::marker::Unpin for bitcoin_units::amount::ParseError +impl core::marker::Unpin for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::marker::Unpin for bitcoin_units::amount::TooPreciseError +impl core::marker::Unpin for bitcoin_units::amount::UnknownDenominationError +impl core::marker::Unpin for bitcoin_units::block::BlockHeight +impl core::marker::Unpin for bitcoin_units::block::BlockHeightInterval +impl core::marker::Unpin for bitcoin_units::block::BlockMtp +impl core::marker::Unpin for bitcoin_units::block::BlockMtpInterval +impl core::marker::Unpin for bitcoin_units::block::TooBigForRelativeHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ConversionError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::Height +impl core::marker::Unpin for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Unpin for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Unpin for bitcoin_units::parse::ParseIntError +impl core::marker::Unpin for bitcoin_units::parse::PrefixedHexError +impl core::marker::Unpin for bitcoin_units::parse::UnprefixedHexError +impl core::ops::arith::Add for bitcoin_units::Amount +impl core::ops::arith::Add for bitcoin_units::FeeRate +impl core::ops::arith::Add for bitcoin_units::SignedAmount +impl core::ops::arith::Add for bitcoin_units::Weight +impl core::ops::arith::Add for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Add<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::SignedAmount +impl core::ops::arith::Add<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Add<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Add<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Add<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Add<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add for &bitcoin_units::Amount +impl core::ops::arith::Add for &bitcoin_units::FeeRate +impl core::ops::arith::Add> for &bitcoin_units::Amount +impl core::ops::arith::Add> for bitcoin_units::Amount +impl core::ops::arith::Add> for &bitcoin_units::SignedAmount +impl core::ops::arith::Add> for bitcoin_units::SignedAmount +impl core::ops::arith::Add for &bitcoin_units::SignedAmount +impl core::ops::arith::Add for &bitcoin_units::Weight +impl core::ops::arith::Add for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Add for &bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockHeight +impl core::ops::arith::Add for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Add for &bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Add for bitcoin_units::block::BlockMtp +impl core::ops::arith::AddAssign for bitcoin_units::FeeRate +impl core::ops::arith::AddAssign for bitcoin_units::Weight +impl core::ops::arith::AddAssign for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::AddAssign for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::AddAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::AddAssign<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::AddAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::SignedAmount +impl core::ops::arith::Div for bitcoin_units::Weight +impl core::ops::arith::Div<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::FeeRate> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::FeeRate> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::Amount +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::Amount +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::FeeRate +impl core::ops::arith::Div<&core::num::nonzero::NonZero> for bitcoin_units::Weight +impl core::ops::arith::Div<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Div<&u64> for bitcoin_units::Amount +impl core::ops::arith::Div<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Div<&u64> for bitcoin_units::Weight +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::NumOpResult +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::NumOpResult +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::SignedAmount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::Weight +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div> for &bitcoin_units::SignedAmount +impl core::ops::arith::Div> for bitcoin_units::SignedAmount +impl core::ops::arith::Div> for &bitcoin_units::Amount +impl core::ops::arith::Div> for &bitcoin_units::FeeRate +impl core::ops::arith::Div> for &bitcoin_units::Weight +impl core::ops::arith::Div> for bitcoin_units::Amount +impl core::ops::arith::Div> for bitcoin_units::FeeRate +impl core::ops::arith::Div> for bitcoin_units::Weight +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::SignedAmount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::SignedAmount +impl core::ops::arith::Div for &bitcoin_units::Amount +impl core::ops::arith::Div for &bitcoin_units::NumOpResult +impl core::ops::arith::Div for &bitcoin_units::Weight +impl core::ops::arith::Div for bitcoin_units::Amount +impl core::ops::arith::Div for bitcoin_units::NumOpResult +impl core::ops::arith::Div for bitcoin_units::Weight +impl core::ops::arith::DivAssign<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::NumOpResult +impl core::ops::arith::DivAssign for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::Amount> for u64 +impl core::ops::arith::Mul<&bitcoin_units::FeeRate> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::FeeRate> for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for u64 +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::Weight +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for i64 +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::FeeRate +impl core::ops::arith::Mul<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::SignedAmount> for i64 +impl core::ops::arith::Mul<&bitcoin_units::Weight> for bitcoin_units::FeeRate +impl core::ops::arith::Mul<&bitcoin_units::Weight> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&bitcoin_units::Weight> for u64 +impl core::ops::arith::Mul<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Mul<&u64> for bitcoin_units::Amount +impl core::ops::arith::Mul<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul<&u64> for bitcoin_units::Weight +impl core::ops::arith::Mul for &u64 +impl core::ops::arith::Mul for u64 +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::Weight +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::Weight +impl core::ops::arith::Mul> for &u64 +impl core::ops::arith::Mul> for u64 +impl core::ops::arith::Mul> for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for &bitcoin_units::Weight +impl core::ops::arith::Mul> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for bitcoin_units::Weight +impl core::ops::arith::Mul> for &i64 +impl core::ops::arith::Mul> for i64 +impl core::ops::arith::Mul> for &bitcoin_units::FeeRate +impl core::ops::arith::Mul> for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul> for bitcoin_units::FeeRate +impl core::ops::arith::Mul> for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &i64 +impl core::ops::arith::Mul for i64 +impl core::ops::arith::Mul for &bitcoin_units::FeeRate +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &u64 +impl core::ops::arith::Mul for bitcoin_units::FeeRate +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for u64 +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::SignedAmount +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::SignedAmount +impl core::ops::arith::Mul for &bitcoin_units::Amount +impl core::ops::arith::Mul for &bitcoin_units::NumOpResult +impl core::ops::arith::Mul for &bitcoin_units::Weight +impl core::ops::arith::Mul for bitcoin_units::Amount +impl core::ops::arith::Mul for bitcoin_units::NumOpResult +impl core::ops::arith::Mul for bitcoin_units::Weight +impl core::ops::arith::MulAssign<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::NumOpResult +impl core::ops::arith::MulAssign for bitcoin_units::Weight +impl core::ops::arith::Neg for bitcoin_units::SignedAmount +impl core::ops::arith::Rem for bitcoin_units::Weight +impl core::ops::arith::Rem<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Rem<&i64> for bitcoin_units::NumOpResult +impl core::ops::arith::Rem<&i64> for bitcoin_units::SignedAmount +impl core::ops::arith::Rem<&u64> for bitcoin_units::Amount +impl core::ops::arith::Rem<&u64> for bitcoin_units::NumOpResult +impl core::ops::arith::Rem<&u64> for bitcoin_units::Weight +impl core::ops::arith::Rem for &bitcoin_units::Weight +impl core::ops::arith::Rem for &bitcoin_units::NumOpResult +impl core::ops::arith::Rem for &bitcoin_units::SignedAmount +impl core::ops::arith::Rem for bitcoin_units::NumOpResult +impl core::ops::arith::Rem for bitcoin_units::SignedAmount +impl core::ops::arith::Rem for &bitcoin_units::Amount +impl core::ops::arith::Rem for &bitcoin_units::NumOpResult +impl core::ops::arith::Rem for &bitcoin_units::Weight +impl core::ops::arith::Rem for bitcoin_units::Amount +impl core::ops::arith::Rem for bitcoin_units::NumOpResult +impl core::ops::arith::Rem for bitcoin_units::Weight +impl core::ops::arith::RemAssign for bitcoin_units::Weight +impl core::ops::arith::Sub for bitcoin_units::Amount +impl core::ops::arith::Sub for bitcoin_units::FeeRate +impl core::ops::arith::Sub for bitcoin_units::SignedAmount +impl core::ops::arith::Sub for bitcoin_units::Weight +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub<&bitcoin_units::Amount> for bitcoin_units::Amount +impl core::ops::arith::Sub<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::Amount +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub<&bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeight> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtp> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub for &bitcoin_units::Amount +impl core::ops::arith::Sub for &bitcoin_units::FeeRate +impl core::ops::arith::Sub> for &bitcoin_units::Amount +impl core::ops::arith::Sub> for bitcoin_units::Amount +impl core::ops::arith::Sub> for &bitcoin_units::SignedAmount +impl core::ops::arith::Sub> for bitcoin_units::SignedAmount +impl core::ops::arith::Sub for &bitcoin_units::SignedAmount +impl core::ops::arith::Sub for &bitcoin_units::Weight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockHeight +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtp +impl core::ops::arith::Sub for &bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::Sub for bitcoin_units::block::BlockMtp +impl core::ops::arith::SubAssign for bitcoin_units::FeeRate +impl core::ops::arith::SubAssign for bitcoin_units::Weight +impl core::ops::arith::SubAssign for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::SubAssign for bitcoin_units::block::BlockMtpInterval +impl core::ops::arith::SubAssign<&bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl core::ops::arith::SubAssign<&bitcoin_units::Weight> for bitcoin_units::Weight +impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl core::ops::arith::SubAssign<&bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Amount +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::BlockTime +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::FeeRate +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::MathOp +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::NumOpError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::SignedAmount +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::Weight +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::Denomination +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::Display +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::InputTooLargeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::InvalidCharacterError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::MissingDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::MissingDigitsError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::OutOfRangeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseAmountError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::ParseError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::TooPreciseError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::amount::UnknownDenominationError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeight +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeightInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtp +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ConversionError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::ParseIntError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::PrefixedHexError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Amount +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::BlockTime +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::FeeRate +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::MathOp +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::NumOpError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::SignedAmount +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Weight +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::Denomination +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::Display +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::InputTooLargeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::InvalidCharacterError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::MissingDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::MissingDigitsError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::OutOfRangeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseAmountError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::ParseError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::PossiblyConfusingDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::TooPreciseError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::amount::UnknownDenominationError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeight +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeightInterval +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtp +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtpInterval +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ConversionError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::ParseIntError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::PrefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::str::traits::FromStr for bitcoin_units::Amount +impl core::str::traits::FromStr for bitcoin_units::SignedAmount +impl core::str::traits::FromStr for bitcoin_units::Weight +impl core::str::traits::FromStr for bitcoin_units::amount::Denomination +impl core::str::traits::FromStr for bitcoin_units::block::BlockHeight +impl core::str::traits::FromStr for bitcoin_units::block::BlockHeightInterval +impl core::str::traits::FromStr for bitcoin_units::block::BlockMtp +impl core::str::traits::FromStr for bitcoin_units::block::BlockMtpInterval +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::Height +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::MedianTimePast +impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOf512Seconds +impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOfBlocks +impl<'a, T> core::ops::arith::Add<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl<'a, T> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl<'a, T> core::ops::arith::Sub<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl<'a, T> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::FeeRate> for bitcoin_units::FeeRate +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::Weight> for bitcoin_units::Weight +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::block::BlockHeightInterval> for bitcoin_units::block::BlockHeightInterval +impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::block::BlockMtpInterval> for bitcoin_units::block::BlockMtpInterval +impl<'a> core::ops::arith::Add<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::FeeRate> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Add<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeightInterval +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Add<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtpInterval +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::FeeRate> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::FeeRate> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Div<&'a core::num::nonzero::NonZero> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Div<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Div<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Amount> for &u64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::FeeRate> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::FeeRate> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &u64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &i64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::SignedAmount> for &i64 +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a bitcoin_units::Weight> for &u64 +impl<'a> core::ops::arith::Mul<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Mul<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Rem<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Rem<&'a i64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Rem<&'a i64> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::NumOpResult +impl<'a> core::ops::arith::Rem<&'a u64> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::Amount> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::FeeRate> for &bitcoin_units::FeeRate +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::Amount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::NumOpResult> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::SignedAmount> for &bitcoin_units::SignedAmount +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::Weight> for &bitcoin_units::Weight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeight> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeight +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockHeightInterval> for &bitcoin_units::block::BlockHeightInterval +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtp> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtp +impl<'a> core::ops::arith::Sub<&'a bitcoin_units::block::BlockMtpInterval> for &bitcoin_units::block::BlockMtpInterval +impl core::clone::Clone for bitcoin_units::NumOpResult +impl core::cmp::Eq for bitcoin_units::NumOpResult +impl core::cmp::PartialEq for bitcoin_units::NumOpResult +impl bitcoin_units::NumOpResult +impl core::fmt::Debug for bitcoin_units::NumOpResult +impl core::marker::Copy for bitcoin_units::NumOpResult +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator +impl bitcoin_units::NumOpResult +impl core::marker::Freeze for bitcoin_units::NumOpResult where T: core::marker::Freeze +impl core::marker::Send for bitcoin_units::NumOpResult where T: core::marker::Send +impl core::marker::StructuralPartialEq for bitcoin_units::NumOpResult +impl core::marker::Sync for bitcoin_units::NumOpResult where T: core::marker::Sync +impl core::marker::Unpin for bitcoin_units::NumOpResult where T: core::marker::Unpin +impl core::ops::arith::Add for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Add<&T> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Add for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> +impl core::ops::arith::Add> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> +impl core::ops::arith::Sub for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub<&T> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub<&bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub for bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::ops::arith::Sub> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::NumOpResult where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::NumOpResult where T: core::panic::unwind_safe::UnwindSafe +pub bitcoin_units::MathOp::Add +pub bitcoin_units::MathOp::Div +pub bitcoin_units::MathOp::Mul +pub bitcoin_units::MathOp::Neg +pub bitcoin_units::MathOp::Rem +pub bitcoin_units::MathOp::Sub +pub bitcoin_units::NumOpResult::Error(bitcoin_units::NumOpError) +pub bitcoin_units::NumOpResult::Valid(T) +pub bitcoin_units::amount::Denomination::Bit +pub bitcoin_units::amount::Denomination::Bitcoin +pub bitcoin_units::amount::Denomination::CentiBitcoin +pub bitcoin_units::amount::Denomination::MicroBitcoin +pub bitcoin_units::amount::Denomination::MilliBitcoin +pub bitcoin_units::amount::Denomination::Satoshi +pub bitcoin_units::amount::ParseDenominationError::PossiblyConfusing(bitcoin_units::amount::PossiblyConfusingDenominationError) +pub bitcoin_units::amount::ParseDenominationError::Unknown(bitcoin_units::amount::UnknownDenominationError) +pub const bitcoin_units::Amount::FIFTY_BTC: Self +pub const bitcoin_units::Amount::MAX: Self +pub const bitcoin_units::Amount::MAX_MONEY: Self +pub const bitcoin_units::Amount::MIN: Self +pub const bitcoin_units::Amount::ONE_BTC: Self +pub const bitcoin_units::Amount::ONE_SAT: Self +pub const bitcoin_units::Amount::SIZE: usize +pub const bitcoin_units::Amount::ZERO: Self +pub const bitcoin_units::FeeRate::BROADCAST_MIN: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::DUST: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::MAX: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::MIN: bitcoin_units::FeeRate +pub const bitcoin_units::FeeRate::ZERO: bitcoin_units::FeeRate +pub const bitcoin_units::SignedAmount::FIFTY_BTC: Self +pub const bitcoin_units::SignedAmount::MAX: Self +pub const bitcoin_units::SignedAmount::MAX_MONEY: Self +pub const bitcoin_units::SignedAmount::MIN: Self +pub const bitcoin_units::SignedAmount::ONE_BTC: Self +pub const bitcoin_units::SignedAmount::ONE_SAT: Self +pub const bitcoin_units::SignedAmount::ZERO: Self +pub const bitcoin_units::Weight::MAX: bitcoin_units::Weight +pub const bitcoin_units::Weight::MAX_BLOCK: bitcoin_units::Weight +pub const bitcoin_units::Weight::MIN: bitcoin_units::Weight +pub const bitcoin_units::Weight::MIN_TRANSACTION: bitcoin_units::Weight +pub const bitcoin_units::Weight::WITNESS_SCALE_FACTOR: u64 +pub const bitcoin_units::Weight::ZERO: bitcoin_units::Weight +pub const bitcoin_units::amount::Denomination::BTC: Self +pub const bitcoin_units::amount::Denomination::SAT: Self +pub const bitcoin_units::block::BlockHeight::MAX: Self +pub const bitcoin_units::block::BlockHeight::MIN: Self +pub const bitcoin_units::block::BlockHeight::ZERO: Self +pub const bitcoin_units::block::BlockHeightInterval::MAX: Self +pub const bitcoin_units::block::BlockHeightInterval::MIN: Self +pub const bitcoin_units::block::BlockHeightInterval::ZERO: Self +pub const bitcoin_units::block::BlockMtp::MAX: Self +pub const bitcoin_units::block::BlockMtp::MIN: Self +pub const bitcoin_units::block::BlockMtp::ZERO: Self +pub const bitcoin_units::block::BlockMtpInterval::MAX: Self +pub const bitcoin_units::block::BlockMtpInterval::MIN: Self +pub const bitcoin_units::block::BlockMtpInterval::ZERO: Self +pub const bitcoin_units::locktime::absolute::Height::MAX: Self +pub const bitcoin_units::locktime::absolute::Height::MIN: Self +pub const bitcoin_units::locktime::absolute::Height::ZERO: Self +pub const bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD: u32 +pub const bitcoin_units::locktime::absolute::MedianTimePast::MAX: Self +pub const bitcoin_units::locktime::absolute::MedianTimePast::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MAX: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOf512Seconds::ZERO: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::MAX: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::MIN: Self +pub const bitcoin_units::locktime::relative::NumberOfBlocks::ZERO: Self +pub const bitcoin_units::weight::WITNESS_SCALE_FACTOR: usize +pub const fn bitcoin_units::Amount::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_rem(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Amount::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Amount::div_by_fee_rate_ceil(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_fee_rate_floor(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_weight_ceil(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::div_by_weight_floor(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Amount::from_btc_u16(whole_bitcoin: u16) -> Self +pub const fn bitcoin_units::Amount::from_sat(satoshi: u64) -> core::result::Result +pub const fn bitcoin_units::Amount::from_sat_u32(satoshi: u32) -> Self +pub const fn bitcoin_units::Amount::to_sat(self) -> u64 +pub const fn bitcoin_units::BlockTime::from_u32(t: u32) -> Self +pub const fn bitcoin_units::BlockTime::to_u32(self) -> u32 +pub const fn bitcoin_units::FeeRate::checked_add(self, rhs: bitcoin_units::FeeRate) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::FeeRate::checked_sub(self, rhs: bitcoin_units::FeeRate) -> core::option::Option +pub const fn bitcoin_units::FeeRate::from_per_kvb(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_per_kwu(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_per_vb(rate: bitcoin_units::Amount) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::from_sat_per_kvb(sat_kvb: u32) -> Self +pub const fn bitcoin_units::FeeRate::from_sat_per_kwu(sat_kwu: u32) -> Self +pub const fn bitcoin_units::FeeRate::from_sat_per_vb(sat_vb: u32) -> Self +pub const fn bitcoin_units::FeeRate::mul_by_weight(self, weight: bitcoin_units::Weight) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::FeeRate::to_fee(self, weight: bitcoin_units::Weight) -> bitcoin_units::Amount +pub const fn bitcoin_units::FeeRate::to_sat_per_kvb_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kvb_floor(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kwu_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_kwu_floor(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_vb_ceil(self) -> u64 +pub const fn bitcoin_units::FeeRate::to_sat_per_vb_floor(self) -> u64 +pub const fn bitcoin_units::SignedAmount::abs(self) -> Self +pub const fn bitcoin_units::SignedAmount::checked_abs(self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_div(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_mul(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_rem(self, rhs: i64) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::SignedAmount::from_btc_i16(whole_bitcoin: i16) -> Self +pub const fn bitcoin_units::SignedAmount::from_sat(satoshi: i64) -> core::result::Result +pub const fn bitcoin_units::SignedAmount::from_sat_i32(satoshi: i32) -> Self +pub const fn bitcoin_units::SignedAmount::to_sat(self) -> i64 +pub const fn bitcoin_units::Weight::checked_add(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_div(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_mul(self, rhs: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::checked_sub(self, rhs: Self) -> core::option::Option +pub const fn bitcoin_units::Weight::from_kwu(wu: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::from_non_witness_data_size(non_witness_size: u64) -> Self +pub const fn bitcoin_units::Weight::from_vb(vb: u64) -> core::option::Option +pub const fn bitcoin_units::Weight::from_vb_unchecked(vb: u64) -> Self +pub const fn bitcoin_units::Weight::from_vb_unwrap(vb: u64) -> bitcoin_units::Weight +pub const fn bitcoin_units::Weight::from_witness_data_size(witness_size: u64) -> Self +pub const fn bitcoin_units::Weight::from_wu(wu: u64) -> Self +pub const fn bitcoin_units::Weight::mul_by_fee_rate(self, fee_rate: bitcoin_units::FeeRate) -> bitcoin_units::NumOpResult +pub const fn bitcoin_units::Weight::to_kwu_ceil(self) -> u64 +pub const fn bitcoin_units::Weight::to_kwu_floor(self) -> u64 +pub const fn bitcoin_units::Weight::to_vbytes_ceil(self) -> u64 +pub const fn bitcoin_units::Weight::to_vbytes_floor(self) -> u64 +pub const fn bitcoin_units::Weight::to_wu(self) -> u64 +pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockHeightInterval::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockHeightInterval::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockMtp::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockMtp::to_u32(self) -> u32 +pub const fn bitcoin_units::block::BlockMtpInterval::from_u32(inner: u32) -> Self +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::Height::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::to_u32(self) -> u32 +pub const fn bitcoin_units::locktime::absolute::is_block_height(n: u32) -> bool +pub const fn bitcoin_units::locktime::absolute::is_block_time(n: u32) -> bool +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_512_second_intervals(intervals: u16) -> Self +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_512_second_intervals(self) -> u16 +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_consensus_u32(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_seconds(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::from_height(blocks: u16) -> Self +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_consensus_u32(self) -> u32 +pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_height(self) -> u16 +pub enum bitcoin_units::NumOpResult +pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Amount::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Amount::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &bitcoin_units::Amount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::FeeRate::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::FeeRate::sub(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::FeeRate::sub(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: &T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: &T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: T) -> Self::Output +pub fn &bitcoin_units::NumOpResult::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::div(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::rem(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &core::num::nonzero::NonZeroI64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: core::num::nonzero::NonZeroI64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::mul(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::mul(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::rem(self, rhs: i64) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn &bitcoin_units::Weight::div(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &bitcoin_units::Weight::mul(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: &u64) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::rem(self, rhs: u64) -> Self::Output +pub fn &bitcoin_units::Weight::sub(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::Weight::sub(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeight) -> Self::Output +pub fn &bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockHeightInterval::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtp) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtp) -> Self::Output +pub fn &bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &bitcoin_units::block::BlockMtpInterval::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn &i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn &i64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &i64::mul(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn &u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn &u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn T::checked_sum(self) -> core::option::Option +pub fn T::checked_sum(self) -> core::option::Option +pub fn T::checked_sum(self) -> core::option::Option +pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::clone(&self) -> bitcoin_units::Amount +pub fn bitcoin_units::Amount::cmp(&self, other: &bitcoin_units::Amount) -> core::cmp::Ordering +pub fn bitcoin_units::Amount::default() -> Self +pub fn bitcoin_units::Amount::display_dynamic(self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::Amount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Amount::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Amount::eq(&self, other: &bitcoin_units::Amount) -> bool +pub fn bitcoin_units::Amount::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::Amount::from_int_btc>(whole_bitcoin: T) -> Self +pub fn bitcoin_units::Amount::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::Amount::from_str_in(s: &str, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::Amount::from_str_with_denomination(s: &str) -> core::result::Result +pub fn bitcoin_units::Amount::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::Amount::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option +pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output +pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Amount::to_signed(self) -> bitcoin_units::SignedAmount +pub fn bitcoin_units::Amount::try_from(value: bitcoin_units::SignedAmount) -> core::result::Result +pub fn bitcoin_units::BlockTime::clone(&self) -> bitcoin_units::BlockTime +pub fn bitcoin_units::BlockTime::cmp(&self, other: &bitcoin_units::BlockTime) -> core::cmp::Ordering +pub fn bitcoin_units::BlockTime::eq(&self, other: &bitcoin_units::BlockTime) -> bool +pub fn bitcoin_units::BlockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::BlockTime::from(t: u32) -> Self +pub fn bitcoin_units::BlockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::BlockTime::partial_cmp(&self, other: &bitcoin_units::BlockTime) -> core::option::Option +pub fn bitcoin_units::CheckedSum::checked_sum(self) -> core::option::Option +pub fn bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: &bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::clone(&self) -> bitcoin_units::FeeRate +pub fn bitcoin_units::FeeRate::cmp(&self, other: &bitcoin_units::FeeRate) -> core::cmp::Ordering +pub fn bitcoin_units::FeeRate::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::FeeRate::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::FeeRate::eq(&self, other: &bitcoin_units::FeeRate) -> bool +pub fn bitcoin_units::FeeRate::fee_vb(self, vb: u64) -> core::option::Option +pub fn bitcoin_units::FeeRate::fee_wu(self, weight: bitcoin_units::Weight) -> core::option::Option +pub fn bitcoin_units::FeeRate::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::FeeRate::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::FeeRate::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::FeeRate::partial_cmp(&self, other: &bitcoin_units::FeeRate) -> core::option::Option +pub fn bitcoin_units::FeeRate::sub(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::sub(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::FeeRate::sub_assign(&mut self, rhs: &bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::sub_assign(&mut self, rhs: bitcoin_units::FeeRate) +pub fn bitcoin_units::FeeRate::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::FeeRate::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::MathOp::clone(&self) -> bitcoin_units::MathOp +pub fn bitcoin_units::MathOp::eq(&self, other: &bitcoin_units::MathOp) -> bool +pub fn bitcoin_units::MathOp::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::MathOp::is_addition(self) -> bool +pub fn bitcoin_units::MathOp::is_div_by_zero(self) -> bool +pub fn bitcoin_units::MathOp::is_multiplication(self) -> bool +pub fn bitcoin_units::MathOp::is_negation(self) -> bool +pub fn bitcoin_units::MathOp::is_overflow(self) -> bool +pub fn bitcoin_units::MathOp::is_subtraction(self) -> bool +pub fn bitcoin_units::NumOpError::clone(&self) -> bitcoin_units::NumOpError +pub fn bitcoin_units::NumOpError::eq(&self, other: &bitcoin_units::NumOpError) -> bool +pub fn bitcoin_units::NumOpError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::NumOpError::is_div_by_zero(self) -> bool +pub fn bitcoin_units::NumOpError::is_overflow(self) -> bool +pub fn bitcoin_units::NumOpError::operation(self) -> bitcoin_units::MathOp +pub fn bitcoin_units::NumOpResult::add(self, rhs: &T) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: Self) -> Self::Output +pub fn bitcoin_units::NumOpResult::add(self, rhs: T) -> Self::Output +pub fn bitcoin_units::NumOpResult::and_then(self, op: F) -> bitcoin_units::NumOpResult where F: core::ops::function::FnOnce(T) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::clone(&self) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::eq(&self, other: &bitcoin_units::NumOpResult) -> bool +pub fn bitcoin_units::NumOpResult::expect(self, msg: &str) -> T +pub fn bitcoin_units::NumOpResult::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::NumOpResult::into_result(self) -> core::result::Result +pub fn bitcoin_units::NumOpResult::is_error(&self) -> bool +pub fn bitcoin_units::NumOpResult::is_valid(&self) -> bool +pub fn bitcoin_units::NumOpResult::map U>(self, op: F) -> bitcoin_units::NumOpResult +pub fn bitcoin_units::NumOpResult::ok(self) -> core::option::Option +pub fn bitcoin_units::NumOpResult::sub(self, rhs: &T) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: Self) -> Self::Output +pub fn bitcoin_units::NumOpResult::sub(self, rhs: T) -> Self::Output +pub fn bitcoin_units::NumOpResult::unwrap(self) -> T +pub fn bitcoin_units::NumOpResult::unwrap_err(self) -> bitcoin_units::NumOpError +pub fn bitcoin_units::NumOpResult::unwrap_or(self, default: T) -> T +pub fn bitcoin_units::NumOpResult::unwrap_or_else(self, f: F) -> T where F: core::ops::function::FnOnce() -> T +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: &u64) +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: u64) +pub fn bitcoin_units::NumOpResult::from(a: &bitcoin_units::Amount) -> Self +pub fn bitcoin_units::NumOpResult::from(a: bitcoin_units::Amount) -> Self +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: &u64) +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: u64) +pub fn bitcoin_units::NumOpResult::rem(self, modulus: u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: &i64) +pub fn bitcoin_units::NumOpResult::div_assign(&mut self, rhs: i64) +pub fn bitcoin_units::NumOpResult::from(a: &bitcoin_units::SignedAmount) -> Self +pub fn bitcoin_units::NumOpResult::from(a: bitcoin_units::SignedAmount) -> Self +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: &i64) +pub fn bitcoin_units::NumOpResult::mul_assign(&mut self, rhs: i64) +pub fn bitcoin_units::NumOpResult::rem(self, modulus: i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::rem(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator> +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::NumOpResult::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::add(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::clone(&self) -> bitcoin_units::SignedAmount +pub fn bitcoin_units::SignedAmount::cmp(&self, other: &bitcoin_units::SignedAmount) -> core::cmp::Ordering +pub fn bitcoin_units::SignedAmount::default() -> Self +pub fn bitcoin_units::SignedAmount::display_dynamic(self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::SignedAmount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display +pub fn bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: &core::num::nonzero::NonZeroI64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: core::num::nonzero::NonZeroI64) -> Self::Output +pub fn bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::eq(&self, other: &bitcoin_units::SignedAmount) -> bool +pub fn bitcoin_units::SignedAmount::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::SignedAmount::from(value: bitcoin_units::Amount) -> Self +pub fn bitcoin_units::SignedAmount::from_int_btc>(whole_bitcoin: T) -> Self +pub fn bitcoin_units::SignedAmount::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_str_in(s: &str, denom: bitcoin_units::amount::Denomination) -> core::result::Result +pub fn bitcoin_units::SignedAmount::from_str_with_denomination(s: &str) -> core::result::Result +pub fn bitcoin_units::SignedAmount::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::SignedAmount::is_negative(self) -> bool +pub fn bitcoin_units::SignedAmount::is_positive(self) -> bool +pub fn bitcoin_units::SignedAmount::mul(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::mul(self, rhs: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::neg(self) -> Self::Output +pub fn bitcoin_units::SignedAmount::partial_cmp(&self, other: &bitcoin_units::SignedAmount) -> core::option::Option +pub fn bitcoin_units::SignedAmount::positive_sub(self, rhs: Self) -> core::option::Option +pub fn bitcoin_units::SignedAmount::rem(self, modulus: i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output +pub fn bitcoin_units::SignedAmount::signum(self) -> i64 +pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::SignedAmount::sub(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn bitcoin_units::SignedAmount::to_unsigned(self) -> core::result::Result +pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount +pub fn bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::add_assign(&mut self, rhs: &bitcoin_units::Weight) +pub fn bitcoin_units::Weight::add_assign(&mut self, rhs: bitcoin_units::Weight) +pub fn bitcoin_units::Weight::clone(&self) -> bitcoin_units::Weight +pub fn bitcoin_units::Weight::cmp(&self, other: &bitcoin_units::Weight) -> core::cmp::Ordering +pub fn bitcoin_units::Weight::div(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: &core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: core::num::nonzero::NonZeroU64) -> Self::Output +pub fn bitcoin_units::Weight::div(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::div_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::eq(&self, other: &bitcoin_units::Weight) -> bool +pub fn bitcoin_units::Weight::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::Weight::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::Weight::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: bitcoin_units::FeeRate) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn bitcoin_units::Weight::mul(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::mul_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::partial_cmp(&self, other: &bitcoin_units::Weight) -> core::option::Option +pub fn bitcoin_units::Weight::rem(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::rem(self, rhs: u64) -> Self::Output +pub fn bitcoin_units::Weight::rem_assign(&mut self, rhs: u64) +pub fn bitcoin_units::Weight::sub(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::sub(self, rhs: bitcoin_units::Weight) -> Self::Output +pub fn bitcoin_units::Weight::sub_assign(&mut self, rhs: &bitcoin_units::Weight) +pub fn bitcoin_units::Weight::sub_assign(&mut self, rhs: bitcoin_units::Weight) +pub fn bitcoin_units::Weight::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::Weight::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::Weight::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::amount::Denomination::clone(&self) -> bitcoin_units::amount::Denomination +pub fn bitcoin_units::amount::Denomination::eq(&self, other: &bitcoin_units::amount::Denomination) -> bool +pub fn bitcoin_units::amount::Denomination::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::Denomination::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::amount::Denomination::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::amount::Display::clone(&self) -> bitcoin_units::amount::Display +pub fn bitcoin_units::amount::Display::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::Display::show_denomination(self) -> Self +pub fn bitcoin_units::amount::InputTooLargeError::clone(&self) -> bitcoin_units::amount::InputTooLargeError +pub fn bitcoin_units::amount::InputTooLargeError::eq(&self, other: &bitcoin_units::amount::InputTooLargeError) -> bool +pub fn bitcoin_units::amount::InputTooLargeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::InvalidCharacterError::clone(&self) -> bitcoin_units::amount::InvalidCharacterError +pub fn bitcoin_units::amount::InvalidCharacterError::eq(&self, other: &bitcoin_units::amount::InvalidCharacterError) -> bool +pub fn bitcoin_units::amount::InvalidCharacterError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::MissingDenominationError::clone(&self) -> bitcoin_units::amount::MissingDenominationError +pub fn bitcoin_units::amount::MissingDenominationError::eq(&self, other: &bitcoin_units::amount::MissingDenominationError) -> bool +pub fn bitcoin_units::amount::MissingDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::MissingDigitsError::clone(&self) -> bitcoin_units::amount::MissingDigitsError +pub fn bitcoin_units::amount::MissingDigitsError::eq(&self, other: &bitcoin_units::amount::MissingDigitsError) -> bool +pub fn bitcoin_units::amount::MissingDigitsError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::OutOfRangeError::clone(&self) -> bitcoin_units::amount::OutOfRangeError +pub fn bitcoin_units::amount::OutOfRangeError::eq(&self, other: &bitcoin_units::amount::OutOfRangeError) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::OutOfRangeError::is_above_max(self) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::is_below_min(self) -> bool +pub fn bitcoin_units::amount::OutOfRangeError::valid_range(self) -> (i64, u64) +pub fn bitcoin_units::amount::ParseAmountError::clone(&self) -> bitcoin_units::amount::ParseAmountError +pub fn bitcoin_units::amount::ParseAmountError::eq(&self, other: &bitcoin_units::amount::ParseAmountError) -> bool +pub fn bitcoin_units::amount::ParseAmountError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseAmountError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::InputTooLargeError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::InvalidCharacterError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::MissingDigitsError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::OutOfRangeError) -> Self +pub fn bitcoin_units::amount::ParseAmountError::from(value: bitcoin_units::amount::TooPreciseError) -> Self +pub fn bitcoin_units::amount::ParseDenominationError::clone(&self) -> bitcoin_units::amount::ParseDenominationError +pub fn bitcoin_units::amount::ParseDenominationError::eq(&self, other: &bitcoin_units::amount::ParseDenominationError) -> bool +pub fn bitcoin_units::amount::ParseDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseDenominationError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::ParseError::clone(&self) -> bitcoin_units::amount::ParseError +pub fn bitcoin_units::amount::ParseError::eq(&self, other: &bitcoin_units::amount::ParseError) -> bool +pub fn bitcoin_units::amount::ParseError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::InputTooLargeError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::InvalidCharacterError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::MissingDigitsError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::OutOfRangeError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::ParseAmountError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::ParseDenominationError) -> Self +pub fn bitcoin_units::amount::ParseError::from(e: bitcoin_units::amount::TooPreciseError) -> Self +pub fn bitcoin_units::amount::ParseError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::clone(&self) -> bitcoin_units::amount::PossiblyConfusingDenominationError +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::eq(&self, other: &bitcoin_units::amount::PossiblyConfusingDenominationError) -> bool +pub fn bitcoin_units::amount::PossiblyConfusingDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::TooPreciseError::clone(&self) -> bitcoin_units::amount::TooPreciseError +pub fn bitcoin_units::amount::TooPreciseError::eq(&self, other: &bitcoin_units::amount::TooPreciseError) -> bool +pub fn bitcoin_units::amount::TooPreciseError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::amount::UnknownDenominationError::clone(&self) -> bitcoin_units::amount::UnknownDenominationError +pub fn bitcoin_units::amount::UnknownDenominationError::eq(&self, other: &bitcoin_units::amount::UnknownDenominationError) -> bool +pub fn bitcoin_units::amount::UnknownDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::checked_add(self, other: bitcoin_units::block::BlockHeightInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::clone(&self) -> bitcoin_units::block::BlockHeight +pub fn bitcoin_units::block::BlockHeight::cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockHeight::eq(&self, other: &bitcoin_units::block::BlockHeight) -> bool +pub fn bitcoin_units::block::BlockHeight::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeight::from(h: bitcoin_units::locktime::absolute::Height) -> Self +pub fn bitcoin_units::block::BlockHeight::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockHeight::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeight::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockHeight::partial_cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::option::Option +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeight) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeight) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeight::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::add_assign(&mut self, rhs: &bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::checked_add(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::clone(&self) -> bitcoin_units::block::BlockHeightInterval +pub fn bitcoin_units::block::BlockHeightInterval::cmp(&self, other: &bitcoin_units::block::BlockHeightInterval) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockHeightInterval::default() -> bitcoin_units::block::BlockHeightInterval +pub fn bitcoin_units::block::BlockHeightInterval::eq(&self, other: &bitcoin_units::block::BlockHeightInterval) -> bool +pub fn bitcoin_units::block::BlockHeightInterval::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockHeightInterval::from(h: bitcoin_units::locktime::relative::NumberOfBlocks) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockHeightInterval::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockHeightInterval::partial_cmp(&self, other: &bitcoin_units::block::BlockHeightInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockHeightInterval::sub(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::sub(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output +pub fn bitcoin_units::block::BlockHeightInterval::sub_assign(&mut self, rhs: &bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::sub_assign(&mut self, rhs: bitcoin_units::block::BlockHeightInterval) +pub fn bitcoin_units::block::BlockHeightInterval::sum>(iter: I) -> Self +pub fn bitcoin_units::block::BlockHeightInterval::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::block::BlockHeightInterval::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::checked_add(self, other: bitcoin_units::block::BlockMtpInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::clone(&self) -> bitcoin_units::block::BlockMtp +pub fn bitcoin_units::block::BlockMtp::cmp(&self, other: &bitcoin_units::block::BlockMtp) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockMtp::eq(&self, other: &bitcoin_units::block::BlockMtp) -> bool +pub fn bitcoin_units::block::BlockMtp::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockMtp::from(h: bitcoin_units::locktime::absolute::MedianTimePast) -> Self +pub fn bitcoin_units::block::BlockMtp::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockMtp::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtp::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockMtp::new(timestamps: [bitcoin_units::BlockTime; 11]) -> Self +pub fn bitcoin_units::block::BlockMtp::partial_cmp(&self, other: &bitcoin_units::block::BlockMtp) -> core::option::Option +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtp) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtp) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtp::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::add(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::add(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::add_assign(&mut self, rhs: &bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::checked_add(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::checked_sub(self, other: Self) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::clone(&self) -> bitcoin_units::block::BlockMtpInterval +pub fn bitcoin_units::block::BlockMtpInterval::cmp(&self, other: &bitcoin_units::block::BlockMtpInterval) -> core::cmp::Ordering +pub fn bitcoin_units::block::BlockMtpInterval::default() -> bitcoin_units::block::BlockMtpInterval +pub fn bitcoin_units::block::BlockMtpInterval::eq(&self, other: &bitcoin_units::block::BlockMtpInterval) -> bool +pub fn bitcoin_units::block::BlockMtpInterval::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::block::BlockMtpInterval::from(h: bitcoin_units::locktime::relative::NumberOf512Seconds) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::from(inner: u32) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::block::BlockMtpInterval::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::block::BlockMtpInterval::partial_cmp(&self, other: &bitcoin_units::block::BlockMtpInterval) -> core::option::Option +pub fn bitcoin_units::block::BlockMtpInterval::sub(self, rhs: &bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::sub(self, rhs: bitcoin_units::block::BlockMtpInterval) -> Self::Output +pub fn bitcoin_units::block::BlockMtpInterval::sub_assign(&mut self, rhs: &bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::sub_assign(&mut self, rhs: bitcoin_units::block::BlockMtpInterval) +pub fn bitcoin_units::block::BlockMtpInterval::sum>(iter: I) -> Self +pub fn bitcoin_units::block::BlockMtpInterval::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator +pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::block::TooBigForRelativeHeightError::clone(&self) -> bitcoin_units::block::TooBigForRelativeHeightError +pub fn bitcoin_units::block::TooBigForRelativeHeightError::eq(&self, other: &bitcoin_units::block::TooBigForRelativeHeightError) -> bool +pub fn bitcoin_units::block::TooBigForRelativeHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::ConversionError +pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool +pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::absolute::Height::eq(&self, other: &bitcoin_units::locktime::absolute::Height) -> bool +pub fn bitcoin_units::locktime::absolute::Height::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::Height::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height) -> bool +pub fn bitcoin_units::locktime::absolute::Height::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::option::Option +pub fn bitcoin_units::locktime::absolute::Height::try_from(h: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::clone(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::MedianTimePast::cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::absolute::MedianTimePast::eq(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::MedianTimePast::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::MedianTimePast::is_satisfied_by(self, time: bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::option::Option +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(h: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::ParseHeightError +pub fn bitcoin_units::locktime::absolute::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::ParseTimeError +pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::InvalidHeightError +pub fn bitcoin_units::locktime::relative::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidHeightError) -> bool +pub fn bitcoin_units::locktime::relative::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::InvalidTimeError +pub fn bitcoin_units::locktime::relative::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidTimeError) -> bool +pub fn bitcoin_units::locktime::relative::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::clone(&self) -> bitcoin_units::locktime::relative::NumberOf512Seconds +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::default() -> bitcoin_units::locktime::relative::NumberOf512Seconds +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::eq(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> bool +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::option::Option +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::clone(&self) -> bitcoin_units::locktime::relative::NumberOfBlocks +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::cmp::Ordering +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::default() -> bitcoin_units::locktime::relative::NumberOfBlocks +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::eq(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> bool +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from(value: u16) -> Self +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::option::Option +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(h: bitcoin_units::block::BlockHeightInterval) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::relative::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::TimeOverflowError +pub fn bitcoin_units::locktime::relative::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::TimeOverflowError) -> bool +pub fn bitcoin_units::locktime::relative::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::ParseIntError::as_ref(&self) -> &core::num::error::ParseIntError +pub fn bitcoin_units::parse::ParseIntError::clone(&self) -> bitcoin_units::parse::ParseIntError +pub fn bitcoin_units::parse::ParseIntError::eq(&self, other: &bitcoin_units::parse::ParseIntError) -> bool +pub fn bitcoin_units::parse::ParseIntError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::PrefixedHexError::clone(&self) -> bitcoin_units::parse::PrefixedHexError +pub fn bitcoin_units::parse::PrefixedHexError::eq(&self, other: &bitcoin_units::parse::PrefixedHexError) -> bool +pub fn bitcoin_units::parse::PrefixedHexError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::PrefixedHexError::from(e: bitcoin_units::parse::ParseIntError) -> Self +pub fn bitcoin_units::parse::PrefixedHexError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::parse::UnprefixedHexError::clone(&self) -> bitcoin_units::parse::UnprefixedHexError +pub fn bitcoin_units::parse::UnprefixedHexError::eq(&self, other: &bitcoin_units::parse::UnprefixedHexError) -> bool +pub fn bitcoin_units::parse::UnprefixedHexError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::parse::UnprefixedHexError::from(e: bitcoin_units::parse::ParseIntError) -> Self +pub fn bitcoin_units::parse::UnprefixedHexError::from(never: core::convert::Infallible) -> Self +pub fn bitcoin_units::parse::hex_check_unprefixed(s: &str) -> core::result::Result<&str, bitcoin_units::parse::UnprefixedHexError> +pub fn bitcoin_units::parse::hex_remove_prefix(s: &str) -> core::result::Result<&str, bitcoin_units::parse::PrefixedHexError> +pub fn bitcoin_units::parse::hex_u128(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_prefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_unchecked(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u128_unprefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result +pub fn bitcoin_units::parse::int_from_str(s: &str) -> core::result::Result +pub fn core::num::error::ParseIntError::from(value: bitcoin_units::parse::ParseIntError) -> Self +pub fn i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output +pub fn i64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn i64::mul(self, rhs: bitcoin_units::SignedAmount) -> Self::Output +pub fn u32::from(height: bitcoin_units::block::BlockHeight) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockHeightInterval) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockMtp) -> Self +pub fn u32::from(height: bitcoin_units::block::BlockMtpInterval) -> Self +pub fn u32::from(t: bitcoin_units::BlockTime) -> Self +pub fn u64::from(value: bitcoin_units::Weight) -> Self +pub fn u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output +pub fn u64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output +pub fn u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output +pub fn u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output +pub mod bitcoin_units +pub mod bitcoin_units::amount +pub mod bitcoin_units::block +pub mod bitcoin_units::fee +pub mod bitcoin_units::fee_rate +pub mod bitcoin_units::locktime +pub mod bitcoin_units::locktime::absolute +pub mod bitcoin_units::locktime::relative +pub mod bitcoin_units::parse +pub mod bitcoin_units::time +pub mod bitcoin_units::weight +pub struct bitcoin_units::Amount(_) +pub struct bitcoin_units::BlockHeight(_) +pub struct bitcoin_units::BlockHeightInterval(_) +pub struct bitcoin_units::BlockMtp(_) +pub struct bitcoin_units::BlockMtpInterval(_) +pub struct bitcoin_units::BlockTime(_) +pub struct bitcoin_units::FeeRate(_) +pub struct bitcoin_units::SignedAmount(_) +pub struct bitcoin_units::Weight(_) +pub struct bitcoin_units::amount::Amount(_) +pub struct bitcoin_units::amount::Display +pub struct bitcoin_units::amount::InputTooLargeError +pub struct bitcoin_units::amount::InvalidCharacterError +pub struct bitcoin_units::amount::MissingDigitsError +pub struct bitcoin_units::amount::OutOfRangeError +pub struct bitcoin_units::amount::ParseAmountError(_) +pub struct bitcoin_units::amount::ParseError(_) +pub struct bitcoin_units::amount::SignedAmount(_) +pub struct bitcoin_units::amount::TooPreciseError +pub struct bitcoin_units::block::BlockHeight(_) +pub struct bitcoin_units::block::BlockHeightInterval(_) +pub struct bitcoin_units::block::BlockMtp(_) +pub struct bitcoin_units::block::BlockMtpInterval(_) +pub struct bitcoin_units::block::TooBigForRelativeHeightError(_) +pub struct bitcoin_units::fee_rate::FeeRate(_) +pub struct bitcoin_units::locktime::absolute::Height(_) +pub struct bitcoin_units::locktime::absolute::MedianTimePast(_) +pub struct bitcoin_units::locktime::absolute::ParseHeightError(_) +pub struct bitcoin_units::locktime::absolute::ParseTimeError(_) +pub struct bitcoin_units::locktime::relative::InvalidHeightError +pub struct bitcoin_units::locktime::relative::InvalidTimeError +pub struct bitcoin_units::locktime::relative::NumberOf512Seconds(_) +pub struct bitcoin_units::locktime::relative::NumberOfBlocks(_) +pub struct bitcoin_units::locktime::relative::TimeOverflowError +pub struct bitcoin_units::parse::PrefixedHexError(_) +pub struct bitcoin_units::parse::UnprefixedHexError(_) +pub struct bitcoin_units::time::BlockTime(_) +pub struct bitcoin_units::weight::Weight(_) +pub trait bitcoin_units::CheckedSum: bitcoin_units::sealed::Sealed +pub trait bitcoin_units::parse::Integer: core::str::traits::FromStr + core::convert::TryFrom + core::marker::Sized + bitcoin_units::parse::sealed::Sealed +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >::Output +pub type &bitcoin_units::Amount::Output = >>::Output +pub type &bitcoin_units::Amount::Output = ::Output +pub type &bitcoin_units::FeeRate::Output = ::Output +pub type &bitcoin_units::FeeRate::Output = >>::Output +pub type &bitcoin_units::FeeRate::Output = >>::Output +pub type &bitcoin_units::FeeRate::Output = >::Output +pub type &bitcoin_units::FeeRate::Output = ::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type &bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = >::Output +pub type &bitcoin_units::SignedAmount::Output = >>::Output +pub type &bitcoin_units::SignedAmount::Output = ::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = >>::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = >>::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = >::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::Weight::Output = ::Output +pub type &bitcoin_units::block::BlockHeight::Output = >::Output +pub type &bitcoin_units::block::BlockHeight::Output = >::Output +pub type &bitcoin_units::block::BlockHeight::Output = ::Output +pub type &bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type &bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type &bitcoin_units::block::BlockMtp::Output = >::Output +pub type &bitcoin_units::block::BlockMtp::Output = >::Output +pub type &bitcoin_units::block::BlockMtp::Output = ::Output +pub type &bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type &bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type &i64::Output = >>::Output +pub type &i64::Output = >::Output +pub type &u64::Output = >::Output +pub type &u64::Output = >>::Output +pub type &u64::Output = >::Output +pub type bitcoin_units::Amount::Err = bitcoin_units::amount::ParseError +pub type bitcoin_units::Amount::Error = bitcoin_units::amount::OutOfRangeError +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >::Output +pub type bitcoin_units::Amount::Output = >>::Output +pub type bitcoin_units::Amount::Output = ::Output +pub type bitcoin_units::Amount::Output = bitcoin_units::Amount +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Amount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::FeeRate::Output = ::Output +pub type bitcoin_units::FeeRate::Output = >>::Output +pub type bitcoin_units::FeeRate::Output = >>::Output +pub type bitcoin_units::FeeRate::Output = >::Output +pub type bitcoin_units::FeeRate::Output = ::Output +pub type bitcoin_units::FeeRate::Output = bitcoin_units::FeeRate +pub type bitcoin_units::FeeRate::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Add>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Sub>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Div>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Rem>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>::Output +pub type bitcoin_units::NumOpResult::Output = as core::ops::arith::Mul>>::Output +pub type bitcoin_units::NumOpResult::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Err = bitcoin_units::amount::ParseError +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = >::Output +pub type bitcoin_units::SignedAmount::Output = >>::Output +pub type bitcoin_units::SignedAmount::Output = ::Output +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::SignedAmount::Output = bitcoin_units::SignedAmount +pub type bitcoin_units::Weight::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::Weight::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = >>::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = >>::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = >::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = ::Output +pub type bitcoin_units::Weight::Output = bitcoin_units::NumOpResult +pub type bitcoin_units::Weight::Output = bitcoin_units::Weight +pub type bitcoin_units::Weight::Output = u64 +pub type bitcoin_units::amount::Denomination::Err = bitcoin_units::amount::ParseDenominationError +pub type bitcoin_units::block::BlockHeight::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeight::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeight::Output = >::Output +pub type bitcoin_units::block::BlockHeight::Output = >::Output +pub type bitcoin_units::block::BlockHeight::Output = ::Output +pub type bitcoin_units::block::BlockHeight::Output = bitcoin_units::block::BlockHeight +pub type bitcoin_units::block::BlockHeight::Output = bitcoin_units::block::BlockHeightInterval +pub type bitcoin_units::block::BlockHeightInterval::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeightInterval::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type bitcoin_units::block::BlockHeightInterval::Output = ::Output +pub type bitcoin_units::block::BlockHeightInterval::Output = bitcoin_units::block::BlockHeightInterval +pub type bitcoin_units::block::BlockMtp::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtp::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtp::Output = >::Output +pub type bitcoin_units::block::BlockMtp::Output = >::Output +pub type bitcoin_units::block::BlockMtp::Output = ::Output +pub type bitcoin_units::block::BlockMtp::Output = bitcoin_units::block::BlockMtp +pub type bitcoin_units::block::BlockMtp::Output = bitcoin_units::block::BlockMtpInterval +pub type bitcoin_units::block::BlockMtpInterval::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtpInterval::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output +pub type bitcoin_units::block::BlockMtpInterval::Output = bitcoin_units::block::BlockMtpInterval +pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::ParseHeightError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ConversionError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ParseHeightError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ConversionError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::block::TooBigForRelativeHeightError +pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::parse::ParseIntError +pub type i64::Output = >>::Output +pub type i64::Output = >::Output +pub type i64::Output = bitcoin_units::NumOpResult +pub type u64::Output = >::Output +pub type u64::Output = >>::Output +pub type u64::Output = >::Output +pub type u64::Output = bitcoin_units::NumOpResult +pub type u64::Output = bitcoin_units::Weight diff --git a/contrib/check-for-api-changes.sh b/contrib/check-for-api-changes.sh index 3bfe415715..3299c3770a 100755 --- a/contrib/check-for-api-changes.sh +++ b/contrib/check-for-api-changes.sh @@ -9,7 +9,7 @@ set -euo pipefail REPO_DIR=$(git rev-parse --show-toplevel) API_DIR="$REPO_DIR/api" -NIGHTLY=$(cat nightly-version) +NIGHTLY=$(cat "$REPO_DIR/nightly-version") # Our docs have broken intra doc links if all features are not enabled. RUSTDOCFLAGS="-A rustdoc::broken_intra_doc_links" @@ -24,9 +24,7 @@ main() { need_nightly need_cargo_public_api - generate_api_files "hashes" - generate_api_files "io" - generate_api_files "primitives" + # Just check crates that are stabilising. generate_api_files "units" check_for_changes From 1f79241bdd776797c4b07b08b40cc5119910c081 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 15 Jul 2025 12:51:26 +1000 Subject: [PATCH 172/857] CI: Enable check-api for units We just re-introduced the `cargo public-api` output files for `units`. Bring back the CI job that runs the `contrib/check-for-api-changes.sh` script. --- .github/workflows/README.md | 9 +++++---- .github/workflows/rust.yml | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index f93b40cd1c..5dd3aeb894 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -28,7 +28,8 @@ Run from rust.yml unless stated otherwise. Unfortunately we are now exceeding th 14. `ASAN` 15. `WASM` 16. `Kani` -17. `Coveralls` - run by `coveralls.yml` -18. `release` - run by `release.yml` -19. `labeler` - run by `manage-pr.yml` -20. `Shellcheck` - run by `shellcheck.yml` +17. `API` +18. `Coveralls` - run by `coveralls.yml` +19. `release` - run by `release.yml` +20. `labeler` - run by `manage-pr.yml` +21. `Shellcheck` - run by `shellcheck.yml` diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ea83c99cbc..a795c60356 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -304,3 +304,21 @@ jobs: uses: model-checking/kani-github-action@v1.1 with: args: "--only-codegen" + + API: + needs: Prepare + name: API - nightly toolchain + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + steps: + - name: "Checkout repo" + uses: actions/checkout@v4 + - name: "Select toolchain" + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ needs.Prepare.outputs.nightly_version }} + - name: "Install cargo-public-api" + run: cargo install --locked cargo-public-api + - name: "Run API checker script" + run: ./contrib/check-for-api-changes.sh From d1f3976f4c2325b8c841fe5e4441ada58da30f91 Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Mon, 7 Jul 2025 22:09:07 -0500 Subject: [PATCH 173/857] Add Arbitrary impl for relative::LockTime --- primitives/src/locktime/relative.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index 5bb2dc1ab9..effcd882d3 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -7,6 +7,9 @@ use core::{convert, fmt}; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; + use internals::write_err; use crate::Sequence; @@ -517,6 +520,16 @@ impl std::error::Error for IsSatisfiedByTimeError { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for LockTime { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + match bool::arbitrary(u)? { + true => Ok(LockTime::Blocks(NumberOfBlocks::arbitrary(u)?)), + false => Ok(LockTime::Time(NumberOf512Seconds::arbitrary(u)?)) + } + } +} + #[cfg(test)] mod tests { use units::{BlockHeight, BlockTime}; From 453888a33c4f496f2309307a41a06667a4bc0637 Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Tue, 15 Jul 2025 21:48:17 -0500 Subject: [PATCH 174/857] Update NumOpResult arbitrary impl to only consume 1 byte of entropy --- units/src/result.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/units/src/result.rs b/units/src/result.rs index 18f968ea57..67c5b051a2 100644 --- a/units/src/result.rs +++ b/units/src/result.rs @@ -325,10 +325,9 @@ impl fmt::Display for MathOp { #[cfg(feature = "arbitrary")] impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for NumOpResult { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - let choice = u.int_in_range(0..=1)?; - match choice { - 0 => Ok(NumOpResult::Valid(T::arbitrary(u)?)), - _ => Ok(NumOpResult::Error(NumOpError(MathOp::arbitrary(u)?))), + match bool::arbitrary(u)? { + true => Ok(NumOpResult::Valid(T::arbitrary(u)?)), + false => Ok(NumOpResult::Error(NumOpError(MathOp::arbitrary(u)?))), } } } From 17dd64003b2f1dc8ad6ff47f7dbdf942731c3a90 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 3 Jul 2025 14:09:28 +1000 Subject: [PATCH 175/857] bitcoin: Add crate level public ext module Add a public `ext` module and re-export all the extension traits anonymously traits so users can use wildcard imports of form: `use bitcoin::ext::*;` If, for some reason, users want the name in scope they have to go to the module its defined in e.g., `use bitcoin::script::ScriptExt`. Update all files in the `examples` directory to use wildcard import, thereby verifying it all works as expected. --- bitcoin/examples/ecdsa-psbt-simple.rs | 3 +-- bitcoin/examples/ecdsa-psbt.rs | 3 +-- bitcoin/examples/sighash.rs | 2 +- bitcoin/examples/sign-tx-segwit-v0.rs | 3 +-- bitcoin/examples/sign-tx-taproot.rs | 3 +-- bitcoin/examples/taproot-psbt-simple.rs | 3 +-- bitcoin/examples/taproot-psbt.rs | 3 +-- bitcoin/src/lib.rs | 27 +++++++++++++++++++++++++ 8 files changed, 34 insertions(+), 13 deletions(-) diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs index 096a5a4f15..d5506c5b62 100644 --- a/bitcoin/examples/ecdsa-psbt-simple.rs +++ b/bitcoin/examples/ecdsa-psbt-simple.rs @@ -25,12 +25,11 @@ use std::collections::BTreeMap; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; +use bitcoin::ext::*; use bitcoin::key::WPubkeyHash; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; -use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{Secp256k1, Signing}; -use bitcoin::witness::WitnessExt as _; use bitcoin::{ consensus, transaction, Address, Amount, EcdsaSighashType, Network, OutPoint, Psbt, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, diff --git a/bitcoin/examples/ecdsa-psbt.rs b/bitcoin/examples/ecdsa-psbt.rs index 9d5520b044..67c86a592f 100644 --- a/bitcoin/examples/ecdsa-psbt.rs +++ b/bitcoin/examples/ecdsa-psbt.rs @@ -33,10 +33,9 @@ use std::fmt; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; use bitcoin::consensus::encode; -use bitcoin::consensus_validation::TransactionExt as _; +use bitcoin::ext::*; use bitcoin::locktime::absolute; use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType}; -use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; use bitcoin::{ transaction, Address, Amount, CompressedPublicKey, Network, OutPoint, ScriptBuf, Sequence, diff --git a/bitcoin/examples/sighash.rs b/bitcoin/examples/sighash.rs index 0374b66e8a..bd4a4e4ccb 100644 --- a/bitcoin/examples/sighash.rs +++ b/bitcoin/examples/sighash.rs @@ -1,4 +1,4 @@ -use bitcoin::script::{ScriptBufExt as _, ScriptExt as _}; +use bitcoin::ext::*; use bitcoin::{ consensus, ecdsa, sighash, Amount, CompressedPublicKey, Script, ScriptBuf, Transaction, }; diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs index eff851d226..7213db846b 100644 --- a/bitcoin/examples/sign-tx-segwit-v0.rs +++ b/bitcoin/examples/sign-tx-segwit-v0.rs @@ -3,11 +3,10 @@ //! Demonstrate creating a transaction that spends to and from p2wpkh outputs. use bitcoin::key::WPubkeyHash; +use bitcoin::ext::*; use bitcoin::locktime::absolute; -use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing}; use bitcoin::sighash::{EcdsaSighashType, SighashCache}; -use bitcoin::witness::WitnessExt as _; use bitcoin::{ transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index 167d9047d1..361c52609e 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -3,11 +3,10 @@ //! Demonstrate creating a transaction that spends to and from p2tr outputs. use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey}; +use bitcoin::ext::*; use bitcoin::locktime::absolute; -use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing, Verification}; use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType}; -use bitcoin::witness::WitnessExt as _; use bitcoin::{ transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index 4260c066cd..7e152bb7e5 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -23,12 +23,11 @@ use std::collections::BTreeMap; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPath, Xpriv, Xpub}; +use bitcoin::ext::*; use bitcoin::key::UntweakedPublicKey; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; -use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::{Secp256k1, Signing}; -use bitcoin::witness::WitnessExt as _; use bitcoin::{ consensus, transaction, Address, Amount, Network, OutPoint, Psbt, ScriptBuf, Sequence, TapLeafHash, TapSighashType, Transaction, TxIn, TxOut, Txid, Witness, XOnlyPublicKey, diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index e03723720c..ed149d5d98 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -79,11 +79,10 @@ use std::collections::BTreeMap; use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv, Xpub}; use bitcoin::consensus::encode; -use bitcoin::consensus_validation::TransactionExt as _; +use bitcoin::ext::*; use bitcoin::key::{TapTweak, XOnlyPublicKey}; use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP}; use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType}; -use bitcoin::script::{ScriptBufExt as _, ScriptExt as _}; use bitcoin::secp256k1::Secp256k1; use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType}; use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo}; diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index d305219262..d9689f6489 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -93,6 +93,33 @@ extern crate serde; mod internal_macros; +pub mod ext { + //! Re-export all the extension traits so downstream can use wildcard imports. + //! + //! As part of stabilizing `primitives` and `units` we created a bunch of extension traits in + //! `rust-bitcoin` to hold all then API that we are not yet ready to stabilize. This module + //! re-exports all of them to improve ergonomics for users comfortable with wildcard imports. + //! + //! # Examples + //! + //! ``` + //! // Wildcard import all of the extension crates. + //! use bitcoin::ext::*; + //! + //! // If, for some reason, you want the name to be in scope access it via the module. E.g. + //! use bitcoin::script::ScriptExt; + //! ``` + #[rustfmt::skip] // Use terse custom grouping. + pub use crate::{ + block::{BlockUncheckedExt as _, BlockCheckedExt as _, HeaderExt as _}, + pow::CompactTargetExt as _, + script::{ScriptExt as _, ScriptBufExt as _}, + transaction::{TxidExt as _, WtxidExt as _, OutPointExt as _, TxInExt as _, TxOutExt as _, TransactionExt as _}, + witness::WitnessExt as _, + }; + #[cfg(feature = "bitcoinconsensus")] + pub use crate::consensus_validation::{ScriptExt as _, TransactionExt as _}; +} #[macro_use] pub mod address; pub mod bip152; From 37eb78b809737647ec53dca1ce0b2a3423627bf6 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 10 Jul 2025 13:59:24 +1000 Subject: [PATCH 176/857] Remove amount serde traits Now that a `SignedAmount` can be infallibly converted to an `Amount` we do not need all the internal complexity in the `amount::serde` module, we can just de/serialize `SignedAmount` and convert it to `Amount`. This also has the advantage if someone has a type that is `Into` and `TryFrom` they can de/serialize it also - BOOM! Props to Kix for the idea. --- units/src/amount/serde.rs | 370 ++++++++++++++------------------- units/tests/data/serde_bincode | Bin 135 -> 133 bytes units/tests/serde.rs | 2 +- 3 files changed, 162 insertions(+), 210 deletions(-) diff --git a/units/src/amount/serde.rs b/units/src/amount/serde.rs index 4be7660581..93d75fdedc 100644 --- a/units/src/amount/serde.rs +++ b/units/src/amount/serde.rs @@ -25,43 +25,8 @@ #[cfg(feature = "alloc")] use core::fmt; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[cfg(feature = "alloc")] // This is because `to_float_in` uses `to_string`. -use super::Denomination; #[cfg(feature = "alloc")] use super::ParseAmountError; -use super::{Amount, SignedAmount}; - -/// This trait is used only to avoid code duplication and naming collisions -/// of the different serde serialization crates. -pub trait SerdeAmount: Copy + Sized { - fn ser_sat(self, s: S, _: private::Token) -> Result; - fn des_sat<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result; - #[cfg(feature = "alloc")] - fn ser_btc(self, s: S, _: private::Token) -> Result; - #[cfg(feature = "alloc")] - fn des_btc<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result; - #[cfg(feature = "alloc")] - fn ser_str(self, s: S, _: private::Token) -> Result; - #[cfg(feature = "alloc")] - fn des_str<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result; -} - -mod private { - /// Controls access to the trait methods. - pub struct Token; -} - -/// This trait is only for internal Amount type serialization/deserialization -pub trait SerdeAmountForOpt: Copy + Sized + SerdeAmount { - fn type_prefix(_: private::Token) -> &'static str; - fn ser_sat_opt(self, s: S, _: private::Token) -> Result; - #[cfg(feature = "alloc")] - fn ser_btc_opt(self, s: S, _: private::Token) -> Result; - #[cfg(feature = "alloc")] - fn ser_str_opt(self, s: S, _: private::Token) -> Result; -} #[cfg(feature = "alloc")] struct DisplayFullError(ParseAmountError); @@ -87,119 +52,41 @@ impl fmt::Display for DisplayFullError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } -impl SerdeAmount for Amount { - fn ser_sat(self, s: S, _: private::Token) -> Result { - u64::serialize(&self.to_sat(), s) - } - fn des_sat<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result { - use serde::de::Error; - Amount::from_sat(u64::deserialize(d)?).map_err(D::Error::custom) - } - #[cfg(feature = "alloc")] - fn ser_btc(self, s: S, _: private::Token) -> Result { - f64::serialize(&self.to_float_in(Denomination::Bitcoin), s) - } - #[cfg(feature = "alloc")] - fn des_btc<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result { - use serde::de::Error; - Amount::from_btc(f64::deserialize(d)?).map_err(DisplayFullError).map_err(D::Error::custom) - } - #[cfg(feature = "alloc")] - fn ser_str(self, s: S, _: private::Token) -> Result { - s.serialize_str(&self.to_string_in(Denomination::Bitcoin)) - } - #[cfg(feature = "alloc")] - fn des_str<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result { - use serde::de::Error; - let s: alloc::string::String = Deserialize::deserialize(d)?; - Amount::from_str_in(&s, Denomination::Bitcoin) - .map_err(DisplayFullError) - .map_err(D::Error::custom) - } -} - -impl SerdeAmountForOpt for Amount { - fn type_prefix(_: private::Token) -> &'static str { "u" } - fn ser_sat_opt(self, s: S, _: private::Token) -> Result { - s.serialize_some(&self.to_sat()) - } - #[cfg(feature = "alloc")] - fn ser_btc_opt(self, s: S, _: private::Token) -> Result { - s.serialize_some(&self.to_btc()) - } - #[cfg(feature = "alloc")] - fn ser_str_opt(self, s: S, _: private::Token) -> Result { - s.serialize_some(&self.to_string_in(Denomination::Bitcoin)) - } -} - -impl SerdeAmount for SignedAmount { - fn ser_sat(self, s: S, _: private::Token) -> Result { - i64::serialize(&self.to_sat(), s) - } - fn des_sat<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result { - use serde::de::Error; - SignedAmount::from_sat(i64::deserialize(d)?).map_err(D::Error::custom) - } - #[cfg(feature = "alloc")] - fn ser_btc(self, s: S, _: private::Token) -> Result { - f64::serialize(&self.to_float_in(Denomination::Bitcoin), s) - } - #[cfg(feature = "alloc")] - fn des_btc<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result { - use serde::de::Error; - SignedAmount::from_btc(f64::deserialize(d)?) - .map_err(DisplayFullError) - .map_err(D::Error::custom) - } - #[cfg(feature = "alloc")] - fn ser_str(self, s: S, _: private::Token) -> Result { - s.serialize_str(self.to_string_in(Denomination::Bitcoin).as_str()) - } - #[cfg(feature = "alloc")] - fn des_str<'d, D: Deserializer<'d>>(d: D, _: private::Token) -> Result { - use serde::de::Error; - let s: alloc::string::String = Deserialize::deserialize(d)?; - SignedAmount::from_str_in(&s, Denomination::Bitcoin) - .map_err(DisplayFullError) - .map_err(D::Error::custom) - } -} - -impl SerdeAmountForOpt for SignedAmount { - fn type_prefix(_: private::Token) -> &'static str { "i" } - fn ser_sat_opt(self, s: S, _: private::Token) -> Result { - s.serialize_some(&self.to_sat()) - } - #[cfg(feature = "alloc")] - fn ser_btc_opt(self, s: S, _: private::Token) -> Result { - s.serialize_some(&self.to_btc()) - } - #[cfg(feature = "alloc")] - fn ser_str_opt(self, s: S, _: private::Token) -> Result { - s.serialize_some(&self.to_string_in(Denomination::Bitcoin)) - } -} - pub mod as_sat { - //! Serialize and deserialize [`Amount`](crate::Amount) as real numbers denominated in satoshi. + //! Serialize and deserialize [`Amount`] and [`SignedAmount`] as real numbers denominated in satoshi. + //! //! Use with `#[serde(with = "amount::serde::as_sat")]`. + //! + //! [`Amount`]: crate::Amount + //! [`SignedAmount`]: crate::SignedAmount - use serde::{Deserializer, Serializer}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use super::private; - use crate::amount::serde::SerdeAmount; + use crate::SignedAmount; - pub fn serialize(a: &A, s: S) -> Result { - a.ser_sat(s, private::Token) + pub fn serialize(a: &A, s: S) -> Result + where + A: Into + Copy, + { + let amount: SignedAmount = (*a).into(); + i64::serialize(&amount.to_sat(), s) } - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result { - A::des_sat(d, private::Token) + pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result + where + A: TryFrom, >::Error: core::fmt::Display + { + let sat = i64::deserialize(d)?; + let amount = SignedAmount::from_sat(sat) + .map_err(serde::de::Error::custom)?; + + A::try_from(amount).map_err(serde::de::Error::custom) } pub mod opt { - //! Serialize and deserialize [`Option`](crate::Amount) as real numbers denominated in satoshi. + //! Serialize and deserialize `Option` and `Option` as real numbers + //! denominated in satoshi. + //! //! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`. use core::fmt; @@ -207,30 +94,36 @@ pub mod as_sat { use serde::{de, Deserializer, Serializer}; - use super::private; - use crate::amount::serde::SerdeAmountForOpt; + use crate::SignedAmount; #[allow(clippy::ref_option)] // API forced by serde. - pub fn serialize( - a: &Option, - s: S, - ) -> Result { + pub fn serialize(a: &Option, s: S) -> Result + where + A: Into + Copy, + { match *a { - Some(a) => a.ser_sat_opt(s, private::Token), + Some(a) => { + let amount: SignedAmount = a.into(); + s.serialize_some(&amount.to_sat()) + } None => s.serialize_none(), } } - pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>( - d: D, - ) -> Result, D::Error> { + pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result, D::Error> + where + A: TryFrom, >::Error: core::fmt::Display + { struct VisitOptAmt(PhantomData); - impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt { + impl<'de, X> de::Visitor<'de> for VisitOptAmt + where + X: TryFrom, >::Error: core::fmt::Display + { type Value = Option; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "an Option<{}64>", X::type_prefix(private::Token)) + write!(formatter, "an Option") } fn visit_none(self) -> Result @@ -239,11 +132,12 @@ pub mod as_sat { { Ok(None) } + fn visit_some(self, d: D) -> Result where D: Deserializer<'de>, { - Ok(Some(X::des_sat(d, private::Token)?)) + Ok(Some(super::deserialize(d)?)) } } d.deserialize_option(VisitOptAmt::(PhantomData)) @@ -253,51 +147,75 @@ pub mod as_sat { #[cfg(feature = "alloc")] pub mod as_btc { - //! Serialize and deserialize [`Amount`](crate::Amount) as JSON numbers denominated in BTC. + //! Serialize and deserialize [`Amount`] and [`SignedAmount`] as JSON numbers denominated in BTC. + //! //! Use with `#[serde(with = "amount::serde::as_btc")]`. + //! + //! [`Amount`]: crate::Amount + //! [`SignedAmount`]: crate::SignedAmount - use serde::{Deserializer, Serializer}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use super::private; - use crate::amount::serde::SerdeAmount; + use super::DisplayFullError; + use crate::amount::{Denomination, SignedAmount}; - pub fn serialize(a: &A, s: S) -> Result { - a.ser_btc(s, private::Token) + pub fn serialize(a: &A, s: S) -> Result + where + A: Into + Copy, + { + let amount: SignedAmount = (*a).into(); + f64::serialize(&amount.to_float_in(Denomination::Bitcoin), s) } - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result { - A::des_btc(d, private::Token) + pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result + where + A: TryFrom, >::Error: core::fmt::Display + { + let btc = f64::deserialize(d)?; + let amount = SignedAmount::from_btc(btc) + .map_err(DisplayFullError) + .map_err(serde::de::Error::custom)?; + + A::try_from(amount).map_err(serde::de::Error::custom) } pub mod opt { - //! Serialize and deserialize `Option` as JSON numbers denominated in BTC. + //! Serialize and deserialize `Option` and `Option` as JSON numbers + //! denominated in BTC. + //! //! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`. use core::fmt; use core::marker::PhantomData; - use serde::{de, Deserializer, Serializer}; + use serde::{de, Deserializer, Serialize, Serializer}; - use super::private; - use crate::amount::serde::SerdeAmountForOpt; + use crate::amount::{Denomination, SignedAmount}; #[allow(clippy::ref_option)] // API forced by serde. - pub fn serialize( - a: &Option, - s: S, - ) -> Result { + pub fn serialize(a: &Option, s: S) -> Result + where + A: Into + Copy, + { match *a { - Some(a) => a.ser_btc_opt(s, private::Token), + Some(a) => { + let amount: SignedAmount = a.into(); + f64::serialize(&amount.to_float_in(Denomination::Bitcoin), s) + } None => s.serialize_none(), } } - pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>( - d: D, - ) -> Result, D::Error> { + pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result, D::Error> + where + A: TryFrom, >::Error: core::fmt::Display + { struct VisitOptAmt(PhantomData); - impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt { + impl<'de, X> de::Visitor<'de> for VisitOptAmt + where + X: TryFrom, >::Error: core::fmt::Display + { type Value = Option; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -310,11 +228,12 @@ pub mod as_btc { { Ok(None) } + fn visit_some(self, d: D) -> Result where D: Deserializer<'de>, { - Ok(Some(X::des_btc(d, private::Token)?)) + Ok(Some(super::deserialize(d)?)) } } d.deserialize_option(VisitOptAmt::(PhantomData)) @@ -324,51 +243,81 @@ pub mod as_btc { #[cfg(feature = "alloc")] pub mod as_str { - //! Serialize and deserialize [`Amount`](crate::Amount) as a JSON string denominated in BTC. + //! Serialize and deserialize [`Amount`] and [`SignedAmount`] as a JSON string denominated in BTC. + //! //! Use with `#[serde(with = "amount::serde::as_str")]`. + //! + //! [`Amount`]: crate::Amount + //! [`SignedAmount`]: crate::SignedAmount + + use alloc::string::String; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + use super::DisplayFullError; + use crate::amount::{Denomination, SignedAmount}; + + pub fn serialize(a: &A, s: S) -> Result + where + A: Into + Copy, + { + let amount: SignedAmount = (*a).into(); + str::serialize(&amount.to_string_in(Denomination::Bitcoin), s) + } + + pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result + where + A: TryFrom, >::Error: core::fmt::Display + { + let btc = String::deserialize(d)?; + let amount = SignedAmount::from_str_in(&btc, Denomination::Bitcoin) + .map_err(DisplayFullError) + .map_err(serde::de::Error::custom)?; - use serde::{Deserializer, Serializer}; - - use super::private; - use crate::amount::serde::SerdeAmount; - - pub fn serialize(a: &A, s: S) -> Result { - a.ser_str(s, private::Token) - } - - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result { - A::des_str(d, private::Token) + A::try_from(amount).map_err(serde::de::Error::custom) } pub mod opt { - //! Serialize and deserialize `Option` as a JSON string denominated in BTC. + //! Serialize and deserialize `Option` and `Option` as a JSON string + //! denominated in BTC. + //! //! Use with `#[serde(default, with = "amount::serde::as_str::opt")]`. use core::fmt; use core::marker::PhantomData; - use serde::{de, Deserializer, Serializer}; + use serde::{de, Deserializer, Serialize, Serializer}; - use super::private; - use crate::amount::serde::SerdeAmountForOpt; + use crate::amount::{Denomination, SignedAmount}; #[allow(clippy::ref_option)] // API forced by serde. - pub fn serialize( + pub fn serialize( a: &Option, s: S, - ) -> Result { + ) -> Result + where + A: Into + Copy, + { match *a { - Some(a) => a.ser_str_opt(s, private::Token), + Some(a) => { + let amount: SignedAmount = a.into(); + str::serialize(&amount.to_string_in(Denomination::Bitcoin), s) + } None => s.serialize_none(), } } - pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>( + pub fn deserialize<'d, A, D: Deserializer<'d>>( d: D, - ) -> Result, D::Error> { + ) -> Result, D::Error> + where + A: TryFrom, >::Error: core::fmt::Display + { struct VisitOptAmt(PhantomData); - impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt { + impl<'de, X> de::Visitor<'de> for VisitOptAmt + where + X: TryFrom, >::Error: core::fmt::Display + { type Value = Option; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -381,11 +330,12 @@ pub mod as_str { { Ok(None) } + fn visit_some(self, d: D) -> Result where D: Deserializer<'de>, { - Ok(Some(X::des_str(d, private::Token)?)) + Ok(Some(super::deserialize(d)?)) } } d.deserialize_option(VisitOptAmt::(PhantomData)) @@ -395,14 +345,10 @@ pub mod as_str { #[cfg(test)] mod tests { - use super::*; - use crate::amount; - #[test] - fn sanity_check() { - assert_eq!(Amount::type_prefix(private::Token), "u"); - assert_eq!(SignedAmount::type_prefix(private::Token), "i"); - } + use serde::{Serialize, Deserialize}; + + use crate::amount::{self, Amount, SignedAmount}; #[test] fn can_serde_as_sat() { @@ -410,12 +356,14 @@ mod tests { pub struct HasAmount { #[serde(with = "amount::serde::as_sat")] pub amount: Amount, + #[serde(with = "amount::serde::as_sat")] + pub signed_amount: SignedAmount, } - let orig = HasAmount { amount: Amount::ONE_BTC }; + let orig = HasAmount { amount: Amount::ONE_BTC, signed_amount: SignedAmount::ONE_BTC }; let json = serde_json::to_string(&orig).expect("failed to ser"); - let want = "{\"amount\":100000000}"; + let want = "{\"amount\":100000000,\"signed_amount\":100000000}"; assert_eq!(json, want); let rinsed: HasAmount = serde_json::from_str(&json).expect("failed to deser"); @@ -429,12 +377,14 @@ mod tests { pub struct HasAmount { #[serde(with = "amount::serde::as_btc")] pub amount: Amount, + #[serde(with = "amount::serde::as_btc")] + pub signed_amount: SignedAmount, } - let orig = HasAmount { amount: Amount::ONE_BTC }; + let orig = HasAmount { amount: Amount::ONE_BTC, signed_amount: SignedAmount::ONE_BTC }; let json = serde_json::to_string(&orig).expect("failed to ser"); - let want = "{\"amount\":1.0}"; + let want = "{\"amount\":1.0,\"signed_amount\":1.0}"; assert_eq!(json, want); let rinsed: HasAmount = serde_json::from_str(&json).expect("failed to deser"); @@ -448,12 +398,14 @@ mod tests { pub struct HasAmount { #[serde(with = "amount::serde::as_str")] pub amount: Amount, + #[serde(with = "amount::serde::as_str")] + pub signed_amount: SignedAmount, } - let orig = HasAmount { amount: Amount::ONE_BTC }; + let orig = HasAmount { amount: Amount::ONE_BTC, signed_amount: SignedAmount::ONE_BTC }; let json = serde_json::to_string(&orig).expect("failed to ser"); - let want = "{\"amount\":\"1\"}"; + let want = "{\"amount\":\"1\",\"signed_amount\":\"1\"}"; assert_eq!(json, want); let rinsed: HasAmount = serde_json::from_str(&json).expect("failed to deser"); diff --git a/units/tests/data/serde_bincode b/units/tests/data/serde_bincode index 556b15cd794bd56e1ef82aa1bd0f4bf3642fd607..e3953e37975efdc782e87c15473f5e5891415e9f 100644 GIT binary patch delta 12 TcmZo?Y-OAvIZ;Y+qK!8I7q Date: Wed, 2 Jul 2025 13:37:53 +1000 Subject: [PATCH 177/857] primitives: Inline impl_to_hex_from_lower_hex and deprecate Macros are basically just a pain in the arse. This one is used to reduced code duplication/verbosity even thought the function can be written as a one-liner. Also calling macros across crate boundries is error prone and a constant source of maintenance grief. Note also: - The generated docs are quite general - `#[inline]` is missing - The docs on the macro are wrong in regards to the no-op Remove all calls to the macro from `primitives` and inline using terse syntax by way of the `format!` macro. Add `deprecated` attribute and direct users to just use `format!("{var:x}")` instead. --- primitives/src/pow.rs | 10 ++++++---- primitives/src/script/borrowed.rs | 12 ++++++++++++ primitives/src/script/mod.rs | 10 ++-------- primitives/src/script/owned.rs | 12 ++++++++++++ primitives/src/sequence.rs | 12 +++++++----- 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/primitives/src/pow.rs b/primitives/src/pow.rs index 7f01074842..abae9c6d41 100644 --- a/primitives/src/pow.rs +++ b/primitives/src/pow.rs @@ -30,16 +30,18 @@ impl CompactTarget { /// Returns the consensus encoded `u32` representation of this [`CompactTarget`]. #[inline] pub fn to_consensus(self) -> u32 { self.0 } + + /// Gets the hex representation of this [`CompactTarget`]. + #[cfg(feature = "alloc")] + #[inline] + #[deprecated(since = "TBD", note = "use `format!(\"{var:x}\")` instead")] + pub fn to_hex(self) -> alloc::string::String { alloc::format!("{:x}", self) } } impl fmt::LowerHex for CompactTarget { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } } -#[cfg(feature = "alloc")] -internals::impl_to_hex_from_lower_hex!(CompactTarget, |compact_target: &CompactTarget| { - 8 - compact_target.0.leading_zeros() as usize / 4 -}); impl fmt::UpperHex for CompactTarget { #[inline] diff --git a/primitives/src/script/borrowed.rs b/primitives/src/script/borrowed.rs index df4e2a3d1b..051bb76419 100644 --- a/primitives/src/script/borrowed.rs +++ b/primitives/src/script/borrowed.rs @@ -137,6 +137,18 @@ impl Script { let inner = unsafe { Box::from_raw(rw) }; ScriptBuf::from_bytes(Vec::from(inner)) } + + /// Gets the hex representation of this script. + /// + /// # Returns + /// + /// Just the script bytes in hexadecimal **not** consensus encoding of the script i.e., the + /// string will not include a length prefix. + #[cfg(feature = "alloc")] + #[cfg(feature = "hex")] + #[inline] + #[deprecated(since = "TBD", note = "use `format!(\"{var:x}\")` instead")] + pub fn to_hex(&self) -> alloc::string::String { alloc::format!("{:x}", self) } } #[cfg(feature = "arbitrary")] diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs index 5a5e6b60e2..0e656fcc84 100644 --- a/primitives/src/script/mod.rs +++ b/primitives/src/script/mod.rs @@ -436,18 +436,12 @@ impl fmt::LowerHex for Script { fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f) } } -#[cfg(feature = "alloc")] -#[cfg(feature = "hex")] -internals::impl_to_hex_from_lower_hex!(Script, |script: &Self| script.len() * 2); #[cfg(feature = "hex")] impl fmt::LowerHex for ScriptBuf { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_script(), f) } } -#[cfg(feature = "alloc")] -#[cfg(feature = "hex")] -internals::impl_to_hex_from_lower_hex!(ScriptBuf, |script_buf: &Self| script_buf.len() * 2); #[cfg(feature = "hex")] impl fmt::UpperHex for Script { @@ -942,7 +936,7 @@ mod tests { #[cfg(feature = "hex")] fn script_to_hex() { let script = Script::from_bytes(&[0xa1, 0xb2, 0xc3]); - let hex = script.to_hex(); + let hex = alloc::format!("{script:x}"); assert_eq!(hex, "a1b2c3"); } @@ -951,7 +945,7 @@ mod tests { #[cfg(feature = "hex")] fn scriptbuf_to_hex() { let script = ScriptBuf::from_bytes(vec![0xa1, 0xb2, 0xc3]); - let hex = script.to_hex(); + let hex = alloc::format!("{script:x}"); assert_eq!(hex, "a1b2c3"); } } diff --git a/primitives/src/script/owned.rs b/primitives/src/script/owned.rs index 70a3cbb874..c350b02f3e 100644 --- a/primitives/src/script/owned.rs +++ b/primitives/src/script/owned.rs @@ -111,6 +111,18 @@ impl ScriptBuf { /// It is guaranteed that `script.capacity() >= script.len()` always holds. #[inline] pub fn capacity(&self) -> usize { self.0.capacity() } + + /// Gets the hex representation of this script. + /// + /// # Returns + /// + /// Just the script bytes in hexadecimal **not** consensus encoding of the script i.e., the + /// string will not include a length prefix. + #[cfg(feature = "alloc")] + #[cfg(feature = "hex")] + #[inline] + #[deprecated(since = "TBD", note = "use `format!(\"{var:x}\")` instead")] + pub fn to_hex(&self) -> alloc::string::String { alloc::format!("{:x}", self) } } impl Deref for ScriptBuf { diff --git a/primitives/src/sequence.rs b/primitives/src/sequence.rs index ecad225dc5..a824a2049a 100644 --- a/primitives/src/sequence.rs +++ b/primitives/src/sequence.rs @@ -25,7 +25,7 @@ use units::parse::{self, PrefixedHexError, UnprefixedHexError}; use crate::locktime::relative; #[cfg(all(doc, feature = "alloc"))] -use crate::transaction::Transaction; +use crate::Transaction; /// Bitcoin transaction input sequence number. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -178,6 +178,12 @@ impl Sequence { #[inline] pub fn to_consensus_u32(self) -> u32 { self.0 } + /// Gets the hex representation of this [`Sequence`]. + #[cfg(feature = "alloc")] + #[inline] + #[deprecated(since = "TBD", note = "use `format!(\"{var:x}\")` instead")] + pub fn to_hex(self) -> alloc::string::String { alloc::format!("{:x}", self) } + /// Constructs a new [`relative::LockTime`] from this [`Sequence`] number. #[inline] pub fn to_relative_lock_time(self) -> Option { @@ -223,10 +229,6 @@ impl fmt::LowerHex for Sequence { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } } -#[cfg(feature = "alloc")] -internals::impl_to_hex_from_lower_hex!(Sequence, |sequence: &Sequence| { - 8 - sequence.0.leading_zeros() as usize / 4 -}); impl fmt::UpperHex for Sequence { #[inline] From eba12041cbeba1de3c71fdc83186dfb112dcae5b Mon Sep 17 00:00:00 2001 From: Luis Schwab Date: Fri, 18 Jul 2025 20:24:46 -0300 Subject: [PATCH 178/857] feat(p2p): create `NetworkExt` trait for default P2P port and network `Magic` values --- p2p/src/lib.rs | 3 +- p2p/src/network_ext.rs | 90 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 p2p/src/network_ext.rs diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index a430eafe7d..aff12e7d44 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -23,6 +23,7 @@ pub mod message_bloom; pub mod message_compact_blocks; pub mod message_filter; pub mod message_network; +mod network_ext; extern crate alloc; @@ -38,7 +39,7 @@ use io::{BufRead, Write}; #[rustfmt::skip] #[doc(inline)] -pub use self::address::Address; +pub use self::{address::Address, network_ext::NetworkExt}; /// Version of the protocol as appearing in network message headers. /// diff --git a/p2p/src/network_ext.rs b/p2p/src/network_ext.rs new file mode 100644 index 0000000000..b677f99da0 --- /dev/null +++ b/p2p/src/network_ext.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! This module implements an extension trait for [`Network`] +//! with getter methods for the default P2P port and default +//! network [`Magic`] bytes. + +use bitcoin::{Network, TestnetVersion}; + +use crate::Magic; + +/// Trait that extends [`Network`] by adding getter methods for the default P2P ports and [`Magic`] bytes. +pub trait NetworkExt { + /// The default P2P port for a given [`Network`]. + fn default_p2p_port(self) -> u16; + + /// The default network [`Magic`] for a given [`Network`]. + fn default_network_magic(self) -> Magic; +} + +impl NetworkExt for Network { + /// The default P2P port for a given [`Network`]. + /// + /// Note: All [`TestnetVersion`] variants >4 are treated as [`TestnetVersion::V4`]. + /// This function will be updated as new test networks are defined. + fn default_p2p_port(self) -> u16 { + match &self { + Network::Bitcoin => 8333, + Network::Signet => 38333, + Network::Testnet(TestnetVersion::V3) => 18333, + Network::Testnet(TestnetVersion::V4) => 48333, + Network::Testnet(_) => 48333, + Network::Regtest => 18444, + } + } + + /// The default network [`Magic`] for a given [`Network`]. + /// + /// Note: All [`TestnetVersion`] variants >4 are treated as [`TestnetVersion::V4`]. + /// This function will be updated as new test networks are defined. + fn default_network_magic(self) -> Magic { + match &self { + Network::Bitcoin => Magic::BITCOIN, + Network::Signet => Magic::SIGNET, + Network::Testnet(TestnetVersion::V3) => Magic::TESTNET3, + Network::Testnet(TestnetVersion::V4) => Magic::TESTNET4, + Network::Testnet(_) => Magic::TESTNET4, + Network::Regtest => Magic::REGTEST, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_p2p_port() { + let networks = [ + Network::Bitcoin, + Network::Signet, + Network::Testnet(TestnetVersion::V3), + Network::Testnet(TestnetVersion::V4), + Network::Regtest, + ]; + + let p2p_ports = vec![8333, 38333, 18333, 48333, 18444]; + + for (network, p2p_port) in networks.iter().zip(p2p_ports) { + assert_eq!(network.default_p2p_port(), p2p_port); + } + } + + #[test] + fn default_network_magic() { + let networks = [ + Network::Bitcoin, + Network::Signet, + Network::Testnet(TestnetVersion::V3), + Network::Testnet(TestnetVersion::V4), + Network::Regtest, + ]; + + let network_magics = + vec![Magic::BITCOIN, Magic::SIGNET, Magic::TESTNET3, Magic::TESTNET4, Magic::REGTEST]; + + for (network, network_magic) in networks.iter().zip(network_magics) { + assert_eq!(network.default_network_magic(), network_magic); + } + } +} From 2e18acc13963bf5ad4d11aafd185f10d10c018ab Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 20 Jul 2025 01:52:41 +0000 Subject: [PATCH 179/857] 2025-07-20 automated rustfmt nightly --- bitcoin/src/blockdata/block.rs | 3 +- bitcoin/src/blockdata/transaction.rs | 16 +++-------- bitcoin/src/network/mod.rs | 1 - bitcoin/tests/network.rs | 17 +++-------- primitives/src/locktime/relative.rs | 3 +- units/src/amount/serde.rs | 42 +++++++++++++++------------- units/src/amount/tests.rs | 19 +++---------- 7 files changed, 37 insertions(+), 64 deletions(-) diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index f74ebfb15b..3411a4a098 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -535,8 +535,7 @@ mod tests { use crate::pow::test_utils::{u128_to_work, u64_to_work}; use crate::script::ScriptBuf; use crate::transaction::{OutPoint, Transaction, TxIn, TxOut, Txid}; - use crate::{block, CompactTarget, Network, TestnetVersion}; - use crate::{Amount, Sequence, Witness}; + use crate::{block, Amount, CompactTarget, Network, Sequence, TestnetVersion, Witness}; #[test] fn static_vector() { diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 296dd213f7..3b1c19a90c 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1175,17 +1175,13 @@ impl Coinbase { /// /// This method does not validate that the transaction is actually a coinbase transaction. /// The caller must ensure that this transaction is indeed a valid coinbase transaction. - pub fn assume_coinbase(tx: Transaction) -> Self { - Self(tx) - } + pub fn assume_coinbase(tx: Transaction) -> Self { Self(tx) } /// Returns the first input of this coinbase transaction. /// /// This method is infallible because a valid coinbase transaction is guaranteed /// to have exactly one input. - pub fn first_input(&self) -> &TxIn { - &self.0.input[0] - } + pub fn first_input(&self) -> &TxIn { &self.0.input[0] } /// Returns a reference to the underlying transaction. /// @@ -1200,17 +1196,13 @@ impl Coinbase { pub fn into_transaction(self) -> Transaction { self.0 } /// Computes the [`Txid`] of this coinbase transaction. - pub fn compute_txid(&self) -> Txid { - self.0.compute_txid() - } + pub fn compute_txid(&self) -> Txid { self.0.compute_txid() } /// Returns the wtxid of this coinbase transaction. /// /// For coinbase transactions, this is always `Wtxid::COINBASE`. #[doc(alias = "compute_wtxid")] - pub const fn wtxid(&self) -> Wtxid { - Wtxid::COINBASE - } + pub const fn wtxid(&self) -> Wtxid { Wtxid::COINBASE } } mod sealed { diff --git a/bitcoin/src/network/mod.rs b/bitcoin/src/network/mod.rs index 6751117d86..214e95bd3d 100644 --- a/bitcoin/src/network/mod.rs +++ b/bitcoin/src/network/mod.rs @@ -59,7 +59,6 @@ pub enum TestnetVersion { V4, } - /// The cryptocurrency network to act on. /// /// This is an exhaustive enum, meaning that we cannot add any future networks without defining a diff --git a/bitcoin/tests/network.rs b/bitcoin/tests/network.rs index 025912d08f..921a29f061 100644 --- a/bitcoin/tests/network.rs +++ b/bitcoin/tests/network.rs @@ -5,9 +5,7 @@ use bitcoin::network::{Network, NetworkKind, TestnetVersion}; #[test] fn can_match_exhaustively_on_network() { // Returns true if `n` is mainnet. - fn is_mainnet(n: Network) -> bool { - matches!(n, Network::Bitcoin) - } + fn is_mainnet(n: Network) -> bool { matches!(n, Network::Bitcoin) } assert!(is_mainnet(Network::Bitcoin)); } @@ -15,9 +13,7 @@ fn can_match_exhaustively_on_network() { #[test] fn can_match_exhaustively_on_testnet() { // Returns true if `n` is any testnet. - fn is_testnet(n: Network) -> bool { - matches!(n, Network::Testnet(_)) - } + fn is_testnet(n: Network) -> bool { matches!(n, Network::Testnet(_)) } assert!(is_testnet(Network::Testnet(TestnetVersion::V3))); } @@ -25,21 +21,16 @@ fn can_match_exhaustively_on_testnet() { #[test] fn can_use_network_kind() { // Returns true if `n` is any mainnet. - fn is_mainnet(n: Network) -> bool { - NetworkKind::from(n).is_mainnet() - } + fn is_mainnet(n: Network) -> bool { NetworkKind::from(n).is_mainnet() } // Returns true if `n` is a any testnet. - fn is_testnet(n: Network) -> bool { - !NetworkKind::from(n).is_mainnet() - } + fn is_testnet(n: Network) -> bool { !NetworkKind::from(n).is_mainnet() } assert!(is_mainnet(Network::Bitcoin)); assert!(!is_testnet(Network::Bitcoin)); assert!(is_testnet(Network::Testnet(TestnetVersion::V3))); assert!(!is_mainnet(Network::Testnet(TestnetVersion::V3))); - } #[test] diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index effcd882d3..cdfcd82160 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -9,7 +9,6 @@ use core::{convert, fmt}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; - use internals::write_err; use crate::Sequence; @@ -525,7 +524,7 @@ impl<'a> Arbitrary<'a> for LockTime { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { match bool::arbitrary(u)? { true => Ok(LockTime::Blocks(NumberOfBlocks::arbitrary(u)?)), - false => Ok(LockTime::Time(NumberOf512Seconds::arbitrary(u)?)) + false => Ok(LockTime::Time(NumberOf512Seconds::arbitrary(u)?)), } } } diff --git a/units/src/amount/serde.rs b/units/src/amount/serde.rs index 93d75fdedc..76d8ad5999 100644 --- a/units/src/amount/serde.rs +++ b/units/src/amount/serde.rs @@ -74,11 +74,11 @@ pub mod as_sat { pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result where - A: TryFrom, >::Error: core::fmt::Display + A: TryFrom, + >::Error: core::fmt::Display, { let sat = i64::deserialize(d)?; - let amount = SignedAmount::from_sat(sat) - .map_err(serde::de::Error::custom)?; + let amount = SignedAmount::from_sat(sat).map_err(serde::de::Error::custom)?; A::try_from(amount).map_err(serde::de::Error::custom) } @@ -112,13 +112,15 @@ pub mod as_sat { pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result, D::Error> where - A: TryFrom, >::Error: core::fmt::Display + A: TryFrom, + >::Error: core::fmt::Display, { struct VisitOptAmt(PhantomData); impl<'de, X> de::Visitor<'de> for VisitOptAmt where - X: TryFrom, >::Error: core::fmt::Display + X: TryFrom, + >::Error: core::fmt::Display, { type Value = Option; @@ -169,7 +171,8 @@ pub mod as_btc { pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result where - A: TryFrom, >::Error: core::fmt::Display + A: TryFrom, + >::Error: core::fmt::Display, { let btc = f64::deserialize(d)?; let amount = SignedAmount::from_btc(btc) @@ -208,13 +211,15 @@ pub mod as_btc { pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result, D::Error> where - A: TryFrom, >::Error: core::fmt::Display + A: TryFrom, + >::Error: core::fmt::Display, { struct VisitOptAmt(PhantomData); impl<'de, X> de::Visitor<'de> for VisitOptAmt where - X: TryFrom, >::Error: core::fmt::Display + X: TryFrom, + >::Error: core::fmt::Display, { type Value = Option; @@ -251,6 +256,7 @@ pub mod as_str { //! [`SignedAmount`]: crate::SignedAmount use alloc::string::String; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; use super::DisplayFullError; @@ -266,7 +272,8 @@ pub mod as_str { pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result where - A: TryFrom, >::Error: core::fmt::Display + A: TryFrom, + >::Error: core::fmt::Display, { let btc = String::deserialize(d)?; let amount = SignedAmount::from_str_in(&btc, Denomination::Bitcoin) @@ -290,10 +297,7 @@ pub mod as_str { use crate::amount::{Denomination, SignedAmount}; #[allow(clippy::ref_option)] // API forced by serde. - pub fn serialize( - a: &Option, - s: S, - ) -> Result + pub fn serialize(a: &Option, s: S) -> Result where A: Into + Copy, { @@ -306,17 +310,17 @@ pub mod as_str { } } - pub fn deserialize<'d, A, D: Deserializer<'d>>( - d: D, - ) -> Result, D::Error> + pub fn deserialize<'d, A, D: Deserializer<'d>>(d: D) -> Result, D::Error> where - A: TryFrom, >::Error: core::fmt::Display + A: TryFrom, + >::Error: core::fmt::Display, { struct VisitOptAmt(PhantomData); impl<'de, X> de::Visitor<'de> for VisitOptAmt where - X: TryFrom, >::Error: core::fmt::Display + X: TryFrom, + >::Error: core::fmt::Display, { type Value = Option; @@ -346,7 +350,7 @@ pub mod as_str { #[cfg(test)] mod tests { - use serde::{Serialize, Deserialize}; + use serde::{Deserialize, Serialize}; use crate::amount::{self, Amount, SignedAmount}; diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 1e55219e58..110977d166 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -847,19 +847,11 @@ fn sum_amounts() { assert_eq!(empty.into_iter().sum::>(), NumOpResult::Valid(SignedAmount::ZERO)); let amounts = [sat(42), sat(1337), sat(21)]; - let sum = amounts - .into_iter() - .map(NumOpResult::from) - .sum::>() - .unwrap(); + let sum = amounts.into_iter().map(NumOpResult::from).sum::>().unwrap(); assert_eq!(sum, sat(1400)); let amounts = [Amount::MAX_MONEY, sat(1337), sat(21)]; - assert!(amounts - .into_iter() - .map(NumOpResult::from) - .sum::>() - .is_error()); + assert!(amounts.into_iter().map(NumOpResult::from).sum::>().is_error()); let amounts = [SignedAmount::MIN, ssat(-1), ssat(21)]; assert!(amounts @@ -876,11 +868,8 @@ fn sum_amounts() { .is_error()); let amounts = [ssat(42), ssat(3301), ssat(21)]; - let sum = amounts - .into_iter() - .map(NumOpResult::from) - .sum::>() - .unwrap(); + let sum = + amounts.into_iter().map(NumOpResult::from).sum::>().unwrap(); assert_eq!(sum, ssat(3364)); } From 2db884f09201e27b6d9eec799e0c43af1807da36 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 9 Jul 2025 13:30:26 +1000 Subject: [PATCH 180/857] Use Self in script Builder The `builder` module is more maintainable if we use `Self` instead of explicitly using `Builder`. Done in preparation for adding script tagging. --- bitcoin/src/blockdata/script/builder.rs | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/bitcoin/src/blockdata/script/builder.rs b/bitcoin/src/blockdata/script/builder.rs index e68ac43a69..58f89c4c0f 100644 --- a/bitcoin/src/blockdata/script/builder.rs +++ b/bitcoin/src/blockdata/script/builder.rs @@ -20,12 +20,12 @@ pub struct Builder(ScriptBuf, Option); impl Builder { /// Constructs a new empty script. #[inline] - pub const fn new() -> Self { Builder(ScriptBuf::new(), None) } + pub const fn new() -> Self { Self(ScriptBuf::new(), None) } /// Constructs a new empty script builder with at least the specified capacity. #[inline] pub fn with_capacity(capacity: usize) -> Self { - Builder(ScriptBuf::with_capacity(capacity), None) + Self(ScriptBuf::with_capacity(capacity), None) } /// Returns the length in bytes of the script. @@ -42,7 +42,7 @@ impl Builder { /// # Errors /// /// Only errors if `data == i32::MIN` (CScriptNum cannot have value -2^31). - pub fn push_int(self, n: i32) -> Result { + pub fn push_int(self, n: i32) -> Result { if n == i32::MIN { // ref: https://github.com/bitcoin/bitcoin/blob/cac846c2fbf6fc69bfc288fd387aa3f68d84d584/src/script/script.h#L230 Err(Error::NumericOverflow) @@ -66,7 +66,7 @@ impl Builder { /// > throwing an exception if arithmetic is done or the result is interpreted as an integer. /// /// Does not check whether `n` is in the range of [-2^31 +1...2^31 -1]. - pub fn push_int_unchecked(self, n: i64) -> Builder { + pub fn push_int_unchecked(self, n: i64) -> Self { match n { -1 => self.push_opcode(OP_PUSHNUM_NEG1), 0 => self.push_opcode(OP_PUSHBYTES_0), @@ -78,14 +78,14 @@ impl Builder { /// Adds instructions to push an integer onto the stack without optimization. /// /// This uses the explicit encoding regardless of the availability of dedicated opcodes. - pub(in crate::blockdata) fn push_int_non_minimal(self, data: i64) -> Builder { + pub(in crate::blockdata) fn push_int_non_minimal(self, data: i64) -> Self { let mut buf = [0u8; 8]; let len = write_scriptint(&mut buf, data); self.push_slice_non_minimal(&<&PushBytes>::from(&buf)[..len]) } /// Adds instructions to push some arbitrary data onto the stack. - pub fn push_slice>(self, data: T) -> Builder { + pub fn push_slice>(self, data: T) -> Self { let bytes = data.as_ref().as_bytes(); if bytes.len() == 1 && (bytes[0] == 0x81 || bytes[0] <= 16) { match bytes[0] { @@ -104,14 +104,14 @@ impl Builder { /// Standardness rules require push minimality according to [CheckMinimalPush] of core. /// /// [CheckMinimalPush]: - pub fn push_slice_non_minimal>(mut self, data: T) -> Builder { + pub fn push_slice_non_minimal>(mut self, data: T) -> Self { self.0.push_slice_non_minimal(data); self.1 = None; self } /// Adds a single opcode to the script. - pub fn push_opcode(mut self, data: Opcode) -> Builder { + pub fn push_opcode(mut self, data: Opcode) -> Self { self.0.push_opcode(data); self.1 = Some(data); self @@ -127,7 +127,7 @@ impl Builder { /// Note that existing `OP_*VERIFY` opcodes do not lead to the instruction being ignored /// because `OP_VERIFY` consumes an item from the stack so ignoring them would change the /// semantics. - pub fn push_verify(mut self) -> Builder { + pub fn push_verify(mut self) -> Self { // "duplicated code" because we need to update `1` field match opcode_to_verify(self.1) { Some(opcode) => { @@ -139,7 +139,7 @@ impl Builder { } /// Adds instructions to push a public key onto the stack. - pub fn push_key(self, key: PublicKey) -> Builder { + pub fn push_key(self, key: PublicKey) -> Self { if key.compressed { self.push_slice(key.inner.serialize()) } else { @@ -148,12 +148,12 @@ impl Builder { } /// Adds instructions to push an XOnly public key onto the stack. - pub fn push_x_only_key(self, x_only_key: XOnlyPublicKey) -> Builder { + pub fn push_x_only_key(self, x_only_key: XOnlyPublicKey) -> Self { self.push_slice(x_only_key.serialize()) } /// Adds instructions to push an absolute lock time onto the stack. - pub fn push_lock_time(self, lock_time: absolute::LockTime) -> Builder { + pub fn push_lock_time(self, lock_time: absolute::LockTime) -> Self { self.push_int_unchecked(lock_time.to_consensus_u32().into()) } @@ -161,7 +161,7 @@ impl Builder { /// /// This is used when creating scripts that use CHECKSEQUENCEVERIFY (CSV) to enforce /// relative time locks. - pub fn push_relative_lock_time(self, lock_time: relative::LockTime) -> Builder { + pub fn push_relative_lock_time(self, lock_time: relative::LockTime) -> Self { self.push_int_unchecked(lock_time.to_consensus_u32().into()) } @@ -177,7 +177,7 @@ impl Builder { since = "TBD", note = "Use push_relative_lock_time instead for working with timelocks in scripts" )] - pub fn push_sequence(self, sequence: Sequence) -> Builder { + pub fn push_sequence(self, sequence: Sequence) -> Self { self.push_int_unchecked(sequence.to_consensus_u32().into()) } @@ -195,15 +195,15 @@ impl Builder { } impl Default for Builder { - fn default() -> Builder { Builder::new() } + fn default() -> Self { Self::new() } } /// Constructs a new builder from an existing vector. impl From> for Builder { - fn from(v: Vec) -> Builder { + fn from(v: Vec) -> Self { let script = ScriptBuf::from(v); let last_op = script.last_opcode(); - Builder(script, last_op) + Self(script, last_op) } } From ae1c0ed60bacf36df939aa9a8ab16b166bae0a55 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 9 Jul 2025 13:37:59 +1000 Subject: [PATCH 181/857] script: Remove public re-exports By convention we do not re-export things from modules where they are used. Also the `borrowed` and `owned` modules are private so these public re-exports make no sense. FTR users can do both of these already - `use bitcoin::script::{Script, ScriptBuf};` - `use bitcoin::{Script, ScriptBuf};` --- bitcoin/src/blockdata/script/borrowed.rs | 6 +----- bitcoin/src/blockdata/script/owned.rs | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 1d3cf2ccb9..d4352700be 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -10,7 +10,7 @@ use secp256k1::{Secp256k1, Verification}; use super::witness_version::WitnessVersion; use super::{ Builder, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScriptSizeError, - ScriptHash, WScriptHash, WitnessScriptSizeError, + Script, ScriptHash, WScriptHash, WitnessScriptSizeError, }; use crate::consensus::{self, Encodable}; use crate::key::{PublicKey, UntweakedPublicKey, WPubkeyHash}; @@ -22,10 +22,6 @@ use crate::script::{self, ScriptBufExt as _}; use crate::taproot::{LeafVersion, TapLeafHash, TapNodeHash}; use crate::{Amount, FeeRate, ScriptBuf}; -#[rustfmt::skip] // Keep public re-exports separate. -#[doc(inline)] -pub use primitives::script::Script; - crate::internal_macros::define_extension_trait! { /// Extension functionality for the [`Script`] type. pub trait ScriptExt impl for Script { diff --git a/bitcoin/src/blockdata/script/owned.rs b/bitcoin/src/blockdata/script/owned.rs index 1e313da32b..ec186c9adb 100644 --- a/bitcoin/src/blockdata/script/owned.rs +++ b/bitcoin/src/blockdata/script/owned.rs @@ -7,7 +7,7 @@ use hex::FromHex as _; use internals::ToU64 as _; use secp256k1::{Secp256k1, Verification}; -use super::{opcode_to_verify, Builder, Instruction, PushBytes, ScriptExtPriv as _}; +use super::{opcode_to_verify, Builder, Instruction, PushBytes, ScriptBuf, ScriptExtPriv as _}; use crate::consensus; use crate::key::{ PubkeyHash, PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, WPubkeyHash, @@ -20,10 +20,6 @@ use crate::script::witness_version::WitnessVersion; use crate::script::{self, ScriptHash, WScriptHash}; use crate::taproot::TapNodeHash; -#[rustfmt::skip] // Keep public re-exports separate. -#[doc(inline)] -pub use primitives::script::ScriptBuf; - crate::internal_macros::define_extension_trait! { /// Extension functionality for the [`ScriptBuf`] type. pub trait ScriptBufExt impl for ScriptBuf { From a795e6dcb46fb9a4674184f06618b6a643702a62 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 9 Jul 2025 09:28:21 +1000 Subject: [PATCH 182/857] fuzz: Use script Display `Sritp::fmt_asm` is deprecated, use `Display` instead. --- fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs b/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs index db021a76db..bea9fc10ba 100644 --- a/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs +++ b/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs @@ -1,6 +1,5 @@ -use std::fmt; +use std::fmt::{self, Write as _}; -use bitcoin::script::ScriptExt as _; use honggfuzz::fuzz; // faster than String, we don't need to actually produce the value, just check absence of panics @@ -14,7 +13,8 @@ impl fmt::Write for NullWriter { fn do_test(data: &[u8]) { let mut writer = NullWriter; - bitcoin::Script::from_bytes(data).fmt_asm(&mut writer).unwrap(); + let script = bitcoin::Script::from_bytes(data); + write!(writer, "{script}").unwrap(); } fn main() { From 180dcdc9d0c24d091029dc19cd0bb1f9d64cf31e Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Sat, 19 Jul 2025 09:37:11 -0500 Subject: [PATCH 183/857] Update fuzz script to include `arbitrary` and `p2p` as a dependency `arbitrary` is necessary to use the impls from the `bitcoin` crate's `arbitrary` feature, and it seems like `p2p` was added to the Cargo.toml instead of to the file generation script and then generated. The changes to the order of the binary targets are just a result of running the generation script again. --- .github/workflows/cron-daily-fuzz.yml | 4 ++-- Cargo-minimal.lock | 1 + Cargo-recent.lock | 1 + fuzz/Cargo.toml | 28 ++++++++++++++------------- fuzz/fuzz-util.sh | 4 ++++ fuzz/generate-files.sh | 6 ++++-- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/.github/workflows/cron-daily-fuzz.yml b/.github/workflows/cron-daily-fuzz.yml index d3ab431e15..a32f576039 100644 --- a/.github/workflows/cron-daily-fuzz.yml +++ b/.github/workflows/cron-daily-fuzz.yml @@ -18,6 +18,7 @@ jobs: # We only get 20 jobs at a time, we probably don't want to go # over that limit with fuzzing because of the hour run time. fuzz_target: [ + bitcoin_deser_net_msg, bitcoin_deserialize_address, bitcoin_deserialize_block, bitcoin_deserialize_prefilled_transaction, @@ -25,7 +26,6 @@ jobs: bitcoin_deserialize_script, bitcoin_deserialize_transaction, bitcoin_deserialize_witness, - bitcoin_deser_net_msg, bitcoin_outpoint_string, bitcoin_p2p_address_roundtrip, bitcoin_script_bytes_to_asm_fmt, @@ -33,8 +33,8 @@ jobs: hashes_ripemd160, hashes_sha1, hashes_sha256, - hashes_sha512_256, hashes_sha512, + hashes_sha512_256, units_deserialize_amount, ] steps: diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 63d43f9197..06fb66468a 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -76,6 +76,7 @@ version = "0.0.0" name = "bitcoin-fuzz" version = "0.0.1" dependencies = [ + "arbitrary", "bitcoin", "bitcoin-p2p-messages", "honggfuzz", diff --git a/Cargo-recent.lock b/Cargo-recent.lock index fcf5c2cc3c..0953c57d9e 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -75,6 +75,7 @@ version = "0.0.0" name = "bitcoin-fuzz" version = "0.0.1" dependencies = [ + "arbitrary", "bitcoin", "bitcoin-p2p-messages", "honggfuzz", diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 5cf7898410..a513571b8f 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bitcoin-fuzz" edition = "2021" +rust-version = "1.63.0" version = "0.0.1" authors = ["Generated by fuzz/generate-files.sh"] publish = false @@ -10,8 +11,9 @@ cargo-fuzz = true [dependencies] honggfuzz = { version = "0.5.56", default-features = false } -bitcoin = { path = "../bitcoin", features = [ "serde" ] } +bitcoin = { path = "../bitcoin", features = [ "serde", "arbitrary" ] } p2p = { path = "../p2p", package = "bitcoin-p2p-messages" } +arbitrary = { version = "1.4" } serde = { version = "1.0.103", features = [ "derive" ] } serde_json = "1.0" @@ -19,6 +21,10 @@ serde_json = "1.0" [lints.rust] unexpected_cfgs = { level = "deny", check-cfg = ['cfg(fuzzing)'] } +[[bin]] +name = "bitcoin_deser_net_msg" +path = "fuzz_targets/bitcoin/deser_net_msg.rs" + [[bin]] name = "bitcoin_deserialize_address" path = "fuzz_targets/bitcoin/deserialize_address.rs" @@ -47,14 +53,14 @@ path = "fuzz_targets/bitcoin/deserialize_transaction.rs" name = "bitcoin_deserialize_witness" path = "fuzz_targets/bitcoin/deserialize_witness.rs" -[[bin]] -name = "bitcoin_deser_net_msg" -path = "fuzz_targets/bitcoin/deser_net_msg.rs" - [[bin]] name = "bitcoin_outpoint_string" path = "fuzz_targets/bitcoin/outpoint_string.rs" +[[bin]] +name = "bitcoin_p2p_address_roundtrip" +path = "fuzz_targets/bitcoin/p2p_address_roundtrip.rs" + [[bin]] name = "bitcoin_script_bytes_to_asm_fmt" path = "fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs" @@ -75,18 +81,14 @@ path = "fuzz_targets/hashes/sha1.rs" name = "hashes_sha256" path = "fuzz_targets/hashes/sha256.rs" -[[bin]] -name = "hashes_sha512_256" -path = "fuzz_targets/hashes/sha512_256.rs" - [[bin]] name = "hashes_sha512" path = "fuzz_targets/hashes/sha512.rs" [[bin]] -name = "units_deserialize_amount" -path = "fuzz_targets/units/deserialize_amount.rs" +name = "hashes_sha512_256" +path = "fuzz_targets/hashes/sha512_256.rs" [[bin]] -name = "bitcoin_p2p_address_roundtrip" -path = "fuzz_targets/bitcoin/p2p_address_roundtrip.rs" +name = "units_deserialize_amount" +path = "fuzz_targets/units/deserialize_amount.rs" diff --git a/fuzz/fuzz-util.sh b/fuzz/fuzz-util.sh index 759d41c4d6..0b3cd82b98 100755 --- a/fuzz/fuzz-util.sh +++ b/fuzz/fuzz-util.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +# Sort order is affected by locale. See `man sort`. +# > Set LC_ALL=C to get the traditional sort order that uses native byte values. +export LC_ALL=C + REPO_DIR=$(git rev-parse --show-toplevel) listTargetFiles() { diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh index e85f20ed54..1d509bc5f9 100755 --- a/fuzz/generate-files.sh +++ b/fuzz/generate-files.sh @@ -22,8 +22,10 @@ publish = false cargo-fuzz = true [dependencies] -honggfuzz = { version = "0.5.55", default-features = false } -bitcoin = { path = "../bitcoin", features = [ "serde" ] } +honggfuzz = { version = "0.5.56", default-features = false } +bitcoin = { path = "../bitcoin", features = [ "serde", "arbitrary" ] } +p2p = { path = "../p2p", package = "bitcoin-p2p-messages" } +arbitrary = { version = "1.4" } serde = { version = "1.0.103", features = [ "derive" ] } serde_json = "1.0" From 66f7a0a51eb74eb9bc1ac18a90948032520f38c0 Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Mon, 21 Jul 2025 19:03:49 -0500 Subject: [PATCH 184/857] Rename `deserialize_amount` to `parse_amount` --- .github/workflows/cron-daily-fuzz.yml | 2 +- fuzz/Cargo.toml | 4 ++-- .../units/{deserialize_amount.rs => parse_amount.rs} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename fuzz/fuzz_targets/units/{deserialize_amount.rs => parse_amount.rs} (100%) diff --git a/.github/workflows/cron-daily-fuzz.yml b/.github/workflows/cron-daily-fuzz.yml index a32f576039..b55ca520f0 100644 --- a/.github/workflows/cron-daily-fuzz.yml +++ b/.github/workflows/cron-daily-fuzz.yml @@ -35,7 +35,7 @@ jobs: hashes_sha256, hashes_sha512, hashes_sha512_256, - units_deserialize_amount, + units_parse_amount, ] steps: - name: Install test dependencies diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index a513571b8f..e2e955e633 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -90,5 +90,5 @@ name = "hashes_sha512_256" path = "fuzz_targets/hashes/sha512_256.rs" [[bin]] -name = "units_deserialize_amount" -path = "fuzz_targets/units/deserialize_amount.rs" +name = "units_parse_amount" +path = "fuzz_targets/units/parse_amount.rs" diff --git a/fuzz/fuzz_targets/units/deserialize_amount.rs b/fuzz/fuzz_targets/units/parse_amount.rs similarity index 100% rename from fuzz/fuzz_targets/units/deserialize_amount.rs rename to fuzz/fuzz_targets/units/parse_amount.rs From ca344e6d0f2d832bd3fb8dd213e24d2bdd5ff4ec Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Sun, 20 Jul 2025 13:09:27 -0500 Subject: [PATCH 185/857] Update deserialize_witness fuzz target to use arbitrary impl --- fuzz/fuzz_targets/bitcoin/deserialize_witness.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs b/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs index 9dec1bc684..42c201f70e 100644 --- a/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs +++ b/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs @@ -1,12 +1,18 @@ use bitcoin::consensus::{deserialize, serialize}; use bitcoin::witness::Witness; use honggfuzz::fuzz; +use arbitrary::{Arbitrary, Unstructured}; fn do_test(data: &[u8]) { - let w: Result = deserialize(data); + let mut u = Unstructured::new(data); + + let w = Witness::arbitrary(&mut u); if let Ok(witness) = w { let serialized = serialize(&witness); - assert_eq!(data, &serialized[..]); + let deserialized: Result = deserialize(serialized.as_slice()); + + assert!(deserialized.is_ok()); + assert_eq!(deserialized.unwrap(), witness); } } From 48961dd5fbe58dd54808146303ce5be1842b5b0f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 12:54:55 +1000 Subject: [PATCH 186/857] Remove Transaction links from locktime docs In preparation for moving the locktime code to `units` remove all links to `Transaction` from the rustdocs of the `absolute` module. --- primitives/src/locktime/absolute.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs index 53225df3e7..4f827518cc 100644 --- a/primitives/src/locktime/absolute.rs +++ b/primitives/src/locktime/absolute.rs @@ -12,7 +12,7 @@ use arbitrary::{Arbitrary, Unstructured}; use units::parse::{self, PrefixedHexError, UnprefixedHexError}; #[cfg(all(doc, feature = "alloc"))] -use crate::{absolute, Transaction}; +use crate::absolute; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -25,8 +25,8 @@ pub type Time = MedianTimePast; /// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds /// since epoch). /// -/// Used for transaction lock time (`nLockTime` in Bitcoin Core and [`Transaction::lock_time`] -/// in this library) and also for the argument to opcode `OP_CHECKLOCKTIMEVERIFY`. +/// Used for transaction lock time (`nLockTime` in Bitcoin Core and `Transaction::lock_time` +/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKLOCKTIMEVERIFY`. /// /// # Note on ordering /// @@ -34,7 +34,7 @@ pub type Time = MedianTimePast; /// ordering on locktimes. In order to compare locktimes, instead of using `<` or `>` we provide the /// [`LockTime::is_satisfied_by`] API. /// -/// For [`Transaction`], which has a locktime field, we implement a total ordering to make +/// For transaction, which has a locktime field, we implement a total ordering to make /// it easy to store transactions in sorted data structures, and use the locktime's 32-bit integer /// consensus encoding to order it. /// @@ -87,7 +87,7 @@ pub enum LockTime { } impl LockTime { - /// If [`Transaction::lock_time`] is set to zero it is ignored, in other words a + /// If transaction lock time is set to zero it is ignored, in other words a /// transaction with nLocktime==0 is able to be included immediately in any block. pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO); @@ -230,8 +230,7 @@ impl LockTime { /// blocktime based lock it is checked against `time`. /// /// A 'timelock constraint' refers to the `n` from `n OP_CHEKCLOCKTIMEVERIFY`, this constraint - /// is satisfied if a transaction with `nLockTime` ([`Transaction::lock_time`]) set to - /// `height`/`time` is valid. + /// is satisfied if a transaction with `nLockTime` set to `height`/`time` is valid. /// /// If `height` and `mtp` represent the current chain tip then a transaction with this /// locktime can be broadcast for inclusion in the next block. From 19e54ee3a530d607047c150d798acc320be23711 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 12:58:32 +1000 Subject: [PATCH 187/857] Remove links to TxIn from locktime docs In preparation for moving the locktime code to `units` remove all links to `TxIn` from the rustdocs of the `relative` module. --- primitives/src/locktime/relative.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index cdfcd82160..01547c5c72 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -12,8 +12,9 @@ use arbitrary::{Arbitrary, Unstructured}; use internals::write_err; use crate::Sequence; + #[cfg(all(doc, feature = "alloc"))] -use crate::{relative, TxIn}; +use crate::relative; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] @@ -30,8 +31,8 @@ pub type Time = NumberOf512Seconds; /// A relative lock time value, representing either a block height or time (512 second intervals). /// -/// Used for sequence numbers (`nSequence` in Bitcoin Core and [`TxIn::sequence`] -/// in this library) and also for the argument to opcode `OP_CHECKSEQUENCEVERIFY`. +/// Used for sequence numbers (`nSequence` in Bitcoin Core and `TxIn::sequence` +/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKSEQUENCEVERIFY`. /// /// # Note on ordering /// From 5f3d3a51c0c249e7bd79a82d9cdd86bc455f4859 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 13:00:24 +1000 Subject: [PATCH 188/857] Remove Transaction links from sequence docs In preparation for moving the sequence module to `units` remove links to `Transaction` from the rustdocs of the module. --- primitives/src/sequence.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/primitives/src/sequence.rs b/primitives/src/sequence.rs index a824a2049a..c7179d4939 100644 --- a/primitives/src/sequence.rs +++ b/primitives/src/sequence.rs @@ -3,7 +3,7 @@ //! Bitcoin transaction input sequence number. //! //! The sequence field is used for: -//! - Indicating whether absolute lock-time (specified in `lock_time` field of [`Transaction`]) is enabled. +//! - Indicating whether absolute lock-time (specified in `lock_time` field of `Transaction`) is enabled. //! - Indicating and encoding [BIP-68] relative lock-times. //! - Indicating whether a transaction opts-in to [BIP-125] replace-by-fee. //! @@ -24,8 +24,6 @@ use units::locktime::relative::{NumberOf512Seconds, TimeOverflowError}; use units::parse::{self, PrefixedHexError, UnprefixedHexError}; use crate::locktime::relative; -#[cfg(all(doc, feature = "alloc"))] -use crate::Transaction; /// Bitcoin transaction input sequence number. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -72,7 +70,7 @@ impl Sequence { /// BIP-68 relative lock time type flag mask. pub(super) const LOCK_TYPE_MASK: u32 = 0x0040_0000; - /// Returns `true` if the sequence number enables absolute lock-time ([`Transaction::lock_time`]). + /// Returns `true` if the sequence number enables absolute lock-time (`Transaction::lock_time`). #[inline] pub fn enables_absolute_lock_time(self) -> bool { self != Sequence::MAX } From 33ac20611eebd03e52c0b7d717b598a79d2b895a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 13:06:14 +1000 Subject: [PATCH 189/857] Move locktimes to module directories In preparation fro adding error modules move the two locktime modules to directories. --- units/src/locktime/{absolute.rs => absolute/mod.rs} | 0 units/src/locktime/{relative.rs => relative/mod.rs} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename units/src/locktime/{absolute.rs => absolute/mod.rs} (100%) rename units/src/locktime/{relative.rs => relative/mod.rs} (100%) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute/mod.rs similarity index 100% rename from units/src/locktime/absolute.rs rename to units/src/locktime/absolute/mod.rs diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative/mod.rs similarity index 100% rename from units/src/locktime/relative.rs rename to units/src/locktime/relative/mod.rs From fe62307eeaae693364598dece89dbfaab721f084 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 14:35:01 +1000 Subject: [PATCH 190/857] Move non-pub import into correct place We have a non-public import that has snuck in below then public ones. This isn't caught by the formatter because we explicitly skip on the public exports. --- primitives/src/locktime/relative.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index 01547c5c72..60cbf50aae 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -10,6 +10,7 @@ use core::{convert, fmt}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; use internals::write_err; +use units::{BlockHeight, BlockMtp}; use crate::Sequence; @@ -19,7 +20,6 @@ use crate::relative; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds, TimeOverflowError, InvalidHeightError, InvalidTimeError}; -use units::{BlockHeight, BlockMtp}; #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] #[doc(hidden)] From d20e586e83ad205f140557f066a777b3925d706b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 13:05:01 +1000 Subject: [PATCH 191/857] Introduce error modules to locktime In order to de-clutter the public API introduce public `error` modules to both locktime modules and move all error types there (in `units` crate). As is now policy, re-export error types that appear in directly the public API but don't doc inline them. This is a bit confusing because _all_ the error types except `ParseError` appear directly in the API. --- primitives/src/locktime/absolute.rs | 6 +- primitives/src/locktime/relative.rs | 4 +- units/src/locktime/absolute/error.rs | 215 +++++++++++++++++++++++++++ units/src/locktime/absolute/mod.rs | 203 +------------------------ units/src/locktime/relative/error.rs | 64 ++++++++ units/src/locktime/relative/mod.rs | 65 +------- units/tests/api.rs | 11 +- 7 files changed, 307 insertions(+), 261 deletions(-) create mode 100644 units/src/locktime/absolute/error.rs create mode 100644 units/src/locktime/relative/error.rs diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs index 4f827518cc..3371d93980 100644 --- a/primitives/src/locktime/absolute.rs +++ b/primitives/src/locktime/absolute.rs @@ -16,7 +16,11 @@ use crate::absolute; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] -pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, MedianTimePast, LOCK_TIME_THRESHOLD}; +pub use units::locktime::absolute::{ + Height, MedianTimePast, LOCK_TIME_THRESHOLD +}; +#[doc(inline)] +pub use units::locktime::absolute::error::{ConversionError, ParseHeightError, ParseTimeError}; #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")] #[doc(hidden)] diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs index 60cbf50aae..e6168a9fdb 100644 --- a/primitives/src/locktime/relative.rs +++ b/primitives/src/locktime/relative.rs @@ -19,7 +19,9 @@ use crate::relative; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] -pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds, TimeOverflowError, InvalidHeightError, InvalidTimeError}; +pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds}; +#[doc(no_inline)] +pub use units::locktime::relative::error::{TimeOverflowError, InvalidHeightError, InvalidTimeError}; #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] #[doc(hidden)] diff --git a/units/src/locktime/absolute/error.rs b/units/src/locktime/absolute/error.rs new file mode 100644 index 0000000000..8d7abde220 --- /dev/null +++ b/units/src/locktime/absolute/error.rs @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Error types for the absolute locktime module. + +use core::convert::Infallible; +use core::fmt; + +use internals::error::InputString; + +use super::LOCK_TIME_THRESHOLD; +use crate::parse::ParseIntError; + +/// Error returned when parsing block height fails. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ParseHeightError(ParseError); + +impl fmt::Display for ParseHeightError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.display(f, "block height", 0, LOCK_TIME_THRESHOLD - 1) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseHeightError { + // To be consistent with `write_err` we need to **not** return source if overflow occurred + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.0.source() } +} + +impl From for ParseHeightError { + fn from(value: ParseError) -> Self { Self(value) } +} + +/// Error returned when parsing block time fails. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ParseTimeError(ParseError); + +impl fmt::Display for ParseTimeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.display(f, "block time", LOCK_TIME_THRESHOLD, u32::MAX) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseTimeError { + // To be consistent with `write_err` we need to **not** return source if overflow occurred + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.0.source() } +} + +impl From for ParseTimeError { + fn from(value: ParseError) -> Self { Self(value) } +} + +/// Internal - common representation for height and time. +#[derive(Debug, Clone, Eq, PartialEq)] +pub(super) enum ParseError { + ParseInt(ParseIntError), + // unit implied by outer type + // we use i64 to have nicer messages for negative values + Conversion(i64), +} + +impl From for ParseError { + fn from(never: Infallible) -> Self { match never {} } +} + +impl ParseError { + pub(super) fn invalid_int>( + s: S, + ) -> impl FnOnce(core::num::ParseIntError) -> Self { + move |source| { + Self::ParseInt(ParseIntError { input: s.into(), bits: 32, is_signed: true, source }) + } + } + + pub(super) fn display( + &self, + f: &mut fmt::Formatter<'_>, + subject: &str, + lower_bound: u32, + upper_bound: u32, + ) -> fmt::Result { + use core::num::IntErrorKind; + + match self { + Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) + if *source.kind() == IntErrorKind::PosOverflow => + { + // Outputs "failed to parse as absolute Height/MedianTimePast ( is above limit )" + write!( + f, + "{} ({} is above limit {})", + input.display_cannot_parse("absolute Height/MedianTimePast"), + subject, + upper_bound + ) + } + Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) + if *source.kind() == IntErrorKind::NegOverflow => + { + // Outputs "failed to parse as absolute Height/MedianTimePast ( is below limit )" + write!( + f, + "{} ({} is below limit {})", + input.display_cannot_parse("absolute Height/MedianTimePast"), + subject, + lower_bound + ) + } + Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => { + write!( + f, + "{} ({})", + input.display_cannot_parse("absolute Height/MedianTimePast"), + subject + ) + } + Self::Conversion(value) if *value < i64::from(lower_bound) => { + write!(f, "{} {} is below limit {}", subject, value, lower_bound) + } + Self::Conversion(value) => { + write!(f, "{} {} is above limit {}", subject, value, upper_bound) + } + } + } + + // To be consistent with `write_err` we need to **not** return source if overflow occurred + #[cfg(feature = "std")] + pub(super) fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use core::num::IntErrorKind; + + match self { + Self::ParseInt(ParseIntError { source, .. }) + if *source.kind() == IntErrorKind::PosOverflow => + None, + Self::ParseInt(ParseIntError { source, .. }) + if *source.kind() == IntErrorKind::NegOverflow => + None, + Self::ParseInt(ParseIntError { source, .. }) => Some(source), + Self::Conversion(_) => None, + } + } +} + +impl From for ParseError { + fn from(value: ConversionError) -> Self { Self::Conversion(value.input.into()) } +} + +/// Error returned when converting a `u32` to a lock time variant fails. +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub struct ConversionError { + /// The expected timelock unit, height (blocks) or time (seconds). + unit: LockTimeUnit, + /// The invalid input value. + input: u32, +} + +impl ConversionError { + /// Constructs a new `ConversionError` from an invalid `n` when expecting a height value. + pub(super) const fn invalid_height(n: u32) -> Self { + Self { unit: LockTimeUnit::Blocks, input: n } + } + + /// Constructs a new `ConversionError` from an invalid `n` when expecting a time value. + pub(super) const fn invalid_time(n: u32) -> Self { + Self { unit: LockTimeUnit::Seconds, input: n } + } +} + +impl fmt::Display for ConversionError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid lock time value {}, {}", self.input, self.unit) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ConversionError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } +} + +/// Describes the two types of locking, lock-by-height and lock-by-time. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +enum LockTimeUnit { + /// Lock by blockheight. + Blocks, + /// Lock by blocktime. + Seconds, +} + +impl fmt::Display for LockTimeUnit { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use LockTimeUnit as L; + + match *self { + L::Blocks => write!(f, "expected lock-by-height (must be < {})", LOCK_TIME_THRESHOLD), + L::Seconds => write!(f, "expected lock-by-time (must be >= {})", LOCK_TIME_THRESHOLD), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(feature = "alloc")] + fn locktime_unit_display() { + use alloc::format; + let blocks = LockTimeUnit::Blocks; + let seconds = LockTimeUnit::Seconds; + + assert_eq!(format!("{}", blocks), "expected lock-by-height (must be < 500000000)"); + assert_eq!(format!("{}", seconds), "expected lock-by-time (must be >= 500000000)"); + } +} diff --git a/units/src/locktime/absolute/mod.rs b/units/src/locktime/absolute/mod.rs index 8f193f2e39..336c9a7a89 100644 --- a/units/src/locktime/absolute/mod.rs +++ b/units/src/locktime/absolute/mod.rs @@ -2,14 +2,20 @@ //! Provides [`Height`] and [`MedianTimePast`] types used by the `rust-bitcoin` `absolute::LockTime` type. -use core::convert::Infallible; +pub mod error; + use core::fmt; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; use internals::error::InputString; -use crate::parse::{self, ParseIntError}; +use self::error::ParseError; +use crate::parse; + +#[rustfmt::skip] // Keep public re-exports separate. +#[doc(no_inline)] +pub use self::error::{ConversionError, ParseHeightError, ParseTimeError}; /// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]). /// @@ -111,26 +117,6 @@ impl fmt::Display for Height { crate::impl_parse_str!(Height, ParseHeightError, parser(Height::from_u32)); -/// Error returned when parsing block height fails. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ParseHeightError(ParseError); - -impl fmt::Display for ParseHeightError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.display(f, "block height", 0, LOCK_TIME_THRESHOLD - 1) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ParseHeightError { - // To be consistent with `write_err` we need to **not** return source if overflow occurred - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.0.source() } -} - -impl From for ParseHeightError { - fn from(value: ParseError) -> Self { Self(value) } -} - #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")] #[doc(hidden)] pub type Time = MedianTimePast; @@ -246,26 +232,6 @@ impl fmt::Display for MedianTimePast { crate::impl_parse_str!(MedianTimePast, ParseTimeError, parser(MedianTimePast::from_u32)); -/// Error returned when parsing block time fails. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ParseTimeError(ParseError); - -impl fmt::Display for ParseTimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.display(f, "block time", LOCK_TIME_THRESHOLD, u32::MAX) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ParseTimeError { - // To be consistent with `write_err` we need to **not** return source if overflow occurred - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.0.source() } -} - -impl From for ParseTimeError { - fn from(value: ParseError) -> Self { Self(value) } -} - fn parser(f: F) -> impl FnOnce(S) -> Result where E: From, @@ -297,148 +263,6 @@ pub const fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD } /// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000. pub const fn is_block_time(n: u32) -> bool { n >= LOCK_TIME_THRESHOLD } -/// Error returned when converting a `u32` to a lock time variant fails. -#[derive(Debug, Clone, PartialEq, Eq)] -#[non_exhaustive] -pub struct ConversionError { - /// The expected timelock unit, height (blocks) or time (seconds). - unit: LockTimeUnit, - /// The invalid input value. - input: u32, -} - -impl ConversionError { - /// Constructs a new `ConversionError` from an invalid `n` when expecting a height value. - const fn invalid_height(n: u32) -> Self { Self { unit: LockTimeUnit::Blocks, input: n } } - - /// Constructs a new `ConversionError` from an invalid `n` when expecting a time value. - const fn invalid_time(n: u32) -> Self { Self { unit: LockTimeUnit::Seconds, input: n } } -} - -impl fmt::Display for ConversionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "invalid lock time value {}, {}", self.input, self.unit) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for ConversionError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } -} - -/// Describes the two types of locking, lock-by-height and lock-by-time. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -enum LockTimeUnit { - /// Lock by blockheight. - Blocks, - /// Lock by blocktime. - Seconds, -} - -impl fmt::Display for LockTimeUnit { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use LockTimeUnit as L; - - match *self { - L::Blocks => write!(f, "expected lock-by-height (must be < {})", LOCK_TIME_THRESHOLD), - L::Seconds => write!(f, "expected lock-by-time (must be >= {})", LOCK_TIME_THRESHOLD), - } - } -} - -/// Internal - common representation for height and time. -#[derive(Debug, Clone, Eq, PartialEq)] -enum ParseError { - ParseInt(ParseIntError), - // unit implied by outer type - // we use i64 to have nicer messages for negative values - Conversion(i64), -} - -impl From for ParseError { - fn from(never: Infallible) -> Self { match never {} } -} - -impl ParseError { - fn invalid_int>(s: S) -> impl FnOnce(core::num::ParseIntError) -> Self { - move |source| { - Self::ParseInt(ParseIntError { input: s.into(), bits: 32, is_signed: true, source }) - } - } - - fn display( - &self, - f: &mut fmt::Formatter<'_>, - subject: &str, - lower_bound: u32, - upper_bound: u32, - ) -> fmt::Result { - use core::num::IntErrorKind; - - match self { - Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) - if *source.kind() == IntErrorKind::PosOverflow => - { - // Outputs "failed to parse as absolute Height/MedianTimePast ( is above limit )" - write!( - f, - "{} ({} is above limit {})", - input.display_cannot_parse("absolute Height/MedianTimePast"), - subject, - upper_bound - ) - } - Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source }) - if *source.kind() == IntErrorKind::NegOverflow => - { - // Outputs "failed to parse as absolute Height/MedianTimePast ( is below limit )" - write!( - f, - "{} ({} is below limit {})", - input.display_cannot_parse("absolute Height/MedianTimePast"), - subject, - lower_bound - ) - } - Self::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => { - write!( - f, - "{} ({})", - input.display_cannot_parse("absolute Height/MedianTimePast"), - subject - ) - } - Self::Conversion(value) if *value < i64::from(lower_bound) => { - write!(f, "{} {} is below limit {}", subject, value, lower_bound) - } - Self::Conversion(value) => { - write!(f, "{} {} is above limit {}", subject, value, upper_bound) - } - } - } - - // To be consistent with `write_err` we need to **not** return source if overflow occurred - #[cfg(feature = "std")] - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use core::num::IntErrorKind; - - match self { - Self::ParseInt(ParseIntError { source, .. }) - if *source.kind() == IntErrorKind::PosOverflow => - None, - Self::ParseInt(ParseIntError { source, .. }) - if *source.kind() == IntErrorKind::NegOverflow => - None, - Self::ParseInt(ParseIntError { source, .. }) => Some(source), - Self::Conversion(_) => None, - } - } -} - -impl From for ParseError { - fn from(value: ConversionError) -> Self { Self::Conversion(value.input.into()) } -} - #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Height { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { @@ -526,17 +350,6 @@ mod tests { assert!(is_block_time(500_000_000)); } - #[test] - #[cfg(feature = "alloc")] - fn locktime_unit_display() { - use alloc::format; - let blocks = LockTimeUnit::Blocks; - let seconds = LockTimeUnit::Seconds; - - assert_eq!(format!("{}", blocks), "expected lock-by-height (must be < 500000000)"); - assert_eq!(format!("{}", seconds), "expected lock-by-time (must be >= 500000000)"); - } - #[test] fn valid_chain_computes_mtp() { use crate::BlockTime; diff --git a/units/src/locktime/relative/error.rs b/units/src/locktime/relative/error.rs new file mode 100644 index 0000000000..04e5026aa0 --- /dev/null +++ b/units/src/locktime/relative/error.rs @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Error types for the relative locktime module. + +use core::fmt; + +/// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TimeOverflowError { + /// Time interval value in seconds that overflowed. + // Private because we maintain an invariant that the `seconds` value does actually overflow. + pub(crate) seconds: u32, +} + +impl fmt::Display for TimeOverflowError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{} seconds is too large to be encoded to a 16 bit 512 second interval", + self.seconds + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for TimeOverflowError {} + +/// Error returned when `NumberOfBlocks::is_satisfied_by` is incorrectly called. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidHeightError { + /// The `chain_tip` argument. + pub(crate) chain_tip: crate::BlockHeight, + /// The `utxo_mined_at` argument. + pub(crate) utxo_mined_at: crate::BlockHeight, +} + +impl fmt::Display for InvalidHeightError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidHeightError {} + +/// Error returned when `NumberOf512Seconds::is_satisfied_by` is incorrectly called. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidTimeError { + /// The `chain_tip` argument. + pub(crate) chain_tip: crate::BlockMtp, + /// The `utxo_mined_at` argument. + pub(crate) utxo_mined_at: crate::BlockMtp, +} + +impl fmt::Display for InvalidTimeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidTimeError {} diff --git a/units/src/locktime/relative/mod.rs b/units/src/locktime/relative/mod.rs index 3a9bcd8517..2d3ae4bf9f 100644 --- a/units/src/locktime/relative/mod.rs +++ b/units/src/locktime/relative/mod.rs @@ -3,11 +3,17 @@ //! Provides [`NumberOfBlocks`] and [`NumberOf512Seconds`] types used by the //! `rust-bitcoin` `relative::LockTime` type. +pub mod error; + use core::fmt; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; +#[rustfmt::skip] // Keep public re-exports separate. +#[doc(no_inline)] +pub use self::error::{InvalidHeightError, InvalidTimeError, TimeOverflowError}; + #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] #[doc(hidden)] pub type Height = NumberOfBlocks; @@ -203,65 +209,6 @@ impl fmt::Display for NumberOf512Seconds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } -/// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TimeOverflowError { - /// Time interval value in seconds that overflowed. - // Private because we maintain an invariant that the `seconds` value does actually overflow. - pub(crate) seconds: u32, -} - -impl fmt::Display for TimeOverflowError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{} seconds is too large to be encoded to a 16 bit 512 second interval", - self.seconds - ) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for TimeOverflowError {} - -/// Error returned when `NumberOfBlocks::is_satisfied_by` is incorrectly called. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct InvalidHeightError { - /// The `chain_tip` argument. - pub(crate) chain_tip: crate::BlockHeight, - /// The `utxo_mined_at` argument. - pub(crate) utxo_mined_at: crate::BlockHeight, -} - -impl fmt::Display for InvalidHeightError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at - ) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for InvalidHeightError {} - -/// Error returned when `NumberOf512Seconds::is_satisfied_by` is incorrectly called. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct InvalidTimeError { - /// The `chain_tip` argument. - pub(crate) chain_tip: crate::BlockMtp, - /// The `utxo_mined_at` argument. - pub(crate) utxo_mined_at: crate::BlockMtp, -} - -impl fmt::Display for InvalidTimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "is_satisfied_by arguments invalid (probably the wrong way around) chain_tip: {} utxo_mined_at: {}", self.chain_tip, self.utxo_mined_at - ) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for InvalidTimeError {} - #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for NumberOfBlocks { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { diff --git a/units/tests/api.rs b/units/tests/api.rs index 0d34bfdb46..d2e569e942 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -189,17 +189,18 @@ fn api_can_use_all_types_from_module_fee_rate() { #[test] fn api_can_use_all_types_from_module_locktime_absolute() { - use bitcoin_units::locktime::absolute::{ - ConversionError, Height, MedianTimePast, ParseHeightError, ParseTimeError, + use bitcoin_units::locktime::absolute::error::{ + ConversionError as _, ParseHeightError as _, ParseTimeError as _, }; + use bitcoin_units::locktime::absolute::{Height, MedianTimePast, ConversionError, ParseHeightError, ParseTimeError}; } #[test] fn api_can_use_all_types_from_module_locktime_relative() { - use bitcoin_units::locktime::relative::{ - Height, InvalidHeightError, InvalidTimeError, NumberOf512Seconds, NumberOfBlocks, Time, - TimeOverflowError, + use bitcoin_units::locktime::relative::error::{ + InvalidHeightError as _, InvalidTimeError as _, TimeOverflowError as _, }; + use bitcoin_units::locktime::relative::{Height, NumberOf512Seconds, NumberOfBlocks, Time, InvalidHeightError, InvalidTimeError, TimeOverflowError}; } #[test] From fa0c9685f7a60b1a5a4892b87d734b506a1d219a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 13:32:10 +1000 Subject: [PATCH 192/857] Move locktime and sequence code to units Move the `sequence` module and the code from both locktime modules from `primitives` to `units`. --- bitcoin/src/blockdata/mod.rs | 8 +- primitives/src/lib.rs | 6 +- primitives/src/locktime/absolute.rs | 646 --------------------- primitives/src/locktime/mod.rs | 6 - primitives/src/locktime/relative.rs | 770 -------------------------- primitives/src/transaction.rs | 8 +- primitives/tests/api.rs | 13 +- units/Cargo.toml | 2 +- units/src/lib.rs | 3 + units/src/locktime/absolute/error.rs | 68 ++- units/src/locktime/absolute/mod.rs | 574 ++++++++++++++++++- units/src/locktime/relative/error.rs | 129 +++++ units/src/locktime/relative/mod.rs | 625 ++++++++++++++++++++- {primitives => units}/src/sequence.rs | 14 +- 14 files changed, 1412 insertions(+), 1460 deletions(-) delete mode 100644 primitives/src/locktime/absolute.rs delete mode 100644 primitives/src/locktime/mod.rs delete mode 100644 primitives/src/locktime/relative.rs rename {primitives => units}/src/sequence.rs (97%) diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs index 7974ba8075..0f19a9f7c9 100644 --- a/bitcoin/src/blockdata/mod.rs +++ b/bitcoin/src/blockdata/mod.rs @@ -39,9 +39,9 @@ pub mod locktime { pub use crate::consensus::encode::{self, Decodable, Encodable}; - /// Re-export everything from the `primitives::locktime::absolute` module. + /// Re-export everything from the `units::locktime::absolute` module. #[rustfmt::skip] // Keep public re-exports separate. - pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, MedianTimePast}; + pub use units::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, MedianTimePast}; #[deprecated(since = "TBD", note = "use `MedianTimePast` instead")] #[doc(hidden)] @@ -69,8 +69,8 @@ pub mod locktime { //! There are two types of lock time: lock-by-height and lock-by-time, distinguished by //! whether bit 22 of the `u32` consensus value is set. - /// Re-export everything from the `primitives::locktime::relative` module. - pub use primitives::locktime::relative::{ + /// Re-export everything from the `units::locktime::relative` module. + pub use units::locktime::relative::{ DisabledLockTimeError, InvalidHeightError, InvalidTimeError, LockTime, NumberOf512Seconds, NumberOfBlocks, TimeOverflowError, }; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 2a22b6060f..c2e1072f92 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -38,13 +38,11 @@ pub mod _export { } pub mod block; -pub mod locktime; pub mod merkle_tree; mod opcodes; pub mod pow; #[cfg(feature = "alloc")] pub mod script; -pub mod sequence; pub mod transaction; #[cfg(feature = "alloc")] pub mod witness; @@ -54,6 +52,8 @@ pub use units::{ amount::{self, Amount, SignedAmount}, block::{BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval}, fee_rate::{self, FeeRate}, + locktime::{self, absolute, relative}, + sequence::{self, Sequence}, time::{self, BlockTime}, weight::{self, Weight}, }; @@ -75,10 +75,8 @@ pub use self::{ #[doc(inline)] pub use self::{ block::{BlockHash, Header as BlockHeader, Version as BlockVersion, WitnessCommitment}, - locktime::{absolute, relative}, merkle_tree::{TxMerkleNode, WitnessMerkleNode}, pow::CompactTarget, - sequence::Sequence, transaction::{OutPoint, Txid, Version as TransactionVersion, Wtxid}, }; diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs deleted file mode 100644 index 3371d93980..0000000000 --- a/primitives/src/locktime/absolute.rs +++ /dev/null @@ -1,646 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Provides type [`LockTime`] that implements the logic around `nLockTime`/`OP_CHECKLOCKTIMEVERIFY`. -//! -//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by -//! whether `LockTime < LOCKTIME_THRESHOLD`. - -use core::fmt; - -#[cfg(feature = "arbitrary")] -use arbitrary::{Arbitrary, Unstructured}; -use units::parse::{self, PrefixedHexError, UnprefixedHexError}; - -#[cfg(all(doc, feature = "alloc"))] -use crate::absolute; - -#[rustfmt::skip] // Keep public re-exports separate. -#[doc(inline)] -pub use units::locktime::absolute::{ - Height, MedianTimePast, LOCK_TIME_THRESHOLD -}; -#[doc(inline)] -pub use units::locktime::absolute::error::{ConversionError, ParseHeightError, ParseTimeError}; - -#[deprecated(since = "TBD", note = "use `MedianTimePast` instead")] -#[doc(hidden)] -pub type Time = MedianTimePast; - -/// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds -/// since epoch). -/// -/// Used for transaction lock time (`nLockTime` in Bitcoin Core and `Transaction::lock_time` -/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKLOCKTIMEVERIFY`. -/// -/// # Note on ordering -/// -/// Locktimes may be height- or time-based, and these metrics are incommensurate; there is no total -/// ordering on locktimes. In order to compare locktimes, instead of using `<` or `>` we provide the -/// [`LockTime::is_satisfied_by`] API. -/// -/// For transaction, which has a locktime field, we implement a total ordering to make -/// it easy to store transactions in sorted data structures, and use the locktime's 32-bit integer -/// consensus encoding to order it. -/// -/// # Relevant BIPs -/// -/// * [BIP-65 OP_CHECKLOCKTIMEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) -/// * [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki) -/// -/// # Examples -/// -/// ``` -/// use bitcoin_primitives::absolute::{self, LockTime as L}; -/// # let n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY -/// # let lock_time = absolute::LockTime::from_consensus(741521); // nLockTime -/// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use: -/// let _is_satisfied = match (n, lock_time) { -/// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time, -/// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time, -/// _ => panic!("handle invalid comparison error"), -/// }; -/// ``` -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub enum LockTime { - /// A block height lock time value. - /// - /// # Examples - /// - /// ```rust - /// use bitcoin_primitives::absolute; - /// - /// let block: u32 = 741521; - /// let n = absolute::LockTime::from_height(block).expect("valid height"); - /// assert!(n.is_block_height()); - /// assert_eq!(n.to_consensus_u32(), block); - /// ``` - Blocks(Height), - /// A UNIX timestamp lock time value. - /// - /// # Examples - /// - /// ```rust - /// use bitcoin_primitives::absolute; - /// - /// let seconds: u32 = 1653195600; // May 22nd, 5am UTC. - /// let n = absolute::LockTime::from_mtp(seconds).expect("valid time"); - /// assert!(n.is_block_time()); - /// assert_eq!(n.to_consensus_u32(), seconds); - /// ``` - Seconds(MedianTimePast), -} - -impl LockTime { - /// If transaction lock time is set to zero it is ignored, in other words a - /// transaction with nLocktime==0 is able to be included immediately in any block. - pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO); - - /// The number of bytes that the locktime contributes to the size of a transaction. - pub const SIZE: usize = 4; // Serialized length of a u32. - - /// Constructs a new `LockTime` from a prefixed hex string. - /// - /// # Examples - /// - /// ``` - /// # use bitcoin_primitives::absolute; - /// let hex_str = "0x61cf9980"; // Unix timestamp for January 1, 2022 - /// let lock_time = absolute::LockTime::from_hex(hex_str)?; - /// assert_eq!(lock_time.to_consensus_u32(), 0x61cf9980); - /// - /// # Ok::<_, units::parse::PrefixedHexError>(()) - /// ``` - #[inline] - pub fn from_hex(s: &str) -> Result { - let lock_time = parse::hex_u32_prefixed(s)?; - Ok(Self::from_consensus(lock_time)) - } - - /// Constructs a new `LockTime` from an unprefixed hex string. - /// - /// # Examples - /// - /// ``` - /// # use bitcoin_primitives::absolute; - /// let hex_str = "61cf9980"; // Unix timestamp for January 1, 2022 - /// let lock_time = absolute::LockTime::from_unprefixed_hex(hex_str)?; - /// assert_eq!(lock_time.to_consensus_u32(), 0x61cf9980); - /// - /// # Ok::<_, units::parse::UnprefixedHexError>(()) - /// ``` - #[inline] - pub fn from_unprefixed_hex(s: &str) -> Result { - let lock_time = parse::hex_u32_unprefixed(s)?; - Ok(Self::from_consensus(lock_time)) - } - - /// Constructs a new `LockTime` from an `nLockTime` value or the argument to `OP_CHEKCLOCKTIMEVERIFY`. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::absolute; - /// - /// // `from_consensus` roundtrips as expected with `to_consensus_u32`. - /// let n_lock_time: u32 = 741521; - /// let lock_time = absolute::LockTime::from_consensus(n_lock_time); - /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); - #[inline] - #[allow(clippy::missing_panics_doc)] - pub fn from_consensus(n: u32) -> Self { - if units::locktime::absolute::is_block_height(n) { - Self::Blocks(Height::from_u32(n).expect("n is valid")) - } else { - Self::Seconds(MedianTimePast::from_u32(n).expect("n is valid")) - } - } - - /// Constructs a new `LockTime` from `n`, expecting `n` to be a valid block height. - /// - /// # Note - /// - /// If the current block height is `h` and the locktime is set to `h`, - /// the transaction can be included in block `h+1` or later. - /// It is possible to broadcast the transaction at block height `h`. - /// - /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid height value. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::absolute; - /// assert!(absolute::LockTime::from_height(741521).is_ok()); - /// assert!(absolute::LockTime::from_height(1653195600).is_err()); - /// ``` - #[inline] - pub fn from_height(n: u32) -> Result { - let height = Height::from_u32(n)?; - Ok(LockTime::Blocks(height)) - } - - #[inline] - #[deprecated(since = "TBD", note = "use `from_mtp` instead")] - #[doc(hidden)] - pub fn from_time(n: u32) -> Result { Self::from_mtp(n) } - - /// Constructs a new `LockTime` from `n`, expecting `n` to be a median-time-past (MTP) - /// which is in range for a locktime. - /// - /// # Note - /// - /// If the locktime is set to an MTP `T`, the transaction can be included in a block only if - /// the MTP of last recent 11 blocks is greater than `T`. - /// - /// It is possible to broadcast the transaction once the MTP is greater than `T`. See BIP-113. - /// - /// [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki) - /// - /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid time value. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::absolute; - /// assert!(absolute::LockTime::from_mtp(1653195600).is_ok()); - /// assert!(absolute::LockTime::from_mtp(741521).is_err()); - /// ``` - #[inline] - pub fn from_mtp(n: u32) -> Result { - let time = MedianTimePast::from_u32(n)?; - Ok(LockTime::Seconds(time)) - } - - /// Returns true if both lock times use the same unit i.e., both height based or both time based. - #[inline] - pub const fn is_same_unit(self, other: LockTime) -> bool { - matches!( - (self, other), - (LockTime::Blocks(_), LockTime::Blocks(_)) - | (LockTime::Seconds(_), LockTime::Seconds(_)) - ) - } - - /// Returns true if this lock time value is a block height. - #[inline] - pub const fn is_block_height(self) -> bool { matches!(self, LockTime::Blocks(_)) } - - /// Returns true if this lock time value is a block time (UNIX timestamp). - #[inline] - pub const fn is_block_time(self) -> bool { !self.is_block_height() } - - /// Returns true if this timelock constraint is satisfied by the respective `height`/`time`. - /// - /// If `self` is a blockheight based lock then it is checked against `height` and if `self` is a - /// blocktime based lock it is checked against `time`. - /// - /// A 'timelock constraint' refers to the `n` from `n OP_CHEKCLOCKTIMEVERIFY`, this constraint - /// is satisfied if a transaction with `nLockTime` set to `height`/`time` is valid. - /// - /// If `height` and `mtp` represent the current chain tip then a transaction with this - /// locktime can be broadcast for inclusion in the next block. - /// - /// If you do not have, or do not wish to calculate, both parameters consider using: - /// - /// * [`is_satisfied_by_height()`](absolute::LockTime::is_satisfied_by_height) - /// * [`is_satisfied_by_time()`](absolute::LockTime::is_satisfied_by_time) - /// - /// # Examples - /// - /// ```no_run - /// # use bitcoin_primitives::absolute; - /// // Can be implemented if block chain data is available. - /// fn get_height() -> absolute::Height { todo!("return the current block height") } - /// fn get_time() -> absolute::MedianTimePast { todo!("return the current block MTP") } - /// - /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`. - /// if n.is_satisfied_by(get_height(), get_time()) { - /// // Can create and mine a transaction that satisfies the OP_CLTV timelock constraint. - /// } - /// ```` - #[inline] - pub fn is_satisfied_by(self, height: Height, mtp: MedianTimePast) -> bool { - match self { - LockTime::Blocks(blocks) => blocks.is_satisfied_by(height), - LockTime::Seconds(time) => time.is_satisfied_by(mtp), - } - } - - /// Returns true if a transaction with this locktime can be spent in the next block. - /// - /// If `height` is the current block height of the chain then a transaction with this locktime - /// can be broadcast for inclusion in the next block. - /// - /// # Errors - /// - /// Returns an error if this lock is not lock-by-height. - #[inline] - pub fn is_satisfied_by_height(self, height: Height) -> Result { - use LockTime as L; - - match self { - L::Blocks(blocks) => Ok(blocks.is_satisfied_by(height)), - L::Seconds(time) => Err(IncompatibleHeightError { lock: time, incompatible: height }), - } - } - - /// Returns true if a transaction with this locktime can be included in the next block. - /// - /// # Errors - /// - /// Returns an error if this lock is not lock-by-time. - #[inline] - pub fn is_satisfied_by_time(self, mtp: MedianTimePast) -> Result { - use LockTime as L; - - match self { - L::Seconds(time) => Ok(time.is_satisfied_by(mtp)), - L::Blocks(blocks) => Err(IncompatibleTimeError { lock: blocks, incompatible: mtp }), - } - } - - /// Returns true if satisfaction of `other` lock time implies satisfaction of this - /// [`absolute::LockTime`]. - /// - /// A lock time can only be satisfied by n blocks being mined or n seconds passing. If you have - /// two lock times (same unit) then the larger lock time being satisfied implies (in a - /// mathematical sense) the smaller one being satisfied. - /// - /// This function serves multiple purposes: - /// - /// * When evaluating `OP_CHECKLOCKTIMEVERIFY` the argument must be less than or equal to the - /// transactions nLockTime. If using this function to validate a script `self` is the argument - /// to `CLTV` and `other` is the transaction nLockTime. - /// - /// * If you wish to check a lock time against various other locks e.g., filtering out locks - /// which cannot be satisfied. Can also be used to remove the smaller value of two - /// `OP_CHECKLOCKTIMEVERIFY` operations within one branch of the script. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::absolute; - /// let lock_time = absolute::LockTime::from_consensus(741521); - /// let check = absolute::LockTime::from_consensus(741521 + 1); - /// assert!(lock_time.is_implied_by(check)); - /// ``` - #[inline] - pub fn is_implied_by(self, other: LockTime) -> bool { - use LockTime as L; - - match (self, other) { - (L::Blocks(this), L::Blocks(other)) => this <= other, - (L::Seconds(this), L::Seconds(other)) => this <= other, - _ => false, // Not the same units. - } - } - - /// Returns the inner `u32` value. This is the value used when creating this `LockTime` - /// i.e., `n OP_CHECKLOCKTIMEVERIFY` or `nLockTime`. - /// - /// # Warning - /// - /// Do not compare values return by this method. The whole point of the `LockTime` type is to - /// assist in doing correct comparisons. Either use `is_satisfied_by`, `is_satisfied_by_lock`, - /// or use the pattern below: - /// - /// # Examples - /// - /// ```rust - /// use bitcoin_primitives::absolute::{self, LockTime as L}; - /// # let n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY - /// # let lock_time = absolute::LockTime::from_consensus(741521 + 1); // nLockTime - /// - /// let _is_satisfied = match (n, lock_time) { - /// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time, - /// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time, - /// _ => panic!("invalid comparison"), - /// }; - /// - /// // Or, if you have Rust 1.53 or greater - /// // let is_satisfied = n.partial_cmp(&lock_time).expect("invalid comparison").is_le(); - /// ``` - #[inline] - pub fn to_consensus_u32(self) -> u32 { - match self { - LockTime::Blocks(ref h) => h.to_u32(), - LockTime::Seconds(ref t) => t.to_u32(), - } - } -} - -units::impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus); - -impl From for LockTime { - #[inline] - fn from(h: Height) -> Self { LockTime::Blocks(h) } -} - -impl From for LockTime { - #[inline] - fn from(t: MedianTimePast) -> Self { LockTime::Seconds(t) } -} - -impl fmt::Debug for LockTime { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use LockTime as L; - - match *self { - L::Blocks(ref h) => write!(f, "{} blocks", h), - L::Seconds(ref t) => write!(f, "{} seconds", t), - } - } -} - -impl fmt::Display for LockTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use LockTime as L; - - if f.alternate() { - match *self { - L::Blocks(ref h) => write!(f, "block-height {}", h), - L::Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t), - } - } else { - match *self { - L::Blocks(ref h) => fmt::Display::fmt(h, f), - L::Seconds(ref t) => fmt::Display::fmt(t, f), - } - } - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for LockTime { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.to_consensus_u32().serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for LockTime { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - u32::deserialize(deserializer).map(Self::from_consensus) - } -} - -/// Tried to satisfy a lock-by-time lock using a height value. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IncompatibleHeightError { - /// The inner value of the lock-by-time lock. - lock: MedianTimePast, - /// Attempted to satisfy a lock-by-time lock with this height. - incompatible: Height, -} - -impl IncompatibleHeightError { - /// Returns the value of the lock-by-time lock. - pub fn lock(&self) -> MedianTimePast { self.lock } - - /// Returns the height that was erroneously used to try and satisfy a lock-by-time lock. - pub fn incompatible(&self) -> Height { self.incompatible } -} - -impl fmt::Display for IncompatibleHeightError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "tried to satisfy a lock-by-time lock {} with height: {}", - self.lock, self.incompatible - ) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for IncompatibleHeightError {} - -/// Tried to satisfy a lock-by-height lock using a height value. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct IncompatibleTimeError { - /// The inner value of the lock-by-height lock. - lock: Height, - /// Attempted to satisfy a lock-by-height lock with this MTP. - incompatible: MedianTimePast, -} - -impl IncompatibleTimeError { - /// Returns the value of the lock-by-height lock. - pub fn lock(&self) -> Height { self.lock } - - /// Returns the MTP that was erroneously used to try and satisfy a lock-by-height lock. - pub fn incompatible(&self) -> MedianTimePast { self.incompatible } -} - -impl fmt::Display for IncompatibleTimeError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "tried to satisfy a lock-by-height lock {} with MTP: {}", - self.lock, self.incompatible - ) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for IncompatibleTimeError {} - -#[cfg(feature = "arbitrary")] -impl<'a> Arbitrary<'a> for LockTime { - fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - let l = u32::arbitrary(u)?; - Ok(LockTime::from_consensus(l)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn display_and_alternate() { - let lock_by_height = LockTime::from_height(741_521).unwrap(); - let lock_by_time = LockTime::from_mtp(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC. - - assert_eq!(format!("{}", lock_by_height), "741521"); - assert_eq!(format!("{:#}", lock_by_height), "block-height 741521"); - assert!(!format!("{:?}", lock_by_height).is_empty()); - - assert_eq!(format!("{}", lock_by_time), "1653195600"); - assert_eq!(format!("{:#}", lock_by_time), "block-time 1653195600 (seconds since epoch)"); - assert!(!format!("{:?}", lock_by_time).is_empty()); - } - - #[test] - fn roundtrips() { - let lock_by_height = LockTime::from_consensus(741_521); - let lock_by_time = LockTime::from_consensus(1_653_195_600); - - assert_eq!(lock_by_height.to_consensus_u32(), 741_521); - assert_eq!(lock_by_time.to_consensus_u32(), 1_653_195_600); - } - - #[test] - fn lock_time_from_hex_lower() { - let lock_by_time = LockTime::from_hex("0x6289c350").unwrap(); - assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); - } - - #[test] - fn lock_time_from_hex_upper() { - let lock_by_time = LockTime::from_hex("0X6289C350").unwrap(); - assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); - } - - #[test] - fn lock_time_from_unprefixed_hex_lower() { - let lock_by_time = LockTime::from_unprefixed_hex("6289c350").unwrap(); - assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); - } - - #[test] - fn lock_time_from_unprefixed_hex_upper() { - let lock_by_time = LockTime::from_unprefixed_hex("6289C350").unwrap(); - assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); - } - - #[test] - fn invalid_hex() { - assert!(LockTime::from_hex("0xzb93").is_err()); - assert!(LockTime::from_unprefixed_hex("zb93").is_err()); - } - - #[test] - fn invalid_locktime_type() { - assert!(LockTime::from_height(499_999_999).is_ok()); // Below the threshold. - assert!(LockTime::from_height(500_000_000).is_err()); // The threshold. - assert!(LockTime::from_height(500_000_001).is_err()); // Above the threshold. - - assert!(LockTime::from_mtp(499_999_999).is_err()); // Below the threshold. - assert!(LockTime::from_mtp(500_000_000).is_ok()); // The threshold. - assert!(LockTime::from_mtp(500_000_001).is_ok()); // Above the threshold. - } - - #[test] - fn parses_correctly_to_height_or_time() { - let lock_by_height = LockTime::from_consensus(750_000); - - assert!(lock_by_height.is_block_height()); - assert!(!lock_by_height.is_block_time()); - - let t: u32 = 1_653_195_600; // May 22nd, 5am UTC. - let lock_by_time = LockTime::from_consensus(t); - - assert!(!lock_by_time.is_block_height()); - assert!(lock_by_time.is_block_time()); - - // Test is_same_unit() logic - assert!(lock_by_height.is_same_unit(LockTime::from_consensus(800_000))); - assert!(!lock_by_height.is_same_unit(lock_by_time)); - assert!(lock_by_time.is_same_unit(LockTime::from_consensus(1_653_282_000))); - assert!(!lock_by_time.is_same_unit(lock_by_height)); - } - - #[test] - fn satisfied_by_height() { - let height_below = Height::from_u32(700_000).unwrap(); - let height = Height::from_u32(750_000).unwrap(); - let height_above = Height::from_u32(800_000).unwrap(); - - let lock_by_height = LockTime::from(height); - - let t: u32 = 1_653_195_600; // May 22nd, 5am UTC. - let time = MedianTimePast::from_u32(t).unwrap(); - - assert!(!lock_by_height.is_satisfied_by(height_below, time)); - assert!(lock_by_height.is_satisfied_by(height, time)); - assert!(lock_by_height.is_satisfied_by(height_above, time)); - } - - #[test] - fn satisfied_by_time() { - let time_before = MedianTimePast::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC. - let time = MedianTimePast::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC. - let time_after = MedianTimePast::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC. - - let lock_by_time = LockTime::from(time); - - let height = Height::from_u32(800_000).unwrap(); - - assert!(!lock_by_time.is_satisfied_by(height, time_before)); - assert!(lock_by_time.is_satisfied_by(height, time)); - assert!(lock_by_time.is_satisfied_by(height, time_after)); - } - - #[test] - fn height_correctly_implies() { - let lock_by_height = LockTime::from_consensus(750_005); - - assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(750_004))); - assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_005))); - assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_006))); - } - - #[test] - fn time_correctly_implies() { - let t: u32 = 1_700_000_005; - let lock_by_time = LockTime::from_consensus(t); - - assert!(!lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_004))); - assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_005))); - assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_006))); - } - - #[test] - fn incorrect_units_do_not_imply() { - let lock_by_height = LockTime::from_consensus(750_005); - assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(1_700_000_004))); - } -} diff --git a/primitives/src/locktime/mod.rs b/primitives/src/locktime/mod.rs deleted file mode 100644 index 4cf62ad101..0000000000 --- a/primitives/src/locktime/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Provides absolute and relative locktimes. - -pub mod absolute; -pub mod relative; diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs deleted file mode 100644 index e6168a9fdb..0000000000 --- a/primitives/src/locktime/relative.rs +++ /dev/null @@ -1,770 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Provides type [`LockTime`] that implements the logic around `nSequence`/`OP_CHECKSEQUENCEVERIFY`. -//! -//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by -//! whether bit 22 of the `u32` consensus value is set. - -use core::{convert, fmt}; - -#[cfg(feature = "arbitrary")] -use arbitrary::{Arbitrary, Unstructured}; -use internals::write_err; -use units::{BlockHeight, BlockMtp}; - -use crate::Sequence; - -#[cfg(all(doc, feature = "alloc"))] -use crate::relative; - -#[rustfmt::skip] // Keep public re-exports separate. -#[doc(inline)] -pub use units::locktime::relative::{NumberOfBlocks, NumberOf512Seconds}; -#[doc(no_inline)] -pub use units::locktime::relative::error::{TimeOverflowError, InvalidHeightError, InvalidTimeError}; - -#[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] -#[doc(hidden)] -pub type Height = NumberOfBlocks; - -#[deprecated(since = "TBD", note = "use `NumberOf512Seconds` instead")] -#[doc(hidden)] -pub type Time = NumberOf512Seconds; - -/// A relative lock time value, representing either a block height or time (512 second intervals). -/// -/// Used for sequence numbers (`nSequence` in Bitcoin Core and `TxIn::sequence` -/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKSEQUENCEVERIFY`. -/// -/// # Note on ordering -/// -/// Locktimes may be height- or time-based, and these metrics are incommensurate; there is no total -/// ordering on locktimes. In order to compare locktimes, instead of using `<` or `>` we provide the -/// [`LockTime::is_satisfied_by`] API. -/// -/// # Relevant BIPs -/// -/// * [BIP 68 Relative lock-time using consensus-enforced sequence numbers](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) -/// * [BIP 112 CHECKSEQUENCEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum LockTime { - /// A block height lock time value. - Blocks(NumberOfBlocks), - /// A 512 second time interval value. - Time(NumberOf512Seconds), -} - -impl LockTime { - /// A relative locktime of 0 is always valid, and is assumed valid for inputs that - /// are not yet confirmed. - pub const ZERO: LockTime = LockTime::Blocks(NumberOfBlocks::ZERO); - - /// The number of bytes that the locktime contributes to the size of a transaction. - pub const SIZE: usize = 4; // Serialized length of a u32. - - /// Constructs a new `LockTime` from an `nSequence` value or the argument to `OP_CHECKSEQUENCEVERIFY`. - /// - /// This method will **not** round-trip with [`Self::to_consensus_u32`], because relative - /// locktimes only use some bits of the underlying `u32` value and discard the rest. If - /// you want to preserve the full value, you should use the [`Sequence`] type instead. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::relative; - /// - /// // Values with bit 22 set to 0 will be interpreted as height-based lock times. - /// let height: u32 = 144; // 144 blocks, approx 24h. - /// let lock_time = relative::LockTime::from_consensus(height)?; - /// assert!(lock_time.is_block_height()); - /// assert_eq!(lock_time.to_consensus_u32(), height); - /// - /// // Values with bit 22 set to 1 will be interpreted as time-based lock times. - /// let time: u32 = 168 | (1 << 22) ; // Bit 22 is 1 with time approx 24h. - /// let lock_time = relative::LockTime::from_consensus(time)?; - /// assert!(lock_time.is_block_time()); - /// assert_eq!(lock_time.to_consensus_u32(), time); - /// - /// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(()) - /// ``` - #[inline] - pub fn from_consensus(n: u32) -> Result { - let sequence = crate::Sequence::from_consensus(n); - sequence.to_relative_lock_time().ok_or(DisabledLockTimeError(n)) - } - - /// Returns the `u32` value used to encode this locktime in an `nSequence` field or - /// argument to `OP_CHECKSEQUENCEVERIFY`. - /// - /// # Warning - /// - /// Locktimes are not ordered by the natural ordering on `u32`. If you want to - /// compare locktimes, use [`Self::is_implied_by`] or similar methods. - #[inline] - pub fn to_consensus_u32(self) -> u32 { - match self { - LockTime::Blocks(ref h) => u32::from(h.to_height()), - LockTime::Time(ref t) => - Sequence::LOCK_TYPE_MASK | u32::from(t.to_512_second_intervals()), - } - } - - /// Constructs a new `LockTime` from the sequence number of a Bitcoin input. - /// - /// This method will **not** round-trip with [`Self::to_sequence`]. See the - /// docs for [`Self::from_consensus`] for more information. - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::{Sequence, relative}; - /// - /// // Interpret a sequence number from a Bitcoin transaction input as a relative lock time - /// let sequence_number = Sequence::from_consensus(144); // 144 blocks, approx 24h. - /// let lock_time = relative::LockTime::from_sequence(sequence_number)?; - /// assert!(lock_time.is_block_height()); - /// - /// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(()) - /// ``` - #[inline] - pub fn from_sequence(n: Sequence) -> Result { - Self::from_consensus(n.to_consensus_u32()) - } - - /// Encodes the locktime as a sequence number. - #[inline] - pub fn to_sequence(self) -> Sequence { Sequence::from_consensus(self.to_consensus_u32()) } - - /// Constructs a new `LockTime` from `n`, expecting `n` to be a 16-bit count of blocks. - #[inline] - pub const fn from_height(n: u16) -> Self { LockTime::Blocks(NumberOfBlocks::from_height(n)) } - - /// Constructs a new `LockTime` from `n`, expecting `n` to be a count of 512-second intervals. - /// - /// This function is a little awkward to use, and users may wish to instead use - /// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`]. - #[inline] - pub const fn from_512_second_intervals(intervals: u16) -> Self { - LockTime::Time(NumberOf512Seconds::from_512_second_intervals(intervals)) - } - - /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval - /// with truncating division. - /// - /// # Errors - /// - /// Will return an error if the input cannot be encoded in 16 bits. - #[inline] - pub const fn from_seconds_floor(seconds: u32) -> Result { - match NumberOf512Seconds::from_seconds_floor(seconds) { - Ok(time) => Ok(LockTime::Time(time)), - Err(e) => Err(e), - } - } - - /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval - /// with ceiling division. - /// - /// # Errors - /// - /// Will return an error if the input cannot be encoded in 16 bits. - #[inline] - pub const fn from_seconds_ceil(seconds: u32) -> Result { - match NumberOf512Seconds::from_seconds_ceil(seconds) { - Ok(time) => Ok(LockTime::Time(time)), - Err(e) => Err(e), - } - } - - /// Returns true if both lock times use the same unit i.e., both height based or both time based. - #[inline] - pub const fn is_same_unit(self, other: LockTime) -> bool { - matches!( - (self, other), - (LockTime::Blocks(_), LockTime::Blocks(_)) | (LockTime::Time(_), LockTime::Time(_)) - ) - } - - /// Returns true if this lock time value is in units of block height. - #[inline] - pub const fn is_block_height(self) -> bool { matches!(self, LockTime::Blocks(_)) } - - /// Returns true if this lock time value is in units of time. - #[inline] - pub const fn is_block_time(self) -> bool { !self.is_block_height() } - - /// Returns true if this [`relative::LockTime`] is satisfied by the given chain state. - /// - /// If this function returns true then an output with this locktime can be spent in the next - /// block. - /// - /// # Errors - /// - /// If `chain_tip` as not _after_ `utxo_mined_at` i.e., if you get the args mixed up. - pub fn is_satisfied_by( - self, - chain_tip_height: BlockHeight, - chain_tip_mtp: BlockMtp, - utxo_mined_at_height: BlockHeight, - utxo_mined_at_mtp: BlockMtp, - ) -> Result { - match self { - LockTime::Blocks(blocks) => blocks - .is_satisfied_by(chain_tip_height, utxo_mined_at_height) - .map_err(IsSatisfiedByError::Blocks), - LockTime::Time(time) => time - .is_satisfied_by(chain_tip_mtp, utxo_mined_at_mtp) - .map_err(IsSatisfiedByError::Time), - } - } - - /// Returns true if an output with this locktime can be spent in the next block. - /// - /// If this function returns true then an output with this locktime can be spent in the next - /// block. - /// - /// # Errors - /// - /// Returns an error if this lock is not lock-by-height. - #[inline] - pub fn is_satisfied_by_height( - self, - chain_tip: BlockHeight, - utxo_mined_at: BlockHeight, - ) -> Result { - use LockTime as L; - - match self { - L::Blocks(blocks) => blocks - .is_satisfied_by(chain_tip, utxo_mined_at) - .map_err(IsSatisfiedByHeightError::Satisfaction), - L::Time(time) => Err(IsSatisfiedByHeightError::Incompatible(time)), - } - } - - /// Returns true if an output with this locktime can be spent in the next block. - /// - /// If this function returns true then an output with this locktime can be spent in the next - /// block. - /// - /// # Errors - /// - /// Returns an error if this lock is not lock-by-time. - #[inline] - pub fn is_satisfied_by_time( - self, - chain_tip: BlockMtp, - utxo_mined_at: BlockMtp, - ) -> Result { - use LockTime as L; - - match self { - L::Time(time) => time - .is_satisfied_by(chain_tip, utxo_mined_at) - .map_err(IsSatisfiedByTimeError::Satisfaction), - L::Blocks(blocks) => Err(IsSatisfiedByTimeError::Incompatible(blocks)), - } - } - - /// Returns true if satisfaction of `other` lock time implies satisfaction of this - /// [`relative::LockTime`]. - /// - /// A lock time can only be satisfied by n blocks being mined or n seconds passing. If you have - /// two lock times (same unit) then the larger lock time being satisfied implies (in a - /// mathematical sense) the smaller one being satisfied. - /// - /// This function is useful when checking sequence values against a lock, first one checks the - /// sequence represents a relative lock time by converting to `LockTime` then use this function - /// to see if satisfaction of the newly created lock time would imply satisfaction of `self`. - /// - /// Can also be used to remove the smaller value of two `OP_CHECKSEQUENCEVERIFY` operations - /// within one branch of the script. - /// - /// # Examples - /// - /// ```rust - /// # use bitcoin_primitives::Sequence; - /// - /// # let required_height = 100; // 100 blocks. - /// # let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height"); - /// # let test_sequence = Sequence::from_height(required_height + 10); - /// - /// let satisfied = match test_sequence.to_relative_lock_time() { - /// None => false, // Handle non-lock-time case. - /// Some(test_lock) => lock.is_implied_by(test_lock), - /// }; - /// assert!(satisfied); - /// ``` - #[inline] - pub fn is_implied_by(self, other: LockTime) -> bool { - use LockTime as L; - - match (self, other) { - (L::Blocks(this), L::Blocks(other)) => this <= other, - (L::Time(this), L::Time(other)) => this <= other, - _ => false, // Not the same units. - } - } - - /// Returns true if satisfaction of the sequence number implies satisfaction of this lock time. - /// - /// When deciding whether an instance of ` CHECKSEQUENCEVERIFY` will pass, this - /// method can be used by parsing `n` as a [`LockTime`] and calling this method - /// with the sequence number of the input which spends the script. - /// - /// # Examples - /// - /// ``` - /// # use bitcoin_primitives::{Sequence, relative}; - /// - /// let sequence = Sequence::from_consensus(1 << 22 | 168); // Bit 22 is 1 with time approx 24h. - /// let lock_time = relative::LockTime::from_sequence(sequence)?; - /// let input_sequence = Sequence::from_consensus(1 << 22 | 336); // Approx 48h. - /// assert!(lock_time.is_block_time()); - /// - /// assert!(lock_time.is_implied_by_sequence(input_sequence)); - /// - /// # Ok::<_, bitcoin_primitives::relative::DisabledLockTimeError>(()) - /// ``` - #[inline] - pub fn is_implied_by_sequence(self, other: Sequence) -> bool { - if let Ok(other) = LockTime::from_sequence(other) { - self.is_implied_by(other) - } else { - false - } - } -} - -impl From for LockTime { - #[inline] - fn from(h: NumberOfBlocks) -> Self { LockTime::Blocks(h) } -} - -impl From for LockTime { - #[inline] - fn from(t: NumberOf512Seconds) -> Self { LockTime::Time(t) } -} - -impl fmt::Display for LockTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use LockTime as L; - - if f.alternate() { - match *self { - L::Blocks(ref h) => write!(f, "block-height {}", h), - L::Time(ref t) => write!(f, "block-time {} (512 second intervals)", t), - } - } else { - match *self { - L::Blocks(ref h) => fmt::Display::fmt(h, f), - L::Time(ref t) => fmt::Display::fmt(t, f), - } - } - } -} - -impl convert::TryFrom for LockTime { - type Error = DisabledLockTimeError; - #[inline] - fn try_from(seq: Sequence) -> Result { - LockTime::from_sequence(seq) - } -} - -impl From for Sequence { - #[inline] - fn from(lt: LockTime) -> Sequence { lt.to_sequence() } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for LockTime { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.to_consensus_u32().serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for LockTime { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - u32::deserialize(deserializer) - .and_then(|n| Self::from_consensus(n).map_err(serde::de::Error::custom)) - } -} - -/// Error returned when a sequence number is parsed as a lock time, but its -/// "disable" flag is set. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct DisabledLockTimeError(u32); - -impl DisabledLockTimeError { - /// Accessor for the `u32` whose "disable" flag was set, preventing - /// it from being parsed as a relative locktime. - #[inline] - pub fn disabled_locktime_value(&self) -> u32 { self.0 } -} - -impl fmt::Display for DisabledLockTimeError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "lock time 0x{:08x} has disable flag set", self.0) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for DisabledLockTimeError {} - -/// Error returned when attempting to satisfy lock fails. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum IsSatisfiedByError { - /// Error when attempting to satisfy lock by height. - Blocks(InvalidHeightError), - /// Error when attempting to satisfy lock by time. - Time(InvalidTimeError), -} - -impl fmt::Display for IsSatisfiedByError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use IsSatisfiedByError as E; - - match *self { - E::Blocks(ref e) => write_err!(f, "blocks"; e), - E::Time(ref e) => write_err!(f, "time"; e), - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for IsSatisfiedByError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use IsSatisfiedByError as E; - - match *self { - E::Blocks(ref e) => Some(e), - E::Time(ref e) => Some(e), - } - } -} - -/// Error returned when `is_satisfied_by_height` fails. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum IsSatisfiedByHeightError { - /// Satisfaction of the lock height value failed. - Satisfaction(InvalidHeightError), - /// Tried to satisfy a lock-by-height locktime using seconds. - // TODO: Hide inner value in a new struct error type. - Incompatible(NumberOf512Seconds), -} - -impl fmt::Display for IsSatisfiedByHeightError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use IsSatisfiedByHeightError as E; - - match *self { - E::Satisfaction(ref e) => write_err!(f, "satisfaction"; e), - E::Incompatible(time) => - write!(f, "tried to satisfy a lock-by-height locktime using seconds {}", time), - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for IsSatisfiedByHeightError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use IsSatisfiedByHeightError as E; - - match *self { - E::Satisfaction(ref e) => Some(e), - E::Incompatible(_) => None, - } - } -} - -/// Error returned when `is_satisfied_by_time` fails. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum IsSatisfiedByTimeError { - /// Satisfaction of the lock time value failed. - Satisfaction(InvalidTimeError), - /// Tried to satisfy a lock-by-time locktime using number of blocks. - // TODO: Hide inner value in a new struct error type. - Incompatible(NumberOfBlocks), -} - -impl fmt::Display for IsSatisfiedByTimeError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use IsSatisfiedByTimeError as E; - - match *self { - E::Satisfaction(ref e) => write_err!(f, "satisfaction"; e), - E::Incompatible(blocks) => - write!(f, "tried to satisfy a lock-by-height locktime using blocks {}", blocks), - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for IsSatisfiedByTimeError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use IsSatisfiedByTimeError as E; - - match *self { - E::Satisfaction(ref e) => Some(e), - E::Incompatible(_) => None, - } - } -} - -#[cfg(feature = "arbitrary")] -impl<'a> Arbitrary<'a> for LockTime { - fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - match bool::arbitrary(u)? { - true => Ok(LockTime::Blocks(NumberOfBlocks::arbitrary(u)?)), - false => Ok(LockTime::Time(NumberOf512Seconds::arbitrary(u)?)), - } - } -} - -#[cfg(test)] -mod tests { - use units::{BlockHeight, BlockTime}; - - use super::*; - - #[test] - fn display_and_alternate() { - let lock_by_height = LockTime::from_height(10); - let lock_by_time = LockTime::from_512_second_intervals(70); - - assert_eq!(format!("{}", lock_by_height), "10"); - assert_eq!(format!("{:#}", lock_by_height), "block-height 10"); - assert!(!format!("{:?}", lock_by_height).is_empty()); - - assert_eq!(format!("{}", lock_by_time), "70"); - assert_eq!(format!("{:#}", lock_by_time), "block-time 70 (512 second intervals)"); - assert!(!format!("{:?}", lock_by_time).is_empty()); - } - - #[test] - fn from_seconds_ceil_and_floor() { - let time = 70 * 512 + 1; - let lock_by_time = LockTime::from_seconds_ceil(time).unwrap(); - assert_eq!(lock_by_time, LockTime::from_512_second_intervals(71)); - - let lock_by_time = LockTime::from_seconds_floor(time).unwrap(); - assert_eq!(lock_by_time, LockTime::from_512_second_intervals(70)); - - let mut max_time = 0xffff * 512; - assert_eq!(LockTime::from_seconds_ceil(max_time), LockTime::from_seconds_floor(max_time)); - max_time += 512; - assert!(LockTime::from_seconds_ceil(max_time).is_err()); - assert!(LockTime::from_seconds_floor(max_time).is_err()); - } - - #[test] - fn parses_correctly_to_height_or_time() { - let height1 = NumberOfBlocks::from(10); - let height2 = NumberOfBlocks::from(11); - let time1 = NumberOf512Seconds::from_512_second_intervals(70); - let time2 = NumberOf512Seconds::from_512_second_intervals(71); - - let lock_by_height1 = LockTime::from(height1); - let lock_by_height2 = LockTime::from(height2); - let lock_by_time1 = LockTime::from(time1); - let lock_by_time2 = LockTime::from(time2); - - assert!(lock_by_height1.is_block_height()); - assert!(!lock_by_height1.is_block_time()); - - assert!(!lock_by_time1.is_block_height()); - assert!(lock_by_time1.is_block_time()); - - // Test is_same_unit() logic - assert!(lock_by_height1.is_same_unit(lock_by_height2)); - assert!(!lock_by_height1.is_same_unit(lock_by_time1)); - assert!(lock_by_time1.is_same_unit(lock_by_time2)); - assert!(!lock_by_time1.is_same_unit(lock_by_height1)); - } - - #[test] - fn height_correctly_implies() { - let height = NumberOfBlocks::from(10); - let lock_by_height = LockTime::from(height); - - assert!(!lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(9)))); - assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(10)))); - assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(11)))); - } - - #[test] - fn time_correctly_implies() { - let time = NumberOf512Seconds::from_512_second_intervals(70); - let lock_by_time = LockTime::from(time); - - assert!(!lock_by_time - .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(69)))); - assert!(lock_by_time - .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(70)))); - assert!(lock_by_time - .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(71)))); - } - - #[test] - fn sequence_correctly_implies() { - let height = NumberOfBlocks::from(10); - let time = NumberOf512Seconds::from_512_second_intervals(70); - - let lock_by_height = LockTime::from(height); - let lock_by_time = LockTime::from(time); - - let seq_height = Sequence::from(lock_by_height); - let seq_time = Sequence::from(lock_by_time); - - assert!(lock_by_height.is_implied_by_sequence(seq_height)); - assert!(!lock_by_height.is_implied_by_sequence(seq_time)); - - assert!(lock_by_time.is_implied_by_sequence(seq_time)); - assert!(!lock_by_time.is_implied_by_sequence(seq_height)); - - let disabled_sequence = Sequence::from_consensus(1 << 31); - assert!(!lock_by_height.is_implied_by_sequence(disabled_sequence)); - assert!(!lock_by_time.is_implied_by_sequence(disabled_sequence)); - } - - #[test] - fn incorrect_units_do_not_imply() { - let time = NumberOf512Seconds::from_512_second_intervals(70); - let height = NumberOfBlocks::from(10); - - let lock_by_time = LockTime::from(time); - assert!(!lock_by_time.is_implied_by(LockTime::from(height))); - } - - #[test] - fn consensus_round_trip() { - assert!(LockTime::from_consensus(1 << 31).is_err()); - assert!(LockTime::from_consensus(1 << 30).is_ok()); - // Relative locktimes do not care about bits 17 through 21. - assert_eq!(LockTime::from_consensus(65536), LockTime::from_consensus(0)); - - for val in [0u32, 1, 1000, 65535] { - let seq = Sequence::from_consensus(val); - let lt = LockTime::from_consensus(val).unwrap(); - assert_eq!(lt.to_consensus_u32(), val); - assert_eq!(lt.to_sequence(), seq); - assert_eq!(LockTime::from_sequence(seq).unwrap().to_sequence(), seq); - - let seq = Sequence::from_consensus(val + (1 << 22)); - let lt = LockTime::from_consensus(val + (1 << 22)).unwrap(); - assert_eq!(lt.to_consensus_u32(), val + (1 << 22)); - assert_eq!(lt.to_sequence(), seq); - assert_eq!(LockTime::from_sequence(seq).unwrap().to_sequence(), seq); - } - } - - #[test] - fn disabled_locktime_error() { - let disabled_sequence = Sequence::from_consensus(1 << 31); - let err = LockTime::try_from(disabled_sequence).unwrap_err(); - - assert_eq!(err.disabled_locktime_value(), 1 << 31); - assert!(!format!("{}", err).is_empty()); - } - - #[test] - fn incompatible_height_error() { - // This is an error test these values are not used in the error path. - let mined_at = BlockHeight::from_u32(700_000); - let chain_tip = BlockHeight::from_u32(800_000); - - let lock_by_time = LockTime::from_512_second_intervals(70); // Arbitrary value. - let err = lock_by_time.is_satisfied_by_height(chain_tip, mined_at).unwrap_err(); - - let expected_time = NumberOf512Seconds::from_512_second_intervals(70); - assert_eq!(err, IsSatisfiedByHeightError::Incompatible(expected_time)); - assert!(!format!("{}", err).is_empty()); - } - - #[test] - fn incompatible_time_error() { - // This is an error test these values are not used in the error path. - let mined_at = BlockMtp::from_u32(1_234_567_890); - let chain_tip = BlockMtp::from_u32(1_600_000_000); - - let lock_by_height = LockTime::from_height(10); // Arbitrary value. - let err = lock_by_height.is_satisfied_by_time(chain_tip, mined_at).unwrap_err(); - - let expected_height = NumberOfBlocks::from(10); - assert_eq!(err, IsSatisfiedByTimeError::Incompatible(expected_height)); - assert!(!format!("{}", err).is_empty()); - } - - #[test] - fn test_locktime_chain_state() { - fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] { - let mut timestamps = [BlockTime::from_u32(0); 11]; - for (i, ts) in timestamps.iter_mut().enumerate() { - *ts = BlockTime::from_u32(start.saturating_sub((step * i as u16).into())); - } - timestamps - } - - let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200); - let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200); - - let chain_height = BlockHeight::from_u32(100); - let chain_mtp = BlockMtp::new(timestamps); - let utxo_height = BlockHeight::from_u32(80); - let utxo_mtp = BlockMtp::new(utxo_timestamps); - - let lock1 = LockTime::Blocks(NumberOfBlocks::from(10)); - assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); - - let lock2 = LockTime::Blocks(NumberOfBlocks::from(21)); - assert!(lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); - - let lock3 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(10)); - assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); - - let lock4 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(20000)); - assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); - - assert!(LockTime::ZERO - .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) - .unwrap()); - assert!(LockTime::from_512_second_intervals(0) - .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) - .unwrap()); - - let lock6 = LockTime::from_seconds_floor(5000).unwrap(); - assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); - - let max_height_lock = LockTime::Blocks(NumberOfBlocks::MAX); - assert!(!max_height_lock - .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) - .unwrap()); - - let max_time_lock = LockTime::Time(NumberOf512Seconds::MAX); - assert!(!max_time_lock - .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) - .unwrap()); - - let max_chain_height = BlockHeight::from_u32(u32::MAX); - let max_chain_mtp = BlockMtp::new(generate_timestamps(u32::MAX, 100)); - let max_utxo_height = BlockHeight::MAX; - let max_utxo_mtp = max_chain_mtp; - assert!(!max_height_lock - .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp) - .unwrap()); - assert!(!max_time_lock - .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp) - .unwrap()); - } -} diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 6dec85fa60..b3f24e8bd8 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -24,20 +24,20 @@ use hashes::sha256d; use internals::compact_size; #[cfg(feature = "hex")] use internals::write_err; +#[cfg(feature = "alloc")] +use units::locktime::absolute; #[cfg(feature = "hex")] use units::parse; #[cfg(feature = "alloc")] +use units::sequence::Sequence; +#[cfg(feature = "alloc")] use units::{Amount, Weight}; -#[cfg(feature = "alloc")] -use crate::locktime::absolute; #[cfg(feature = "alloc")] use crate::prelude::Vec; #[cfg(feature = "alloc")] use crate::script::ScriptBuf; #[cfg(feature = "alloc")] -use crate::sequence::Sequence; -#[cfg(feature = "alloc")] use crate::witness::Witness; /// Bitcoin transaction. diff --git a/primitives/tests/api.rs b/primitives/tests/api.rs index 4cedc5ec84..4fd534039a 100644 --- a/primitives/tests/api.rs +++ b/primitives/tests/api.rs @@ -163,10 +163,10 @@ struct Default { #[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG). struct Errors { a: transaction::ParseOutPointError, - b: relative::DisabledLockTimeError, - c: relative::IsSatisfiedByError, - d: relative::IsSatisfiedByHeightError, - e: relative::IsSatisfiedByTimeError, + b: relative::error::DisabledLockTimeError, + c: relative::error::IsSatisfiedByError, + d: relative::error::IsSatisfiedByHeightError, + e: relative::error::IsSatisfiedByTimeError, f: script::RedeemScriptSizeError, g: script::WitnessScriptSizeError, } @@ -209,9 +209,10 @@ fn api_can_use_types_from_crate_root() { #[test] fn api_can_use_all_types_from_module_locktime() { - use bitcoin_primitives::locktime::relative::{ - DisabledLockTimeError, InvalidHeightError, InvalidTimeError, LockTime, + use bitcoin_primitives::locktime::relative::error::{ + DisabledLockTimeError, InvalidHeightError, InvalidTimeError, }; + use bitcoin_primitives::locktime::relative::LockTime; use bitcoin_primitives::locktime::{absolute, relative}; } diff --git a/units/Cargo.toml b/units/Cargo.toml index 8d943b44f0..64291d24d2 100644 --- a/units/Cargo.toml +++ b/units/Cargo.toml @@ -20,7 +20,7 @@ alloc = ["internals/alloc","serde?/alloc"] [dependencies] internals = { package = "bitcoin-internals", path = "../internals", version = "0.4.0" } -serde = { version = "1.0.103", default-features = false, optional = true } +serde = { version = "1.0.103", default-features = false, features = ["derive"], optional = true } arbitrary = { version = "1.4", optional = true } [dev-dependencies] diff --git a/units/src/lib.rs b/units/src/lib.rs index 56d173cfda..b10e1a3b36 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -51,6 +51,7 @@ pub mod fee; pub mod fee_rate; pub mod locktime; pub mod parse; +pub mod sequence; pub mod time; pub mod weight; @@ -60,7 +61,9 @@ pub use self::{ amount::{Amount, SignedAmount}, block::{BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval}, fee_rate::FeeRate, + locktime::{absolute, relative}, result::{NumOpError, NumOpResult, MathOp}, + sequence::Sequence, time::BlockTime, weight::Weight }; diff --git a/units/src/locktime/absolute/error.rs b/units/src/locktime/absolute/error.rs index 8d7abde220..96e125d038 100644 --- a/units/src/locktime/absolute/error.rs +++ b/units/src/locktime/absolute/error.rs @@ -7,9 +7,71 @@ use core::fmt; use internals::error::InputString; -use super::LOCK_TIME_THRESHOLD; +use super::{Height, MedianTimePast, LOCK_TIME_THRESHOLD}; use crate::parse::ParseIntError; +/// Tried to satisfy a lock-by-time lock using a height value. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IncompatibleHeightError { + /// The inner value of the lock-by-time lock. + pub(super) lock: MedianTimePast, + /// Attempted to satisfy a lock-by-time lock with this height. + pub(super) incompatible: Height, +} + +impl IncompatibleHeightError { + /// Returns the value of the lock-by-time lock. + pub fn lock(&self) -> MedianTimePast { self.lock } + + /// Returns the height that was erroneously used to try and satisfy a lock-by-time lock. + pub fn incompatible(&self) -> Height { self.incompatible } +} + +impl fmt::Display for IncompatibleHeightError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "tried to satisfy a lock-by-time lock {} with height: {}", + self.lock, self.incompatible + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IncompatibleHeightError {} + +/// Tried to satisfy a lock-by-height lock using a height value. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IncompatibleTimeError { + /// The inner value of the lock-by-height lock. + pub(super) lock: Height, + /// Attempted to satisfy a lock-by-height lock with this MTP. + pub(super) incompatible: MedianTimePast, +} + +impl IncompatibleTimeError { + /// Returns the value of the lock-by-height lock. + pub fn lock(&self) -> Height { self.lock } + + /// Returns the MTP that was erroneously used to try and satisfy a lock-by-height lock. + pub fn incompatible(&self) -> MedianTimePast { self.incompatible } +} + +impl fmt::Display for IncompatibleTimeError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "tried to satisfy a lock-by-height lock {} with MTP: {}", + self.lock, self.incompatible + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IncompatibleTimeError {} + /// Error returned when parsing block height fails. #[derive(Debug, Clone, Eq, PartialEq)] pub struct ParseHeightError(ParseError); @@ -200,12 +262,12 @@ impl fmt::Display for LockTimeUnit { #[cfg(test)] mod tests { - use super::*; - #[test] #[cfg(feature = "alloc")] fn locktime_unit_display() { use alloc::format; + use super::LockTimeUnit; + let blocks = LockTimeUnit::Blocks; let seconds = LockTimeUnit::Seconds; diff --git a/units/src/locktime/absolute/mod.rs b/units/src/locktime/absolute/mod.rs index 336c9a7a89..f4bc0239a5 100644 --- a/units/src/locktime/absolute/mod.rs +++ b/units/src/locktime/absolute/mod.rs @@ -1,6 +1,10 @@ // SPDX-License-Identifier: CC0-1.0 -//! Provides [`Height`] and [`MedianTimePast`] types used by the `rust-bitcoin` `absolute::LockTime` type. +//! Provides type [`LockTime`] that implements the logic around `nLockTime`/`OP_CHECKLOCKTIMEVERIFY`. +//! +//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by +//! whether `LockTime < LOCKTIME_THRESHOLD`. To support these we provide the [`Height`] and +//! [`MedianTimePast`] types. pub mod error; @@ -11,11 +15,15 @@ use arbitrary::{Arbitrary, Unstructured}; use internals::error::InputString; use self::error::ParseError; -use crate::parse; +#[cfg(doc)] +use crate::absolute; +use crate::parse::{self, PrefixedHexError, UnprefixedHexError}; #[rustfmt::skip] // Keep public re-exports separate. #[doc(no_inline)] -pub use self::error::{ConversionError, ParseHeightError, ParseTimeError}; +pub use self::error::{ + ConversionError, IncompatibleHeightError, IncompatibleTimeError, ParseHeightError, ParseTimeError, +}; /// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]). /// @@ -30,6 +38,410 @@ pub use self::error::{ConversionError, ParseHeightError, ParseTimeError}; /// [Bitcoin Core]: https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39 pub const LOCK_TIME_THRESHOLD: u32 = 500_000_000; +/// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds +/// since epoch). +/// +/// Used for transaction lock time (`nLockTime` in Bitcoin Core and `Transaction::lock_time` +/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKLOCKTIMEVERIFY`. +/// +/// # Note on ordering +/// +/// Locktimes may be height- or time-based, and these metrics are incommensurate; there is no total +/// ordering on locktimes. In order to compare locktimes, instead of using `<` or `>` we provide the +/// [`LockTime::is_satisfied_by`] API. +/// +/// For transaction, which has a locktime field, we implement a total ordering to make +/// it easy to store transactions in sorted data structures, and use the locktime's 32-bit integer +/// consensus encoding to order it. +/// +/// # Relevant BIPs +/// +/// * [BIP-65 OP_CHECKLOCKTIMEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) +/// * [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki) +/// +/// # Examples +/// +/// ``` +/// use bitcoin_units::absolute::{self, LockTime as L}; +/// # let n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY +/// # let lock_time = absolute::LockTime::from_consensus(741521); // nLockTime +/// // To compare absolute lock times there are various `is_satisfied_*` methods, you may also use: +/// let _is_satisfied = match (n, lock_time) { +/// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time, +/// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time, +/// _ => panic!("handle invalid comparison error"), +/// }; +/// ``` +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum LockTime { + /// A block height lock time value. + /// + /// # Examples + /// + /// ```rust + /// use bitcoin_units::absolute; + /// + /// let block: u32 = 741521; + /// let n = absolute::LockTime::from_height(block).expect("valid height"); + /// assert!(n.is_block_height()); + /// assert_eq!(n.to_consensus_u32(), block); + /// ``` + Blocks(Height), + /// A UNIX timestamp lock time value. + /// + /// # Examples + /// + /// ```rust + /// use bitcoin_units::absolute; + /// + /// let seconds: u32 = 1653195600; // May 22nd, 5am UTC. + /// let n = absolute::LockTime::from_mtp(seconds).expect("valid time"); + /// assert!(n.is_block_time()); + /// assert_eq!(n.to_consensus_u32(), seconds); + /// ``` + Seconds(MedianTimePast), +} + +impl LockTime { + /// If transaction lock time is set to zero it is ignored, in other words a + /// transaction with nLocktime==0 is able to be included immediately in any block. + pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO); + + /// The number of bytes that the locktime contributes to the size of a transaction. + pub const SIZE: usize = 4; // Serialized length of a u32. + + /// Constructs a new `LockTime` from a prefixed hex string. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::{absolute, parse}; + /// let hex_str = "0x61cf9980"; // Unix timestamp for January 1, 2022 + /// let lock_time = absolute::LockTime::from_hex(hex_str)?; + /// assert_eq!(lock_time.to_consensus_u32(), 0x61cf9980); + /// + /// # Ok::<_, parse::PrefixedHexError>(()) + /// ``` + #[inline] + pub fn from_hex(s: &str) -> Result { + let lock_time = parse::hex_u32_prefixed(s)?; + Ok(Self::from_consensus(lock_time)) + } + + /// Constructs a new `LockTime` from an unprefixed hex string. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::{absolute, parse}; + /// let hex_str = "61cf9980"; // Unix timestamp for January 1, 2022 + /// let lock_time = absolute::LockTime::from_unprefixed_hex(hex_str)?; + /// assert_eq!(lock_time.to_consensus_u32(), 0x61cf9980); + /// + /// # Ok::<_, parse::UnprefixedHexError>(()) + /// ``` + #[inline] + pub fn from_unprefixed_hex(s: &str) -> Result { + let lock_time = parse::hex_u32_unprefixed(s)?; + Ok(Self::from_consensus(lock_time)) + } + + /// Constructs a new `LockTime` from an `nLockTime` value or the argument to `OP_CHEKCLOCKTIMEVERIFY`. + /// + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::absolute; + /// + /// // `from_consensus` roundtrips as expected with `to_consensus_u32`. + /// let n_lock_time: u32 = 741521; + /// let lock_time = absolute::LockTime::from_consensus(n_lock_time); + /// assert_eq!(lock_time.to_consensus_u32(), n_lock_time); + #[inline] + #[allow(clippy::missing_panics_doc)] + pub fn from_consensus(n: u32) -> Self { + if crate::locktime::absolute::is_block_height(n) { + Self::Blocks(Height::from_u32(n).expect("n is valid")) + } else { + Self::Seconds(MedianTimePast::from_u32(n).expect("n is valid")) + } + } + + /// Constructs a new `LockTime` from `n`, expecting `n` to be a valid block height. + /// + /// # Note + /// + /// If the current block height is `h` and the locktime is set to `h`, + /// the transaction can be included in block `h+1` or later. + /// It is possible to broadcast the transaction at block height `h`. + /// + /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid height value. + /// + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::absolute; + /// assert!(absolute::LockTime::from_height(741521).is_ok()); + /// assert!(absolute::LockTime::from_height(1653195600).is_err()); + /// ``` + #[inline] + pub fn from_height(n: u32) -> Result { + let height = Height::from_u32(n)?; + Ok(LockTime::Blocks(height)) + } + + #[inline] + #[deprecated(since = "TBD", note = "use `from_mtp` instead")] + #[doc(hidden)] + pub fn from_time(n: u32) -> Result { Self::from_mtp(n) } + + /// Constructs a new `LockTime` from `n`, expecting `n` to be a median-time-past (MTP) + /// which is in range for a locktime. + /// + /// # Note + /// + /// If the locktime is set to an MTP `T`, the transaction can be included in a block only if + /// the MTP of last recent 11 blocks is greater than `T`. + /// + /// It is possible to broadcast the transaction once the MTP is greater than `T`. See BIP-113. + /// + /// [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki) + /// + /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid time value. + /// + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::absolute; + /// assert!(absolute::LockTime::from_mtp(1653195600).is_ok()); + /// assert!(absolute::LockTime::from_mtp(741521).is_err()); + /// ``` + #[inline] + pub fn from_mtp(n: u32) -> Result { + let time = MedianTimePast::from_u32(n)?; + Ok(LockTime::Seconds(time)) + } + + /// Returns true if both lock times use the same unit i.e., both height based or both time based. + #[inline] + pub const fn is_same_unit(self, other: LockTime) -> bool { + matches!( + (self, other), + (LockTime::Blocks(_), LockTime::Blocks(_)) + | (LockTime::Seconds(_), LockTime::Seconds(_)) + ) + } + + /// Returns true if this lock time value is a block height. + #[inline] + pub const fn is_block_height(self) -> bool { matches!(self, LockTime::Blocks(_)) } + + /// Returns true if this lock time value is a block time (UNIX timestamp). + #[inline] + pub const fn is_block_time(self) -> bool { !self.is_block_height() } + + /// Returns true if this timelock constraint is satisfied by the respective `height`/`time`. + /// + /// If `self` is a blockheight based lock then it is checked against `height` and if `self` is a + /// blocktime based lock it is checked against `time`. + /// + /// A 'timelock constraint' refers to the `n` from `n OP_CHEKCLOCKTIMEVERIFY`, this constraint + /// is satisfied if a transaction with `nLockTime` set to `height`/`time` is valid. + /// + /// If `height` and `mtp` represent the current chain tip then a transaction with this + /// locktime can be broadcast for inclusion in the next block. + /// + /// If you do not have, or do not wish to calculate, both parameters consider using: + /// + /// * [`is_satisfied_by_height()`](absolute::LockTime::is_satisfied_by_height) + /// * [`is_satisfied_by_time()`](absolute::LockTime::is_satisfied_by_time) + /// + /// # Examples + /// + /// ```no_run + /// # use bitcoin_units::absolute; + /// // Can be implemented if block chain data is available. + /// fn get_height() -> absolute::Height { todo!("return the current block height") } + /// fn get_time() -> absolute::MedianTimePast { todo!("return the current block MTP") } + /// + /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`. + /// if n.is_satisfied_by(get_height(), get_time()) { + /// // Can create and mine a transaction that satisfies the OP_CLTV timelock constraint. + /// } + /// ```` + #[inline] + pub fn is_satisfied_by(self, height: Height, mtp: MedianTimePast) -> bool { + match self { + LockTime::Blocks(blocks) => blocks.is_satisfied_by(height), + LockTime::Seconds(time) => time.is_satisfied_by(mtp), + } + } + + /// Returns true if a transaction with this locktime can be spent in the next block. + /// + /// If `height` is the current block height of the chain then a transaction with this locktime + /// can be broadcast for inclusion in the next block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-height. + #[inline] + pub fn is_satisfied_by_height(self, height: Height) -> Result { + use LockTime as L; + + match self { + L::Blocks(blocks) => Ok(blocks.is_satisfied_by(height)), + L::Seconds(time) => Err(IncompatibleHeightError { lock: time, incompatible: height }), + } + } + + /// Returns true if a transaction with this locktime can be included in the next block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-time. + #[inline] + pub fn is_satisfied_by_time(self, mtp: MedianTimePast) -> Result { + use LockTime as L; + + match self { + L::Seconds(time) => Ok(time.is_satisfied_by(mtp)), + L::Blocks(blocks) => Err(IncompatibleTimeError { lock: blocks, incompatible: mtp }), + } + } + + /// Returns true if satisfaction of `other` lock time implies satisfaction of this + /// [`absolute::LockTime`]. + /// + /// A lock time can only be satisfied by n blocks being mined or n seconds passing. If you have + /// two lock times (same unit) then the larger lock time being satisfied implies (in a + /// mathematical sense) the smaller one being satisfied. + /// + /// This function serves multiple purposes: + /// + /// * When evaluating `OP_CHECKLOCKTIMEVERIFY` the argument must be less than or equal to the + /// transactions nLockTime. If using this function to validate a script `self` is the argument + /// to `CLTV` and `other` is the transaction nLockTime. + /// + /// * If you wish to check a lock time against various other locks e.g., filtering out locks + /// which cannot be satisfied. Can also be used to remove the smaller value of two + /// `OP_CHECKLOCKTIMEVERIFY` operations within one branch of the script. + /// + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::absolute; + /// let lock_time = absolute::LockTime::from_consensus(741521); + /// let check = absolute::LockTime::from_consensus(741521 + 1); + /// assert!(lock_time.is_implied_by(check)); + /// ``` + #[inline] + pub fn is_implied_by(self, other: LockTime) -> bool { + use LockTime as L; + + match (self, other) { + (L::Blocks(this), L::Blocks(other)) => this <= other, + (L::Seconds(this), L::Seconds(other)) => this <= other, + _ => false, // Not the same units. + } + } + + /// Returns the inner `u32` value. This is the value used when creating this `LockTime` + /// i.e., `n OP_CHECKLOCKTIMEVERIFY` or `nLockTime`. + /// + /// # Warning + /// + /// Do not compare values return by this method. The whole point of the `LockTime` type is to + /// assist in doing correct comparisons. Either use `is_satisfied_by`, `is_satisfied_by_lock`, + /// or use the pattern below: + /// + /// # Examples + /// + /// ```rust + /// use bitcoin_units::absolute::{self, LockTime as L}; + /// # let n = absolute::LockTime::from_consensus(741521); // n OP_CHECKLOCKTIMEVERIFY + /// # let lock_time = absolute::LockTime::from_consensus(741521 + 1); // nLockTime + /// + /// let _is_satisfied = match (n, lock_time) { + /// (L::Blocks(n), L::Blocks(lock_time)) => n <= lock_time, + /// (L::Seconds(n), L::Seconds(lock_time)) => n <= lock_time, + /// _ => panic!("invalid comparison"), + /// }; + /// + /// // Or, if you have Rust 1.53 or greater + /// // let is_satisfied = n.partial_cmp(&lock_time).expect("invalid comparison").is_le(); + /// ``` + #[inline] + pub fn to_consensus_u32(self) -> u32 { + match self { + LockTime::Blocks(ref h) => h.to_u32(), + LockTime::Seconds(ref t) => t.to_u32(), + } + } +} + +crate::impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus); + +impl From for LockTime { + #[inline] + fn from(h: Height) -> Self { LockTime::Blocks(h) } +} + +impl From for LockTime { + #[inline] + fn from(t: MedianTimePast) -> Self { LockTime::Seconds(t) } +} + +impl fmt::Debug for LockTime { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use LockTime as L; + + match *self { + L::Blocks(ref h) => write!(f, "{} blocks", h), + L::Seconds(ref t) => write!(f, "{} seconds", t), + } + } +} + +impl fmt::Display for LockTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use LockTime as L; + + if f.alternate() { + match *self { + L::Blocks(ref h) => write!(f, "block-height {}", h), + L::Seconds(ref t) => write!(f, "block-time {} (seconds since epoch)", t), + } + } else { + match *self { + L::Blocks(ref h) => fmt::Display::fmt(h, f), + L::Seconds(ref t) => fmt::Display::fmt(t, f), + } + } + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for LockTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_consensus_u32().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for LockTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + u32::deserialize(deserializer).map(Self::from_consensus) + } +} + /// An absolute block height, guaranteed to always contain a valid height value. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Height(u32); @@ -76,7 +488,7 @@ impl Height { /// let h: u32 = 741521; /// let height = absolute::Height::from_u32(h)?; /// assert_eq!(height.to_u32(), h); - /// # Ok::<_, absolute::ConversionError>(()) + /// # Ok::<_, absolute::error::ConversionError>(()) /// ``` #[inline] pub const fn from_u32(n: u32) -> Result { @@ -190,7 +602,7 @@ impl MedianTimePast { /// let t: u32 = 1653195600; // May 22nd, 5am UTC. /// let time = absolute::MedianTimePast::from_u32(t)?; /// assert_eq!(time.to_u32(), t); - /// # Ok::<_, absolute::ConversionError>(()) + /// # Ok::<_, absolute::error::ConversionError>(()) /// ``` #[inline] pub const fn from_u32(n: u32) -> Result { @@ -263,6 +675,14 @@ pub const fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD } /// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000. pub const fn is_block_time(n: u32) -> bool { n >= LOCK_TIME_THRESHOLD } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for LockTime { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let l = u32::arbitrary(u)?; + Ok(LockTime::from_consensus(l)) + } +} + #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Height { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { @@ -299,8 +719,152 @@ impl<'a> Arbitrary<'a> for MedianTimePast { #[cfg(test)] mod tests { + #[cfg(feature = "alloc")] + use alloc::format; + use super::*; + #[test] + #[cfg(feature = "alloc")] + fn display_and_alternate() { + let lock_by_height = LockTime::from_height(741_521).unwrap(); + let lock_by_time = LockTime::from_mtp(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC. + + assert_eq!(format!("{}", lock_by_height), "741521"); + assert_eq!(format!("{:#}", lock_by_height), "block-height 741521"); + assert!(!format!("{:?}", lock_by_height).is_empty()); + + assert_eq!(format!("{}", lock_by_time), "1653195600"); + assert_eq!(format!("{:#}", lock_by_time), "block-time 1653195600 (seconds since epoch)"); + assert!(!format!("{:?}", lock_by_time).is_empty()); + } + + #[test] + fn roundtrips() { + let lock_by_height = LockTime::from_consensus(741_521); + let lock_by_time = LockTime::from_consensus(1_653_195_600); + + assert_eq!(lock_by_height.to_consensus_u32(), 741_521); + assert_eq!(lock_by_time.to_consensus_u32(), 1_653_195_600); + } + + #[test] + fn lock_time_from_hex_lower() { + let lock_by_time = LockTime::from_hex("0x6289c350").unwrap(); + assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); + } + + #[test] + fn lock_time_from_hex_upper() { + let lock_by_time = LockTime::from_hex("0X6289C350").unwrap(); + assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); + } + + #[test] + fn lock_time_from_unprefixed_hex_lower() { + let lock_by_time = LockTime::from_unprefixed_hex("6289c350").unwrap(); + assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); + } + + #[test] + fn lock_time_from_unprefixed_hex_upper() { + let lock_by_time = LockTime::from_unprefixed_hex("6289C350").unwrap(); + assert_eq!(lock_by_time, LockTime::from_consensus(0x6289_C350)); + } + + #[test] + fn invalid_hex() { + assert!(LockTime::from_hex("0xzb93").is_err()); + assert!(LockTime::from_unprefixed_hex("zb93").is_err()); + } + + #[test] + fn invalid_locktime_type() { + assert!(LockTime::from_height(499_999_999).is_ok()); // Below the threshold. + assert!(LockTime::from_height(500_000_000).is_err()); // The threshold. + assert!(LockTime::from_height(500_000_001).is_err()); // Above the threshold. + + assert!(LockTime::from_mtp(499_999_999).is_err()); // Below the threshold. + assert!(LockTime::from_mtp(500_000_000).is_ok()); // The threshold. + assert!(LockTime::from_mtp(500_000_001).is_ok()); // Above the threshold. + } + + #[test] + fn parses_correctly_to_height_or_time() { + let lock_by_height = LockTime::from_consensus(750_000); + + assert!(lock_by_height.is_block_height()); + assert!(!lock_by_height.is_block_time()); + + let t: u32 = 1_653_195_600; // May 22nd, 5am UTC. + let lock_by_time = LockTime::from_consensus(t); + + assert!(!lock_by_time.is_block_height()); + assert!(lock_by_time.is_block_time()); + + // Test is_same_unit() logic + assert!(lock_by_height.is_same_unit(LockTime::from_consensus(800_000))); + assert!(!lock_by_height.is_same_unit(lock_by_time)); + assert!(lock_by_time.is_same_unit(LockTime::from_consensus(1_653_282_000))); + assert!(!lock_by_time.is_same_unit(lock_by_height)); + } + + #[test] + fn satisfied_by_height() { + let height_below = Height::from_u32(700_000).unwrap(); + let height = Height::from_u32(750_000).unwrap(); + let height_above = Height::from_u32(800_000).unwrap(); + + let lock_by_height = LockTime::from(height); + + let t: u32 = 1_653_195_600; // May 22nd, 5am UTC. + let time = MedianTimePast::from_u32(t).unwrap(); + + assert!(!lock_by_height.is_satisfied_by(height_below, time)); + assert!(lock_by_height.is_satisfied_by(height, time)); + assert!(lock_by_height.is_satisfied_by(height_above, time)); + } + + #[test] + fn satisfied_by_time() { + let time_before = MedianTimePast::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC. + let time = MedianTimePast::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC. + let time_after = MedianTimePast::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC. + + let lock_by_time = LockTime::from(time); + + let height = Height::from_u32(800_000).unwrap(); + + assert!(!lock_by_time.is_satisfied_by(height, time_before)); + assert!(lock_by_time.is_satisfied_by(height, time)); + assert!(lock_by_time.is_satisfied_by(height, time_after)); + } + + #[test] + fn height_correctly_implies() { + let lock_by_height = LockTime::from_consensus(750_005); + + assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(750_004))); + assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_005))); + assert!(lock_by_height.is_implied_by(LockTime::from_consensus(750_006))); + } + + #[test] + fn time_correctly_implies() { + let t: u32 = 1_700_000_005; + let lock_by_time = LockTime::from_consensus(t); + + assert!(!lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_004))); + assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_005))); + assert!(lock_by_time.is_implied_by(LockTime::from_consensus(1_700_000_006))); + } + + #[test] + fn incorrect_units_do_not_imply() { + let lock_by_height = LockTime::from_consensus(750_005); + assert!(!lock_by_height.is_implied_by(LockTime::from_consensus(1_700_000_004))); + } + #[test] fn time_from_str_hex_happy_path() { let actual = MedianTimePast::from_hex("0x6289C350").unwrap(); diff --git a/units/src/locktime/relative/error.rs b/units/src/locktime/relative/error.rs index 04e5026aa0..d24ebfeb03 100644 --- a/units/src/locktime/relative/error.rs +++ b/units/src/locktime/relative/error.rs @@ -4,6 +4,135 @@ use core::fmt; +use internals::write_err; + +use super::{NumberOf512Seconds, NumberOfBlocks}; + +/// Error returned when a sequence number is parsed as a lock time, but its +/// "disable" flag is set. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct DisabledLockTimeError(pub(super) u32); + +impl DisabledLockTimeError { + /// Accessor for the `u32` whose "disable" flag was set, preventing + /// it from being parsed as a relative locktime. + #[inline] + pub fn disabled_locktime_value(&self) -> u32 { self.0 } +} + +impl fmt::Display for DisabledLockTimeError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "lock time 0x{:08x} has disable flag set", self.0) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for DisabledLockTimeError {} + +/// Error returned when attempting to satisfy lock fails. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum IsSatisfiedByError { + /// Error when attempting to satisfy lock by height. + Blocks(InvalidHeightError), + /// Error when attempting to satisfy lock by time. + Time(InvalidTimeError), +} + +impl fmt::Display for IsSatisfiedByError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use IsSatisfiedByError as E; + + match *self { + E::Blocks(ref e) => write_err!(f, "blocks"; e), + E::Time(ref e) => write_err!(f, "time"; e), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IsSatisfiedByError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use IsSatisfiedByError as E; + + match *self { + E::Blocks(ref e) => Some(e), + E::Time(ref e) => Some(e), + } + } +} + +/// Error returned when `is_satisfied_by_height` fails. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum IsSatisfiedByHeightError { + /// Satisfaction of the lock height value failed. + Satisfaction(InvalidHeightError), + /// Tried to satisfy a lock-by-height locktime using seconds. + // TODO: Hide inner value in a new struct error type. + Incompatible(NumberOf512Seconds), +} + +impl fmt::Display for IsSatisfiedByHeightError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use IsSatisfiedByHeightError as E; + + match *self { + E::Satisfaction(ref e) => write_err!(f, "satisfaction"; e), + E::Incompatible(time) => + write!(f, "tried to satisfy a lock-by-height locktime using seconds {}", time), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IsSatisfiedByHeightError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use IsSatisfiedByHeightError as E; + + match *self { + E::Satisfaction(ref e) => Some(e), + E::Incompatible(_) => None, + } + } +} + +/// Error returned when `is_satisfied_by_time` fails. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum IsSatisfiedByTimeError { + /// Satisfaction of the lock time value failed. + Satisfaction(InvalidTimeError), + /// Tried to satisfy a lock-by-time locktime using number of blocks. + // TODO: Hide inner value in a new struct error type. + Incompatible(NumberOfBlocks), +} + +impl fmt::Display for IsSatisfiedByTimeError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use IsSatisfiedByTimeError as E; + + match *self { + E::Satisfaction(ref e) => write_err!(f, "satisfaction"; e), + E::Incompatible(blocks) => + write!(f, "tried to satisfy a lock-by-height locktime using blocks {}", blocks), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for IsSatisfiedByTimeError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use IsSatisfiedByTimeError as E; + + match *self { + E::Satisfaction(ref e) => Some(e), + E::Incompatible(_) => None, + } + } +} + /// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval. #[derive(Debug, Clone, PartialEq, Eq)] pub struct TimeOverflowError { diff --git a/units/src/locktime/relative/mod.rs b/units/src/locktime/relative/mod.rs index 2d3ae4bf9f..ab60084388 100644 --- a/units/src/locktime/relative/mod.rs +++ b/units/src/locktime/relative/mod.rs @@ -1,18 +1,394 @@ // SPDX-License-Identifier: CC0-1.0 -//! Provides [`NumberOfBlocks`] and [`NumberOf512Seconds`] types used by the -//! `rust-bitcoin` `relative::LockTime` type. +//! Provides type [`LockTime`] that implements the logic around `nSequence`/`OP_CHECKSEQUENCEVERIFY`. +//! +//! There are two types of lock time: lock-by-height and lock-by-time, distinguished by whether bit +//! 22 of the `u32` consensus value is set. To support these we provide the [`NumberOfBlocks`] and +//! [`NumberOf512Seconds`] types. pub mod error; -use core::fmt; +use core::{convert, fmt}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; +#[cfg(doc)] +use crate::relative; +use crate::{BlockHeight, BlockMtp, Sequence}; + #[rustfmt::skip] // Keep public re-exports separate. #[doc(no_inline)] -pub use self::error::{InvalidHeightError, InvalidTimeError, TimeOverflowError}; +pub use self::error::{ + DisabledLockTimeError, InvalidHeightError, InvalidTimeError, IsSatisfiedByError, + IsSatisfiedByHeightError, IsSatisfiedByTimeError, TimeOverflowError, +}; + +/// A relative lock time value, representing either a block height or time (512 second intervals). +/// +/// Used for sequence numbers (`nSequence` in Bitcoin Core and `TxIn::sequence` +/// in `rust-bitcoin`) and also for the argument to opcode `OP_CHECKSEQUENCEVERIFY`. +/// +/// # Note on ordering +/// +/// Locktimes may be height- or time-based, and these metrics are incommensurate; there is no total +/// ordering on locktimes. In order to compare locktimes, instead of using `<` or `>` we provide the +/// [`LockTime::is_satisfied_by`] API. +/// +/// # Relevant BIPs +/// +/// * [BIP 68 Relative lock-time using consensus-enforced sequence numbers](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) +/// * [BIP 112 CHECKSEQUENCEVERIFY](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum LockTime { + /// A block height lock time value. + Blocks(NumberOfBlocks), + /// A 512 second time interval value. + Time(NumberOf512Seconds), +} + +impl LockTime { + /// A relative locktime of 0 is always valid, and is assumed valid for inputs that + /// are not yet confirmed. + pub const ZERO: LockTime = LockTime::Blocks(NumberOfBlocks::ZERO); + + /// The number of bytes that the locktime contributes to the size of a transaction. + pub const SIZE: usize = 4; // Serialized length of a u32. + + /// Constructs a new `LockTime` from an `nSequence` value or the argument to `OP_CHECKSEQUENCEVERIFY`. + /// + /// This method will **not** round-trip with [`Self::to_consensus_u32`], because relative + /// locktimes only use some bits of the underlying `u32` value and discard the rest. If + /// you want to preserve the full value, you should use the [`Sequence`] type instead. + /// + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::relative; + /// + /// // Values with bit 22 set to 0 will be interpreted as height-based lock times. + /// let height: u32 = 144; // 144 blocks, approx 24h. + /// let lock_time = relative::LockTime::from_consensus(height)?; + /// assert!(lock_time.is_block_height()); + /// assert_eq!(lock_time.to_consensus_u32(), height); + /// + /// // Values with bit 22 set to 1 will be interpreted as time-based lock times. + /// let time: u32 = 168 | (1 << 22) ; // Bit 22 is 1 with time approx 24h. + /// let lock_time = relative::LockTime::from_consensus(time)?; + /// assert!(lock_time.is_block_time()); + /// assert_eq!(lock_time.to_consensus_u32(), time); + /// + /// # Ok::<_, relative::error::DisabledLockTimeError>(()) + /// ``` + #[inline] + pub fn from_consensus(n: u32) -> Result { + let sequence = crate::Sequence::from_consensus(n); + sequence.to_relative_lock_time().ok_or(DisabledLockTimeError(n)) + } + + /// Returns the `u32` value used to encode this locktime in an `nSequence` field or + /// argument to `OP_CHECKSEQUENCEVERIFY`. + /// + /// # Warning + /// + /// Locktimes are not ordered by the natural ordering on `u32`. If you want to + /// compare locktimes, use [`Self::is_implied_by`] or similar methods. + #[inline] + pub fn to_consensus_u32(self) -> u32 { + match self { + LockTime::Blocks(ref h) => u32::from(h.to_height()), + LockTime::Time(ref t) => + Sequence::LOCK_TYPE_MASK | u32::from(t.to_512_second_intervals()), + } + } + + /// Constructs a new `LockTime` from the sequence number of a Bitcoin input. + /// + /// This method will **not** round-trip with [`Self::to_sequence`]. See the + /// docs for [`Self::from_consensus`] for more information. + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::{Sequence, relative}; + /// + /// // Interpret a sequence number from a Bitcoin transaction input as a relative lock time + /// let sequence_number = Sequence::from_consensus(144); // 144 blocks, approx 24h. + /// let lock_time = relative::LockTime::from_sequence(sequence_number)?; + /// assert!(lock_time.is_block_height()); + /// + /// # Ok::<_, relative::error::DisabledLockTimeError>(()) + /// ``` + #[inline] + pub fn from_sequence(n: Sequence) -> Result { + Self::from_consensus(n.to_consensus_u32()) + } + + /// Encodes the locktime as a sequence number. + #[inline] + pub fn to_sequence(self) -> Sequence { Sequence::from_consensus(self.to_consensus_u32()) } + + /// Constructs a new `LockTime` from `n`, expecting `n` to be a 16-bit count of blocks. + #[inline] + pub const fn from_height(n: u16) -> Self { LockTime::Blocks(NumberOfBlocks::from_height(n)) } + + /// Constructs a new `LockTime` from `n`, expecting `n` to be a count of 512-second intervals. + /// + /// This function is a little awkward to use, and users may wish to instead use + /// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`]. + #[inline] + pub const fn from_512_second_intervals(intervals: u16) -> Self { + LockTime::Time(NumberOf512Seconds::from_512_second_intervals(intervals)) + } + + /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval + /// with truncating division. + /// + /// # Errors + /// + /// Will return an error if the input cannot be encoded in 16 bits. + #[inline] + pub const fn from_seconds_floor(seconds: u32) -> Result { + match NumberOf512Seconds::from_seconds_floor(seconds) { + Ok(time) => Ok(LockTime::Time(time)), + Err(e) => Err(e), + } + } + + /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval + /// with ceiling division. + /// + /// # Errors + /// + /// Will return an error if the input cannot be encoded in 16 bits. + #[inline] + pub const fn from_seconds_ceil(seconds: u32) -> Result { + match NumberOf512Seconds::from_seconds_ceil(seconds) { + Ok(time) => Ok(LockTime::Time(time)), + Err(e) => Err(e), + } + } + + /// Returns true if both lock times use the same unit i.e., both height based or both time based. + #[inline] + pub const fn is_same_unit(self, other: LockTime) -> bool { + matches!( + (self, other), + (LockTime::Blocks(_), LockTime::Blocks(_)) | (LockTime::Time(_), LockTime::Time(_)) + ) + } + + /// Returns true if this lock time value is in units of block height. + #[inline] + pub const fn is_block_height(self) -> bool { matches!(self, LockTime::Blocks(_)) } + + /// Returns true if this lock time value is in units of time. + #[inline] + pub const fn is_block_time(self) -> bool { !self.is_block_height() } + + /// Returns true if this [`relative::LockTime`] is satisfied by the given chain state. + /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// + /// # Errors + /// + /// If `chain_tip` as not _after_ `utxo_mined_at` i.e., if you get the args mixed up. + pub fn is_satisfied_by( + self, + chain_tip_height: BlockHeight, + chain_tip_mtp: BlockMtp, + utxo_mined_at_height: BlockHeight, + utxo_mined_at_mtp: BlockMtp, + ) -> Result { + match self { + LockTime::Blocks(blocks) => blocks + .is_satisfied_by(chain_tip_height, utxo_mined_at_height) + .map_err(IsSatisfiedByError::Blocks), + LockTime::Time(time) => time + .is_satisfied_by(chain_tip_mtp, utxo_mined_at_mtp) + .map_err(IsSatisfiedByError::Time), + } + } + + /// Returns true if an output with this locktime can be spent in the next block. + /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-height. + #[inline] + pub fn is_satisfied_by_height( + self, + chain_tip: BlockHeight, + utxo_mined_at: BlockHeight, + ) -> Result { + use LockTime as L; + + match self { + L::Blocks(blocks) => blocks + .is_satisfied_by(chain_tip, utxo_mined_at) + .map_err(IsSatisfiedByHeightError::Satisfaction), + L::Time(time) => Err(IsSatisfiedByHeightError::Incompatible(time)), + } + } + + /// Returns true if an output with this locktime can be spent in the next block. + /// + /// If this function returns true then an output with this locktime can be spent in the next + /// block. + /// + /// # Errors + /// + /// Returns an error if this lock is not lock-by-time. + #[inline] + pub fn is_satisfied_by_time( + self, + chain_tip: BlockMtp, + utxo_mined_at: BlockMtp, + ) -> Result { + use LockTime as L; + + match self { + L::Time(time) => time + .is_satisfied_by(chain_tip, utxo_mined_at) + .map_err(IsSatisfiedByTimeError::Satisfaction), + L::Blocks(blocks) => Err(IsSatisfiedByTimeError::Incompatible(blocks)), + } + } + + /// Returns true if satisfaction of `other` lock time implies satisfaction of this + /// [`relative::LockTime`]. + /// + /// A lock time can only be satisfied by n blocks being mined or n seconds passing. If you have + /// two lock times (same unit) then the larger lock time being satisfied implies (in a + /// mathematical sense) the smaller one being satisfied. + /// + /// This function is useful when checking sequence values against a lock, first one checks the + /// sequence represents a relative lock time by converting to `LockTime` then use this function + /// to see if satisfaction of the newly created lock time would imply satisfaction of `self`. + /// + /// Can also be used to remove the smaller value of two `OP_CHECKSEQUENCEVERIFY` operations + /// within one branch of the script. + /// + /// # Examples + /// + /// ```rust + /// # use bitcoin_units::Sequence; + /// + /// # let required_height = 100; // 100 blocks. + /// # let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height"); + /// # let test_sequence = Sequence::from_height(required_height + 10); + /// + /// let satisfied = match test_sequence.to_relative_lock_time() { + /// None => false, // Handle non-lock-time case. + /// Some(test_lock) => lock.is_implied_by(test_lock), + /// }; + /// assert!(satisfied); + /// ``` + #[inline] + pub fn is_implied_by(self, other: LockTime) -> bool { + use LockTime as L; + + match (self, other) { + (L::Blocks(this), L::Blocks(other)) => this <= other, + (L::Time(this), L::Time(other)) => this <= other, + _ => false, // Not the same units. + } + } + + /// Returns true if satisfaction of the sequence number implies satisfaction of this lock time. + /// + /// When deciding whether an instance of ` CHECKSEQUENCEVERIFY` will pass, this + /// method can be used by parsing `n` as a [`LockTime`] and calling this method + /// with the sequence number of the input which spends the script. + /// + /// # Examples + /// + /// ``` + /// # use bitcoin_units::{Sequence, relative}; + /// + /// let sequence = Sequence::from_consensus(1 << 22 | 168); // Bit 22 is 1 with time approx 24h. + /// let lock_time = relative::LockTime::from_sequence(sequence)?; + /// let input_sequence = Sequence::from_consensus(1 << 22 | 336); // Approx 48h. + /// assert!(lock_time.is_block_time()); + /// + /// assert!(lock_time.is_implied_by_sequence(input_sequence)); + /// + /// # Ok::<_, relative::error::DisabledLockTimeError>(()) + /// ``` + #[inline] + pub fn is_implied_by_sequence(self, other: Sequence) -> bool { + if let Ok(other) = LockTime::from_sequence(other) { + self.is_implied_by(other) + } else { + false + } + } +} + +impl From for LockTime { + #[inline] + fn from(h: NumberOfBlocks) -> Self { LockTime::Blocks(h) } +} + +impl From for LockTime { + #[inline] + fn from(t: NumberOf512Seconds) -> Self { LockTime::Time(t) } +} + +impl fmt::Display for LockTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use LockTime as L; + + if f.alternate() { + match *self { + L::Blocks(ref h) => write!(f, "block-height {}", h), + L::Time(ref t) => write!(f, "block-time {} (512 second intervals)", t), + } + } else { + match *self { + L::Blocks(ref h) => fmt::Display::fmt(h, f), + L::Time(ref t) => fmt::Display::fmt(t, f), + } + } + } +} + +impl convert::TryFrom for LockTime { + type Error = DisabledLockTimeError; + #[inline] + fn try_from(seq: Sequence) -> Result { + LockTime::from_sequence(seq) + } +} + +impl From for Sequence { + #[inline] + fn from(lt: LockTime) -> Sequence { lt.to_sequence() } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for LockTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_consensus_u32().serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for LockTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + u32::deserialize(deserializer) + .and_then(|n| Self::from_consensus(n).map_err(serde::de::Error::custom)) + } +} #[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")] #[doc(hidden)] @@ -237,11 +613,248 @@ impl<'a> Arbitrary<'a> for NumberOf512Seconds { #[cfg(test)] mod tests { + #[cfg(feature = "alloc")] + use alloc::format; + use super::*; - use crate::BlockTime; + use crate::{BlockHeight, BlockTime}; const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512; + #[test] + #[cfg(feature = "alloc")] + fn display_and_alternate() { + let lock_by_height = LockTime::from_height(10); + let lock_by_time = LockTime::from_512_second_intervals(70); + + assert_eq!(format!("{}", lock_by_height), "10"); + assert_eq!(format!("{:#}", lock_by_height), "block-height 10"); + assert!(!format!("{:?}", lock_by_height).is_empty()); + + assert_eq!(format!("{}", lock_by_time), "70"); + assert_eq!(format!("{:#}", lock_by_time), "block-time 70 (512 second intervals)"); + assert!(!format!("{:?}", lock_by_time).is_empty()); + } + + #[test] + fn from_seconds_ceil_and_floor() { + let time = 70 * 512 + 1; + let lock_by_time = LockTime::from_seconds_ceil(time).unwrap(); + assert_eq!(lock_by_time, LockTime::from_512_second_intervals(71)); + + let lock_by_time = LockTime::from_seconds_floor(time).unwrap(); + assert_eq!(lock_by_time, LockTime::from_512_second_intervals(70)); + + let mut max_time = 0xffff * 512; + assert_eq!(LockTime::from_seconds_ceil(max_time), LockTime::from_seconds_floor(max_time)); + max_time += 512; + assert!(LockTime::from_seconds_ceil(max_time).is_err()); + assert!(LockTime::from_seconds_floor(max_time).is_err()); + } + + #[test] + fn parses_correctly_to_height_or_time() { + let height1 = NumberOfBlocks::from(10); + let height2 = NumberOfBlocks::from(11); + let time1 = NumberOf512Seconds::from_512_second_intervals(70); + let time2 = NumberOf512Seconds::from_512_second_intervals(71); + + let lock_by_height1 = LockTime::from(height1); + let lock_by_height2 = LockTime::from(height2); + let lock_by_time1 = LockTime::from(time1); + let lock_by_time2 = LockTime::from(time2); + + assert!(lock_by_height1.is_block_height()); + assert!(!lock_by_height1.is_block_time()); + + assert!(!lock_by_time1.is_block_height()); + assert!(lock_by_time1.is_block_time()); + + // Test is_same_unit() logic + assert!(lock_by_height1.is_same_unit(lock_by_height2)); + assert!(!lock_by_height1.is_same_unit(lock_by_time1)); + assert!(lock_by_time1.is_same_unit(lock_by_time2)); + assert!(!lock_by_time1.is_same_unit(lock_by_height1)); + } + + #[test] + fn height_correctly_implies() { + let height = NumberOfBlocks::from(10); + let lock_by_height = LockTime::from(height); + + assert!(!lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(9)))); + assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(10)))); + assert!(lock_by_height.is_implied_by(LockTime::from(NumberOfBlocks::from(11)))); + } + + #[test] + fn time_correctly_implies() { + let time = NumberOf512Seconds::from_512_second_intervals(70); + let lock_by_time = LockTime::from(time); + + assert!(!lock_by_time + .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(69)))); + assert!(lock_by_time + .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(70)))); + assert!(lock_by_time + .is_implied_by(LockTime::from(NumberOf512Seconds::from_512_second_intervals(71)))); + } + + #[test] + fn sequence_correctly_implies() { + let height = NumberOfBlocks::from(10); + let time = NumberOf512Seconds::from_512_second_intervals(70); + + let lock_by_height = LockTime::from(height); + let lock_by_time = LockTime::from(time); + + let seq_height = Sequence::from(lock_by_height); + let seq_time = Sequence::from(lock_by_time); + + assert!(lock_by_height.is_implied_by_sequence(seq_height)); + assert!(!lock_by_height.is_implied_by_sequence(seq_time)); + + assert!(lock_by_time.is_implied_by_sequence(seq_time)); + assert!(!lock_by_time.is_implied_by_sequence(seq_height)); + + let disabled_sequence = Sequence::from_consensus(1 << 31); + assert!(!lock_by_height.is_implied_by_sequence(disabled_sequence)); + assert!(!lock_by_time.is_implied_by_sequence(disabled_sequence)); + } + + #[test] + fn incorrect_units_do_not_imply() { + let time = NumberOf512Seconds::from_512_second_intervals(70); + let height = NumberOfBlocks::from(10); + + let lock_by_time = LockTime::from(time); + assert!(!lock_by_time.is_implied_by(LockTime::from(height))); + } + + #[test] + fn consensus_round_trip() { + assert!(LockTime::from_consensus(1 << 31).is_err()); + assert!(LockTime::from_consensus(1 << 30).is_ok()); + // Relative locktimes do not care about bits 17 through 21. + assert_eq!(LockTime::from_consensus(65536), LockTime::from_consensus(0)); + + for val in [0u32, 1, 1000, 65535] { + let seq = Sequence::from_consensus(val); + let lt = LockTime::from_consensus(val).unwrap(); + assert_eq!(lt.to_consensus_u32(), val); + assert_eq!(lt.to_sequence(), seq); + assert_eq!(LockTime::from_sequence(seq).unwrap().to_sequence(), seq); + + let seq = Sequence::from_consensus(val + (1 << 22)); + let lt = LockTime::from_consensus(val + (1 << 22)).unwrap(); + assert_eq!(lt.to_consensus_u32(), val + (1 << 22)); + assert_eq!(lt.to_sequence(), seq); + assert_eq!(LockTime::from_sequence(seq).unwrap().to_sequence(), seq); + } + } + + #[test] + #[cfg(feature = "alloc")] + fn disabled_locktime_error() { + let disabled_sequence = Sequence::from_consensus(1 << 31); + let err = LockTime::try_from(disabled_sequence).unwrap_err(); + + assert_eq!(err.disabled_locktime_value(), 1 << 31); + assert!(!format!("{}", err).is_empty()); + } + + #[test] + #[cfg(feature = "alloc")] + fn incompatible_height_error() { + // This is an error test these values are not used in the error path. + let mined_at = BlockHeight::from_u32(700_000); + let chain_tip = BlockHeight::from_u32(800_000); + + let lock_by_time = LockTime::from_512_second_intervals(70); // Arbitrary value. + let err = lock_by_time.is_satisfied_by_height(chain_tip, mined_at).unwrap_err(); + + let expected_time = NumberOf512Seconds::from_512_second_intervals(70); + assert_eq!(err, IsSatisfiedByHeightError::Incompatible(expected_time)); + assert!(!format!("{}", err).is_empty()); + } + + #[test] + #[cfg(feature = "alloc")] + fn incompatible_time_error() { + // This is an error test these values are not used in the error path. + let mined_at = BlockMtp::from_u32(1_234_567_890); + let chain_tip = BlockMtp::from_u32(1_600_000_000); + + let lock_by_height = LockTime::from_height(10); // Arbitrary value. + let err = lock_by_height.is_satisfied_by_time(chain_tip, mined_at).unwrap_err(); + + let expected_height = NumberOfBlocks::from(10); + assert_eq!(err, IsSatisfiedByTimeError::Incompatible(expected_height)); + assert!(!format!("{}", err).is_empty()); + } + + #[test] + fn test_locktime_chain_state() { + fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] { + let mut timestamps = [BlockTime::from_u32(0); 11]; + for (i, ts) in timestamps.iter_mut().enumerate() { + *ts = BlockTime::from_u32(start.saturating_sub((step * i as u16).into())); + } + timestamps + } + + let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200); + let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200); + + let chain_height = BlockHeight::from_u32(100); + let chain_mtp = BlockMtp::new(timestamps); + let utxo_height = BlockHeight::from_u32(80); + let utxo_mtp = BlockMtp::new(utxo_timestamps); + + let lock1 = LockTime::Blocks(NumberOfBlocks::from(10)); + assert!(lock1.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); + + let lock2 = LockTime::Blocks(NumberOfBlocks::from(21)); + assert!(lock2.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); + + let lock3 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(10)); + assert!(lock3.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); + + let lock4 = LockTime::Time(NumberOf512Seconds::from_512_second_intervals(20000)); + assert!(!lock4.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); + + assert!(LockTime::ZERO + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); + assert!(LockTime::from_512_second_intervals(0) + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); + + let lock6 = LockTime::from_seconds_floor(5000).unwrap(); + assert!(lock6.is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp).unwrap()); + + let max_height_lock = LockTime::Blocks(NumberOfBlocks::MAX); + assert!(!max_height_lock + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); + + let max_time_lock = LockTime::Time(NumberOf512Seconds::MAX); + assert!(!max_time_lock + .is_satisfied_by(chain_height, chain_mtp, utxo_height, utxo_mtp) + .unwrap()); + + let max_chain_height = BlockHeight::from_u32(u32::MAX); + let max_chain_mtp = BlockMtp::new(generate_timestamps(u32::MAX, 100)); + let max_utxo_height = BlockHeight::MAX; + let max_utxo_mtp = max_chain_mtp; + assert!(!max_height_lock + .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp) + .unwrap()); + assert!(!max_time_lock + .is_satisfied_by(max_chain_height, max_chain_mtp, max_utxo_height, max_utxo_mtp) + .unwrap()); + } + #[test] #[allow(deprecated_in_future)] fn sanity_check() { @@ -357,8 +970,6 @@ mod tests { #[test] fn test_height_chain_state() { - use crate::BlockHeight; - let height_lock = NumberOfBlocks(10); // Test case 1: Satisfaction (current_height >= utxo_height + required) diff --git a/primitives/src/sequence.rs b/units/src/sequence.rs similarity index 97% rename from primitives/src/sequence.rs rename to units/src/sequence.rs index c7179d4939..87eb866949 100644 --- a/primitives/src/sequence.rs +++ b/units/src/sequence.rs @@ -20,10 +20,10 @@ use core::fmt; use arbitrary::{Arbitrary, Unstructured}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use units::locktime::relative::{NumberOf512Seconds, TimeOverflowError}; -use units::parse::{self, PrefixedHexError, UnprefixedHexError}; -use crate::locktime::relative; +use crate::locktime::relative::error::TimeOverflowError; +use crate::locktime::relative::{self, NumberOf512Seconds}; +use crate::parse::{self, PrefixedHexError, UnprefixedHexError}; /// Bitcoin transaction input sequence number. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -242,7 +242,7 @@ impl fmt::Debug for Sequence { } #[cfg(feature = "alloc")] -units::impl_parse_str_from_int_infallible!(Sequence, u32, from_consensus); +crate::impl_parse_str_from_int_infallible!(Sequence, u32, from_consensus); #[cfg(feature = "arbitrary")] #[cfg(feature = "alloc")] @@ -289,6 +289,8 @@ impl<'a> Arbitrary<'a> for Sequence { #[cfg(test)] #[cfg(feature = "alloc")] mod tests { + use alloc::format; + use super::*; const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512; @@ -345,6 +347,7 @@ mod tests { } #[test] + #[cfg(feature = "alloc")] fn sequence_formatting() { let sequence = Sequence(0x7FFF_FFFF); assert_eq!(format!("{:x}", sequence), "7fffffff"); @@ -356,7 +359,10 @@ mod tests { } #[test] + #[cfg(feature = "alloc")] fn sequence_display() { + use alloc::string::ToString; + let sequence = Sequence(0x7FFF_FFFF); let want: u32 = 0x7FFF_FFFF; assert_eq!(format!("{}", sequence), want.to_string()); From 029d5c6492e2c7f0080c86c0c0e4c7957c6f07aa Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 7 Jul 2025 14:00:31 +1000 Subject: [PATCH 193/857] units: Add Errors section to rustdocs In `units` we lint for the `# Errors` section but in `primitives` we don't so during recent code move from `primitives` to `units` we introduced a bunch of lint warnings. Add docs and clear all lint warnings. --- units/src/locktime/absolute/mod.rs | 19 +++++++++++++++++++ units/src/locktime/relative/mod.rs | 9 +++++++++ units/src/sequence.rs | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/units/src/locktime/absolute/mod.rs b/units/src/locktime/absolute/mod.rs index f4bc0239a5..ed0a3a282f 100644 --- a/units/src/locktime/absolute/mod.rs +++ b/units/src/locktime/absolute/mod.rs @@ -112,6 +112,11 @@ impl LockTime { /// Constructs a new `LockTime` from a prefixed hex string. /// + /// # Errors + /// + /// If the input string is not a valid hex representation of a locktime or it does not include + /// the `0x` prefix. + /// /// # Examples /// /// ``` @@ -130,6 +135,11 @@ impl LockTime { /// Constructs a new `LockTime` from an unprefixed hex string. /// + /// # Errors + /// + /// If the input string is not a valid hex representation of a locktime or if it includes the + /// `0x` prefix. + /// /// # Examples /// /// ``` @@ -177,6 +187,11 @@ impl LockTime { /// /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid height value. /// + /// # Errors + /// + /// If `n` does not represent a block height within the valid range for a locktime: + /// `[0, 499_999_999]`. + /// /// # Examples /// /// ```rust @@ -209,6 +224,10 @@ impl LockTime { /// /// See [`LOCK_TIME_THRESHOLD`] for definition of a valid time value. /// + /// # Errors + /// + /// If `n` is not in the allowable range of MTPs in a locktime: `[500_000_000, 2^32 - 1]`. + /// /// # Examples /// /// ```rust diff --git a/units/src/locktime/relative/mod.rs b/units/src/locktime/relative/mod.rs index ab60084388..81395783b2 100644 --- a/units/src/locktime/relative/mod.rs +++ b/units/src/locktime/relative/mod.rs @@ -61,6 +61,10 @@ impl LockTime { /// locktimes only use some bits of the underlying `u32` value and discard the rest. If /// you want to preserve the full value, you should use the [`Sequence`] type instead. /// + /// # Errors + /// + /// If `n`, interpreted as a [`Sequence`] number does not encode a relative lock time. + /// /// # Examples /// /// ```rust @@ -106,6 +110,11 @@ impl LockTime { /// /// This method will **not** round-trip with [`Self::to_sequence`]. See the /// docs for [`Self::from_consensus`] for more information. + /// + /// # Errors + /// + /// If `n` does not encode a relative lock time. + /// /// # Examples /// /// ```rust diff --git a/units/src/sequence.rs b/units/src/sequence.rs index 87eb866949..ef95f67ee1 100644 --- a/units/src/sequence.rs +++ b/units/src/sequence.rs @@ -122,6 +122,11 @@ impl Sequence { } /// Constructs a new `Sequence` from a prefixed hex string. + /// + /// # Errors + /// + /// If the input string is not a valid hex representation of a locktime or it does not include + /// the `0x` prefix. #[inline] pub fn from_hex(s: &str) -> Result { let lock_time = parse::hex_u32_prefixed(s)?; @@ -129,6 +134,11 @@ impl Sequence { } /// Constructs a new `Sequence` from an unprefixed hex string. + /// + /// # Errors + /// + /// If the input string is not a valid hex representation of a locktime or if it includes the + /// `0x` prefix. #[inline] pub fn from_unprefixed_hex(s: &str) -> Result { let lock_time = parse::hex_u32_unprefixed(s)?; @@ -152,6 +162,11 @@ impl Sequence { /// interval with floor division. /// /// Will return an error if the input cannot be encoded in 16 bits. + /// + /// # Errors + /// + /// Will return an error if `seconds` cannot be encoded in 16 bits. See + /// [`NumberOf512Seconds::from_seconds_floor`]. #[inline] pub fn from_seconds_floor(seconds: u32) -> Result { let intervals = NumberOf512Seconds::from_seconds_floor(seconds)?; @@ -162,6 +177,11 @@ impl Sequence { /// interval with ceiling division. /// /// Will return an error if the input cannot be encoded in 16 bits. + /// + /// # Errors + /// + /// Will return an error if `seconds` cannot be encoded in 16 bits. See + /// [`NumberOf512Seconds::from_seconds_ceil`]. #[inline] pub fn from_seconds_ceil(seconds: u32) -> Result { let intervals = NumberOf512Seconds::from_seconds_ceil(seconds)?; From 8cde2cae87bbcf96a21077a4995ed9eafd4bb2a1 Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Tue, 22 Jul 2025 21:47:19 -0500 Subject: [PATCH 194/857] Add Arbitrary impl for BlockHash, TxMerkleNode, and Wtxid --- primitives/src/block.rs | 7 +++++++ primitives/src/merkle_tree.rs | 9 +++++++++ primitives/src/transaction.rs | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/primitives/src/block.rs b/primitives/src/block.rs index 42e6ca10ec..17c79af5ab 100644 --- a/primitives/src/block.rs +++ b/primitives/src/block.rs @@ -354,6 +354,13 @@ impl<'a> Arbitrary<'a> for Block { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for BlockHash { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(BlockHash::from_byte_array(u.arbitrary()?)) + } +} + #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Header { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { diff --git a/primitives/src/merkle_tree.rs b/primitives/src/merkle_tree.rs index e5cc601017..48c6972a6e 100644 --- a/primitives/src/merkle_tree.rs +++ b/primitives/src/merkle_tree.rs @@ -2,6 +2,8 @@ //! Bitcoin Merkle tree functions. +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use hashes::sha256d; hashes::hash_newtype! { @@ -17,3 +19,10 @@ hashes::impl_hex_for_newtype!(TxMerkleNode, WitnessMerkleNode); hashes::impl_debug_only_for_newtype!(TxMerkleNode, WitnessMerkleNode); #[cfg(feature = "serde")] hashes::impl_serde_for_newtype!(TxMerkleNode, WitnessMerkleNode); + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for TxMerkleNode { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(TxMerkleNode::from_byte_array(u.arbitrary()?)) + } +} diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 6dec85fa60..57c267a4a3 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -652,6 +652,13 @@ impl<'a> Arbitrary<'a> for Txid { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for Wtxid { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(Wtxid::from_byte_array(u.arbitrary()?)) + } +} + #[cfg(feature = "alloc")] #[cfg(test)] mod tests { From 89e309cc8aa6f655d6cb0d342b413e6c09ae146b Mon Sep 17 00:00:00 2001 From: Bugarim Date: Thu, 24 Jul 2025 13:07:16 +0200 Subject: [PATCH 195/857] Update borrowed.rs --- primitives/src/script/borrowed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/script/borrowed.rs b/primitives/src/script/borrowed.rs index 051bb76419..47065e0686 100644 --- a/primitives/src/script/borrowed.rs +++ b/primitives/src/script/borrowed.rs @@ -52,7 +52,7 @@ internals::transparent_newtype! { /// # Hexadecimal strings /// /// Scripts are consensus encoded with a length prefix and as a result of this in some places in - /// the eccosystem one will encounter hex strings that include the prefix while in other places + /// the ecosystem one will encounter hex strings that include the prefix while in other places /// the prefix is excluded. To support parsing and formatting scripts as hex we provide a bunch /// of different APIs and trait implementations. Please see [`examples/script.rs`] for a /// thorough example of all the APIs. From 6d1f37f253d3a9c59a5335af84f9d11cc7226afc Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Thu, 24 Jul 2025 09:01:40 -0500 Subject: [PATCH 196/857] Add arbitrary impl for `ProprietaryKey` and `Key` --- bitcoin/src/psbt/raw.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bitcoin/src/psbt/raw.rs b/bitcoin/src/psbt/raw.rs index 205d076b57..c17766e603 100644 --- a/bitcoin/src/psbt/raw.rs +++ b/bitcoin/src/psbt/raw.rs @@ -6,6 +6,8 @@ //! . use core::fmt; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use internals::ToU64 as _; use io::{BufRead, Write}; @@ -188,3 +190,21 @@ where Ok(deserialize(&key.key_data)?) } } + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for ProprietaryKey { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(ProprietaryKey { + prefix: Vec::::arbitrary(u)?, + subtype: u64::arbitrary(u)?, + key: Vec::::arbitrary(u)? + }) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for Key { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(Key { type_value: u.arbitrary()?, key_data: Vec::::arbitrary(u)? }) + } +} From ff48db2faf86db306fc0434a0fa791ba31ed7378 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 24 Jul 2025 19:02:41 +0300 Subject: [PATCH 197/857] fix: typo in panic message in amount module tests The panic message in the amount module tests contained a typo: "failed to crate amount from" was corrected to "failed to create amount from". --- units/src/amount/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 110977d166..6644ddb477 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -70,7 +70,7 @@ fn from_str_zero() { for v in &["0", "000"] { let s = format!("{} {}", v, denom); match s.parse::() { - Err(e) => panic!("failed to crate amount from {}: {:?}", s, e), + Err(e) => panic!("failed to create amount from {}: {:?}", s, e), Ok(amount) => assert_eq!(amount, Amount::ZERO), } } From 5a128ba4e2cc9f7971edecfe611ea3d3c7d9a24b Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Fri, 25 Jul 2025 14:21:46 +0100 Subject: [PATCH 198/857] p2p: Add formal `Alert` type There is a well-known final alert message that is sent for potentially vulerable peers, but otherwise the alert system is deprecated. The only use for this message is to send the final alert, or to decide if a peer has sent a strange or unexpected alert. --- p2p/src/message.rs | 6 +++--- p2p/src/message_network.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/p2p/src/message.rs b/p2p/src/message.rs index 942e258285..0f62e57050 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -246,7 +246,7 @@ pub enum NetworkMessage { /// BIP152 blocktxn BlockTxn(message_compact_blocks::BlockTxn), /// `alert` - Alert(Vec), + Alert(message_network::Alert), /// `reject` Reject(message_network::Reject), /// `feefilter` @@ -732,7 +732,7 @@ mod test { use crate::message_filter::{ CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters, }; - use crate::message_network::{Reject, RejectReason, VersionMessage}; + use crate::message_network::{Alert, Reject, RejectReason, VersionMessage}; use crate::ServiceFlags; fn hash(array: [u8; 32]) -> sha256d::Hash { sha256d::Hash::from_byte_array(array) } @@ -835,7 +835,7 @@ mod test { FilterHeader::from_byte_array(hash([99u8; 32]).to_byte_array()), ], }), - NetworkMessage::Alert(vec![45, 66, 3, 2, 6, 8, 9, 12, 3, 130]), + NetworkMessage::Alert(Alert::final_alert()), NetworkMessage::Reject(Reject { message: "Test reject".into(), ccode: RejectReason::Duplicate, diff --git a/p2p/src/message_network.rs b/p2p/src/message_network.rs index f43ed5705c..16dcc3bf3d 100644 --- a/p2p/src/message_network.rs +++ b/p2p/src/message_network.rs @@ -6,12 +6,12 @@ //! capabilities. use std::borrow::Cow; -use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt}; +use bitcoin::consensus::{encode, Decodable, Encodable, ReadExt, WriteExt}; use hashes::sha256d; use io::{BufRead, Write}; use crate::address::Address; -use crate::consensus::impl_consensus_encoding; +use crate::consensus::{impl_consensus_encoding, impl_vec_wrapper}; use crate::ServiceFlags; // Some simple messages @@ -145,6 +145,29 @@ pub struct Reject { impl_consensus_encoding!(Reject, message, ccode, reason, hash); +/// A deprecated message type that was used to notify users of system changes. Due to a number of +/// vulerabilities, alerts are no longer used. A final alert was sent as of Bitcoin Core 0.14.0, +/// and is sent to any node that is advertising a potentially vulerable protocol version. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Alert(Vec); + +impl Alert { + const FINAL_ALERT: [u8; 96] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0]; + + /// Build the final alert to send to a potentially vulerable peer. + pub fn final_alert() -> Self { + Self(Self::FINAL_ALERT.into()) + } + + /// The final alert advertised by Bitcoin Core. This alert is sent if the advertised protocol + /// version is vulerable to the alert-system vulerablities. + pub fn is_final_alert(&self) -> bool { + self.0.eq(&Self::FINAL_ALERT) + } +} + +impl_vec_wrapper!(Alert, Vec); + #[cfg(test)] mod tests { use bitcoin::consensus::encode::{deserialize, serialize}; @@ -208,4 +231,11 @@ mod tests { assert_eq!(serialize(&conflict), reject_tx_conflict); assert_eq!(serialize(&nonfinal), reject_tx_nonfinal); } + + #[test] + fn alert_message_test() { + let alert_hex = hex!("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c207570677261646520726571756972656400"); + let alert: Alert = deserialize(&alert_hex).unwrap(); + assert!(alert.is_final_alert()); + } } From 7afb79807783d1099b112145f021e0b491f1f586 Mon Sep 17 00:00:00 2001 From: Shing Him Ng Date: Tue, 22 Jul 2025 21:50:27 -0500 Subject: [PATCH 199/857] Add Arbitary impls for some bip152, bip158 & merkle block types --- bitcoin/src/bip152.rs | 42 ++++++++++++++++++++++++++++++++ bitcoin/src/bip158.rs | 16 ++++++++++++ bitcoin/src/merkle_tree/block.rs | 20 +++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs index 5aed10c940..d454dfd555 100644 --- a/bitcoin/src/bip152.rs +++ b/bitcoin/src/bip152.rs @@ -9,6 +9,8 @@ use core::{convert, fmt, mem}; #[cfg(feature = "std")] use std::error; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use hashes::{sha256, siphash24}; use internals::array::ArrayExt as _; use internals::ToU64 as _; @@ -404,6 +406,46 @@ impl BlockTransactions { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for ShortId { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(ShortId(u.arbitrary()?)) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for PrefilledTransaction { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(PrefilledTransaction { idx: u.arbitrary()?, tx: u.arbitrary()? }) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for HeaderAndShortIds { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(HeaderAndShortIds { + header: u.arbitrary()?, + nonce: u.arbitrary()?, + short_ids: Vec::::arbitrary(u)?, + prefilled_txs: Vec::::arbitrary(u)?, + }) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for BlockTransactions { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(BlockTransactions { block_hash: u.arbitrary()?, transactions: Vec::::arbitrary(u)? }) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for BlockTransactionsRequest { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(BlockTransactionsRequest { block_hash: u.arbitrary()?, indexes: Vec::::arbitrary(u)? }) + } +} + #[cfg(test)] mod test { use hex::FromHex; diff --git a/bitcoin/src/bip158.rs b/bitcoin/src/bip158.rs index b62617e5c7..8926ba6de7 100644 --- a/bitcoin/src/bip158.rs +++ b/bitcoin/src/bip158.rs @@ -41,6 +41,8 @@ use core::cmp::{self, Ordering}; use core::convert::Infallible; use core::fmt; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use hashes::{sha256d, siphash24, HashEngine as _}; use internals::array::ArrayExt as _; use internals::{write_err, ToU64 as _}; @@ -574,6 +576,20 @@ impl<'a, W: Write> BitStreamWriter<'a, W> { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for FilterHash { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(FilterHash::from_byte_array(u.arbitrary()?)) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for FilterHeader { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(FilterHeader::from_byte_array(u.arbitrary()?)) + } +} + #[cfg(test)] mod test { use std::collections::HashMap; diff --git a/bitcoin/src/merkle_tree/block.rs b/bitcoin/src/merkle_tree/block.rs index fe6589bd36..fe19904d21 100644 --- a/bitcoin/src/merkle_tree/block.rs +++ b/bitcoin/src/merkle_tree/block.rs @@ -12,6 +12,8 @@ use core::convert::Infallible; use core::fmt; +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; use internals::ToU64 as _; use io::{BufRead, Write}; @@ -510,6 +512,24 @@ impl std::error::Error for MerkleBlockError { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for PartialMerkleTree { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(PartialMerkleTree { + num_transactions: u.arbitrary()?, + bits: Vec::::arbitrary(u)?, + hashes: Vec::::arbitrary(u)?, + }) + } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for MerkleBlock { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + Ok(MerkleBlock { header: u.arbitrary()?, txn: u.arbitrary()? }) + } +} + #[cfg(test)] mod tests { use hex::{DisplayHex, FromHex}; From 8294e54b3d72337152247ed72b9dba00b790762d Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sun, 27 Jul 2025 10:39:21 +1000 Subject: [PATCH 200/857] doc: Remove duplicate word Remove typo; duplicate word 'this'. --- bitcoin/src/network/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/network/mod.rs b/bitcoin/src/network/mod.rs index 214e95bd3d..f98114d0cf 100644 --- a/bitcoin/src/network/mod.rs +++ b/bitcoin/src/network/mod.rs @@ -65,7 +65,7 @@ pub enum TestnetVersion { /// new, incompatible version of this type. If you are using this type directly and wish to support the /// new network, this will be a breaking change to your APIs and likely require changes in your code. /// -/// If you are concerned about forward compatibility, consider using `T: Into` instead of this +/// If you are concerned about forward compatibility, consider using `T: Into` instead of /// this type as a parameter to functions in your public API, or directly using the `Params` type. // For extensive discussion on the usage of `non_exhaustive` please see: // https://github.com/rust-bitcoin/rust-bitcoin/issues/2225 From 8cdd2a5c405f90434944165b95b343858fb912d0 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 23 Jul 2025 13:39:15 +1000 Subject: [PATCH 201/857] Add docs directory Add a `docs` directory including a basic README. The purpose is outline in the readme. Add an initial `roadmap`, done as a single patch because the roadmap is referenced in the readme. --- docs/README.md | 9 +++++++++ docs/address.md | 3 +++ docs/bip-32.md | 7 +++++++ docs/psbt.md | 8 ++++++++ docs/roadmap.md | 15 +++++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 docs/README.md create mode 100644 docs/address.md create mode 100644 docs/bip-32.md create mode 100644 docs/psbt.md create mode 100644 docs/roadmap.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..dcc5ab65f5 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,9 @@ +# rust-bitcoin documentation + +This directory holds documentation for the `rust-bitcoin` repository and potentially various other +directly related crates from the `rust-bitcoin` GitHub organisation (e.g. `rust-secp256k1`). + +In general, PR discussions on source code should be about the technical content of changes. To debate +whether a change should be made at all, or the strategy for making changes, it is better to first PR to +the `docs/` tree. If a PR discussion veers into this sort of strategic discussion, the PR should be put on +hold and a PR made to the `docs/` tree or in the Discussions section to debate it before moving forward. diff --git a/docs/address.md b/docs/address.md new file mode 100644 index 0000000000..f55b57989d --- /dev/null +++ b/docs/address.md @@ -0,0 +1,3 @@ +# Split out an address crate + +Split the `address` module out into its own crate. diff --git a/docs/bip-32.md b/docs/bip-32.md new file mode 100644 index 0000000000..4e780a52b4 --- /dev/null +++ b/docs/bip-32.md @@ -0,0 +1,7 @@ +# BIP-32 and BIP-380 + +The current module has not been patched much in the last 5 years and the rest of the code base has +stylistically changed quite a bit. + +* Re-write the BIP-32 API +* Add support for BIP-380 diff --git a/docs/psbt.md b/docs/psbt.md new file mode 100644 index 0000000000..6f24dcfd08 --- /dev/null +++ b/docs/psbt.md @@ -0,0 +1,8 @@ +# PSBT + +We would like to enable support for PSBTv2, not necessarily add support to `rust-bitcoin`. +Potentially we want to spilt out the current PSBTv1 into a separate crate. The serialization logic +likely stays in `rust-bitcoin`. There are various attempts at this in flight but mostly stale. + +* Initial support in `rust-bitcoin`: [#3507](https://github.com/rust-bitcoin/rust-bitcoin/pull/3507) +* Initial PSBTV2 impl: https://github.com/tcharding/rust-psbt diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000000..092bd5263e --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,15 @@ +# `rust-bitcoin` repository roadmap + +* ~Release `units v1.0.0-rc.0`~ +* Release `primitives v1.0.0-rc.0` + * Implement script tagging + * Add support for consensus encoding to `primitives` +* Release `bitcoin v0.33.0-rc.0` +* Split out an address crate (see [address.md](./address.md)) +* BIP-32 and BIP-380 (see [bip-32.md](./bip-32.md)) +* PSBTv2 (see [psbt.md](./psbt.md)) + +## RC cycle + +We want to do a long release candidate cycle to give time for downstream testing and feedback on the +API of the 1.0 crates. At a minimum this will be 6 months from the release `primitives-1.0-rc.0`. From fa92c10817342f17a62a093caac7bab9f6f37360 Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 27 Jul 2025 01:55:02 +0000 Subject: [PATCH 202/857] 2025-07-27 automated rustfmt nightly --- bitcoin/examples/sign-tx-segwit-v0.rs | 2 +- bitcoin/examples/sign-tx-taproot.rs | 2 +- bitcoin/src/blockdata/script/builder.rs | 4 +--- fuzz/fuzz_targets/bitcoin/deserialize_witness.rs | 2 +- units/src/locktime/absolute/error.rs | 1 + units/tests/api.rs | 9 +++++++-- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs index 7213db846b..2355c26491 100644 --- a/bitcoin/examples/sign-tx-segwit-v0.rs +++ b/bitcoin/examples/sign-tx-segwit-v0.rs @@ -2,8 +2,8 @@ //! Demonstrate creating a transaction that spends to and from p2wpkh outputs. -use bitcoin::key::WPubkeyHash; use bitcoin::ext::*; +use bitcoin::key::WPubkeyHash; use bitcoin::locktime::absolute; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing}; use bitcoin::sighash::{EcdsaSighashType, SighashCache}; diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index 361c52609e..077aa38cb7 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -2,8 +2,8 @@ //! Demonstrate creating a transaction that spends to and from p2tr outputs. -use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey}; use bitcoin::ext::*; +use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey}; use bitcoin::locktime::absolute; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing, Verification}; use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType}; diff --git a/bitcoin/src/blockdata/script/builder.rs b/bitcoin/src/blockdata/script/builder.rs index 58f89c4c0f..c9e0601a61 100644 --- a/bitcoin/src/blockdata/script/builder.rs +++ b/bitcoin/src/blockdata/script/builder.rs @@ -24,9 +24,7 @@ impl Builder { /// Constructs a new empty script builder with at least the specified capacity. #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self(ScriptBuf::with_capacity(capacity), None) - } + pub fn with_capacity(capacity: usize) -> Self { Self(ScriptBuf::with_capacity(capacity), None) } /// Returns the length in bytes of the script. pub fn len(&self) -> usize { self.0.len() } diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs b/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs index 42c201f70e..d4df534de3 100644 --- a/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs +++ b/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs @@ -1,7 +1,7 @@ +use arbitrary::{Arbitrary, Unstructured}; use bitcoin::consensus::{deserialize, serialize}; use bitcoin::witness::Witness; use honggfuzz::fuzz; -use arbitrary::{Arbitrary, Unstructured}; fn do_test(data: &[u8]) { let mut u = Unstructured::new(data); diff --git a/units/src/locktime/absolute/error.rs b/units/src/locktime/absolute/error.rs index 96e125d038..925d7105e3 100644 --- a/units/src/locktime/absolute/error.rs +++ b/units/src/locktime/absolute/error.rs @@ -266,6 +266,7 @@ mod tests { #[cfg(feature = "alloc")] fn locktime_unit_display() { use alloc::format; + use super::LockTimeUnit; let blocks = LockTimeUnit::Blocks; diff --git a/units/tests/api.rs b/units/tests/api.rs index d2e569e942..5ea14b413f 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -192,7 +192,9 @@ fn api_can_use_all_types_from_module_locktime_absolute() { use bitcoin_units::locktime::absolute::error::{ ConversionError as _, ParseHeightError as _, ParseTimeError as _, }; - use bitcoin_units::locktime::absolute::{Height, MedianTimePast, ConversionError, ParseHeightError, ParseTimeError}; + use bitcoin_units::locktime::absolute::{ + ConversionError, Height, MedianTimePast, ParseHeightError, ParseTimeError, + }; } #[test] @@ -200,7 +202,10 @@ fn api_can_use_all_types_from_module_locktime_relative() { use bitcoin_units::locktime::relative::error::{ InvalidHeightError as _, InvalidTimeError as _, TimeOverflowError as _, }; - use bitcoin_units::locktime::relative::{Height, NumberOf512Seconds, NumberOfBlocks, Time, InvalidHeightError, InvalidTimeError, TimeOverflowError}; + use bitcoin_units::locktime::relative::{ + Height, InvalidHeightError, InvalidTimeError, NumberOf512Seconds, NumberOfBlocks, Time, + TimeOverflowError, + }; } #[test] From 434e192ac12a4979b7d4a6050b94b346871ec0dd Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sun, 27 Jul 2025 15:15:19 +1000 Subject: [PATCH 203/857] Allow missing panics docs in const functions These functions explicitly do not panic, just allow the lint. --- units/src/amount/signed.rs | 2 ++ units/src/amount/unsigned.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/units/src/amount/signed.rs b/units/src/amount/signed.rs index c033eb316a..694f1a3c69 100644 --- a/units/src/amount/signed.rs +++ b/units/src/amount/signed.rs @@ -112,6 +112,7 @@ impl SignedAmount { /// /// Accepts an `i32` which is guaranteed to be in range for the type, but which can only /// represent roughly -21.47 to 21.47 BTC. + #[allow(clippy::missing_panics_doc)] pub const fn from_sat_i32(satoshi: i32) -> Self { let sats = satoshi as i64; // cannot use i64::from in a constfn match Self::from_sat(sats) { @@ -316,6 +317,7 @@ impl SignedAmount { /// /// This function never overflows or panics, unlike `i64::abs()`. #[must_use] + #[allow(clippy::missing_panics_doc)] pub const fn abs(self) -> Self { // `i64::abs()` can never overflow because SignedAmount::MIN == -MAX_MONEY. match Self::from_sat(self.to_sat().abs()) { diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 57e27e120f..9102807921 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -114,6 +114,7 @@ impl Amount { /// /// Accepts an `u32` which is guaranteed to be in range for the type, but which can only /// represent roughly 0 to 42.95 BTC. + #[allow(clippy::missing_panics_doc)] pub const fn from_sat_u32(satoshi: u32) -> Self { let sats = satoshi as u64; // cannot use i64::from in a constfn match Self::from_sat(sats) { From e064b14514209bdfe7ad02d84620bb86f7b56b61 Mon Sep 17 00:00:00 2001 From: nahem Date: Mon, 28 Jul 2025 11:12:53 +0200 Subject: [PATCH 204/857] Fix panic messages in from_sat_i32 and from_sat_u32 to include input value in satoshis --- units/src/amount/signed.rs | 2 +- units/src/amount/unsigned.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/units/src/amount/signed.rs b/units/src/amount/signed.rs index c033eb316a..ffaabba4fa 100644 --- a/units/src/amount/signed.rs +++ b/units/src/amount/signed.rs @@ -116,7 +116,7 @@ impl SignedAmount { let sats = satoshi as i64; // cannot use i64::from in a constfn match Self::from_sat(sats) { Ok(amount) => amount, - Err(_) => panic!("unreachable - 32,767 BTC is within range"), + Err(_) => panic!("unreachable - i32 input [-2,147,483,648 to 2,147,483,647 satoshis] is within range"), } } diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 57e27e120f..82b9516e94 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -118,7 +118,8 @@ impl Amount { let sats = satoshi as u64; // cannot use i64::from in a constfn match Self::from_sat(sats) { Ok(amount) => amount, - Err(_) => panic!("unreachable - 65,536 BTC is within range"), + Err(_) => + panic!("unreachable - u32 input [0 to 4,294,967,295 satoshis] is within range"), } } From 3a89e3f72f4df5dcf9bd09ff19e95a4019be4453 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Mon, 28 Jul 2025 11:40:51 +0100 Subject: [PATCH 205/857] p2p: Add a `V1MessageHeader` When using `p2p` and version one messaging, the user is put into a strange position where they must figure out how many bytes to read, but cannot do so without implementing some version of this type in their crate. Add a first-class `V1MessageHeader` so users may first decoded this, then the rest of the message. An example is in Floresta here: https://github.com/vinteumorg/Floresta/blob/5e78a8179da596101508ac6ad1a454e80c1635bc/crates/floresta-wire/src/p2p_wire/transport.rs#L85 Which is used to parse data here: https://github.com/vinteumorg/Floresta/blob/5e78a8179da596101508ac6ad1a454e80c1635bc/crates/floresta-wire/src/p2p_wire/transport.rs#L333 --- p2p/src/message.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/p2p/src/message.rs b/p2p/src/message.rs index 942e258285..7264693c51 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -17,7 +17,7 @@ use internals::ToU64 as _; use io::{BufRead, Write}; use crate::address::{AddrV2Message, Address}; -use crate::consensus::impl_vec_wrapper; +use crate::consensus::{impl_consensus_encoding, impl_vec_wrapper}; use crate::{ message_blockdata, message_bloom, message_compact_blocks, message_filter, message_network, Magic, @@ -159,6 +159,21 @@ pub struct RawNetworkMessage { checksum: [u8; 4], } +/// A v1 message header used to describe the incoming payload. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct V1MessageHeader { + /// The network magic, a unique 4 byte sequence. + pub magic: Magic, + /// The "command" used to describe the payload. + pub command: CommandString, + /// The length of the payload. + pub length: u32, + /// A checksum to the afformentioned data. + pub checksum: [u8; 4], +} + +impl_consensus_encoding!(V1MessageHeader, magic, command, length, checksum); + /// A Network message using the v2 p2p protocol defined in BIP324. #[derive(Clone, Debug, PartialEq, Eq)] pub struct V2NetworkMessage { From c98560f5380427619a9fccc3d831448efaba9fb9 Mon Sep 17 00:00:00 2001 From: bigbear <155267841+aso20455@users.noreply.github.com> Date: Mon, 28 Jul 2025 20:55:04 +0200 Subject: [PATCH 206/857] fix: correct typo in test function name "tyes" to "types" --- io/tests/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/tests/api.rs b/io/tests/api.rs index efc64f2e69..0267dc171a 100644 --- a/io/tests/api.rs +++ b/io/tests/api.rs @@ -130,7 +130,7 @@ fn api_all_non_error_types_have_non_empty_debug() { } #[test] -fn all_non_error_tyes_implement_send_sync() { +fn all_non_error_types_implement_send_sync() { fn assert_send() {} fn assert_sync() {} From b24dfeb7e6988c0514b13bb6fa469173025a9828 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Tue, 29 Jul 2025 13:33:26 +0100 Subject: [PATCH 207/857] Add user-agent header to curl command The weekly Update cargo-semver-checks returned `curl: (22) The requested URL returned error: 403` when run in CI. Add a user-agent header to fix it. --- .github/workflows/cron-weekly-update-cargo-semver-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cron-weekly-update-cargo-semver-checks.yml b/.github/workflows/cron-weekly-update-cargo-semver-checks.yml index 75f706a1cc..f992e756e8 100644 --- a/.github/workflows/cron-weekly-update-cargo-semver-checks.yml +++ b/.github/workflows/cron-weekly-update-cargo-semver-checks.yml @@ -14,7 +14,7 @@ jobs: set -x # Grab the latest version of cargo semver-checks from crates.io # that is not yanked. - LATEST_VERSION=$(curl --proto '=https' --tlsv1.3 -sSf https://crates.io/api/v1/crates/cargo-semver-checks/versions | jq -r 'first( .versions[] | select(.yanked == false) ) | .num') + LATEST_VERSION=$(curl --proto '=https' --tlsv1.3 -sSf -H "User-Agent: rust-bitcoin-ci" https://crates.io/api/v1/crates/cargo-semver-checks/versions | jq -r 'first( .versions[] | select(.yanked == false) ) | .num') # Update the latest version in the reference file. echo "${LATEST_VERSION}" > ./.github/workflows/cargo-semver-checks-version echo "cargo_semver_checks_version=${LATEST_VERSION}" >> $GITHUB_ENV From 05f58031d5b7af81aef3328832f9bbf70016879c Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Wed, 30 Jul 2025 09:59:10 +0300 Subject: [PATCH 208/857] Fix LICENSE link in p2p/README.md --- p2p/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/README.md b/p2p/README.md index f4fe096e40..2670b996bf 100644 --- a/p2p/README.md +++ b/p2p/README.md @@ -8,5 +8,5 @@ This library should always compile with any combination of features on **Rust 1. ## Licensing -The code in this project is licensed under the [Creative Commons CC0 1.0 Universal license](LICENSE). +The code in this project is licensed under the [Creative Commons CC0 1.0 Universal license](../LICENSE). We use the [SPDX license list](https://spdx.org/licenses/) and [SPDX IDs](https://spdx.dev/ids/). From 2688fdcf2fc866952f7c129e19a4ddec45efe8a8 Mon Sep 17 00:00:00 2001 From: Galoretka Date: Wed, 30 Jul 2025 12:10:36 +0300 Subject: [PATCH 209/857] fix small typo --- bitcoin/src/blockdata/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 3b1c19a90c..928ef668b6 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -2036,7 +2036,7 @@ mod tests { } #[test] - // needless_borrows_for_generic_args incorrecctly identifies &[] as a needless borrow + // needless_borrows_for_generic_args incorrectly identifies &[] as a needless borrow #[allow(clippy::needless_borrows_for_generic_args)] fn weight_prediction_new() { let p2wpkh_max = InputWeightPrediction::new(0, [72, 33]); From 2aae0dbec6c4c524873c8fdd970f7d4102769660 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 31 Jul 2025 09:40:18 +1000 Subject: [PATCH 210/857] Update nightly toolchain The recent bot update failed with lint warnings. We have already merged the fixes. Now CI is failing on all open PRs because `cargo public-api` requires nightly 2025-07-17 Manually update the nightly toolchain using the same version that the bot PR (#4712) would have used. --- nightly-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nightly-version b/nightly-version index 98cd340e39..f5765334c9 100644 --- a/nightly-version +++ b/nightly-version @@ -1 +1 @@ -nightly-2025-07-11 +nightly-2025-07-25 From 50caaaff3b705867884e1935552533e50a932aa6 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 31 Jul 2025 09:58:02 +1000 Subject: [PATCH 211/857] Run just check-api We recently started checking the API for `units` in CI but the text files are out of date because I did not update PR #4705 before merge. Run the script and update API text files for recent changes merged into `units`. --- api/units/all-features.txt | 673 +++++++++++++++++++++++++++---------- api/units/alloc-only.txt | 570 ++++++++++++++++++++++++------- api/units/no-features.txt | 555 +++++++++++++++++++++++------- 3 files changed, 1396 insertions(+), 402 deletions(-) diff --git a/api/units/all-features.txt b/api/units/all-features.txt index 4f4be7971a..67b20afebc 100644 --- a/api/units/all-features.txt +++ b/api/units/all-features.txt @@ -2,11 +2,14 @@ #[non_exhaustive] pub enum bitcoin_units::amount::Denomination #[non_exhaustive] pub enum bitcoin_units::amount::ParseDenominationError #[non_exhaustive] pub struct bitcoin_units::NumOpError(_) +#[non_exhaustive] pub struct bitcoin_units::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::absolute::error::ConversionError #[non_exhaustive] pub struct bitcoin_units::amount::MissingDenominationError #[non_exhaustive] pub struct bitcoin_units::amount::PossiblyConfusingDenominationError(_) #[non_exhaustive] pub struct bitcoin_units::amount::UnknownDenominationError(_) #[non_exhaustive] pub struct bitcoin_units::fee_rate::serde::OverflowError #[non_exhaustive] pub struct bitcoin_units::locktime::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::locktime::absolute::error::ConversionError #[non_exhaustive] pub struct bitcoin_units::parse::ParseIntError impl bitcoin_units::Amount impl bitcoin_units::BlockTime @@ -18,18 +21,19 @@ impl bitcoin_units::Weight impl bitcoin_units::amount::Denomination impl bitcoin_units::amount::Display impl bitcoin_units::amount::OutOfRangeError -impl bitcoin_units::amount::serde::SerdeAmount for bitcoin_units::Amount -impl bitcoin_units::amount::serde::SerdeAmount for bitcoin_units::SignedAmount -impl bitcoin_units::amount::serde::SerdeAmountForOpt for bitcoin_units::Amount -impl bitcoin_units::amount::serde::SerdeAmountForOpt for bitcoin_units::SignedAmount impl bitcoin_units::block::BlockHeight impl bitcoin_units::block::BlockHeightInterval impl bitcoin_units::block::BlockMtp impl bitcoin_units::block::BlockMtpInterval impl bitcoin_units::locktime::absolute::Height +impl bitcoin_units::locktime::absolute::LockTime impl bitcoin_units::locktime::absolute::MedianTimePast +impl bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl bitcoin_units::locktime::relative::LockTime impl bitcoin_units::locktime::relative::NumberOf512Seconds impl bitcoin_units::locktime::relative::NumberOfBlocks +impl bitcoin_units::locktime::relative::error::DisabledLockTimeError impl bitcoin_units::parse::Integer for i128 impl bitcoin_units::parse::Integer for i16 impl bitcoin_units::parse::Integer for i32 @@ -40,6 +44,7 @@ impl bitcoin_units::parse::Integer for u16 impl bitcoin_units::parse::Integer for u32 impl bitcoin_units::parse::Integer for u64 impl bitcoin_units::parse::Integer for u8 +impl bitcoin_units::sequence::Sequence impl core::clone::Clone for bitcoin_units::Amount impl core::clone::Clone for bitcoin_units::BlockTime impl core::clone::Clone for bitcoin_units::FeeRate @@ -66,19 +71,28 @@ impl core::clone::Clone for bitcoin_units::block::BlockMtp impl core::clone::Clone for bitcoin_units::block::BlockMtpInterval impl core::clone::Clone for bitcoin_units::block::TooBigForRelativeHeightError impl core::clone::Clone for bitcoin_units::fee_rate::serde::OverflowError -impl core::clone::Clone for bitcoin_units::locktime::absolute::ConversionError impl core::clone::Clone for bitcoin_units::locktime::absolute::Height +impl core::clone::Clone for bitcoin_units::locktime::absolute::LockTime impl core::clone::Clone for bitcoin_units::locktime::absolute::MedianTimePast -impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseHeightError -impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseTimeError -impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidHeightError -impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ConversionError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::LockTime impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::clone::Clone for bitcoin_units::locktime::relative::TimeOverflowError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::clone::Clone for bitcoin_units::parse::ParseIntError impl core::clone::Clone for bitcoin_units::parse::PrefixedHexError impl core::clone::Clone for bitcoin_units::parse::UnprefixedHexError +impl core::clone::Clone for bitcoin_units::sequence::Sequence impl core::cmp::Eq for bitcoin_units::Amount impl core::cmp::Eq for bitcoin_units::BlockTime impl core::cmp::Eq for bitcoin_units::FeeRate @@ -104,19 +118,28 @@ impl core::cmp::Eq for bitcoin_units::block::BlockMtp impl core::cmp::Eq for bitcoin_units::block::BlockMtpInterval impl core::cmp::Eq for bitcoin_units::block::TooBigForRelativeHeightError impl core::cmp::Eq for bitcoin_units::fee_rate::serde::OverflowError -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ConversionError impl core::cmp::Eq for bitcoin_units::locktime::absolute::Height +impl core::cmp::Eq for bitcoin_units::locktime::absolute::LockTime impl core::cmp::Eq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::LockTime impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::cmp::Eq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::cmp::Eq for bitcoin_units::parse::ParseIntError impl core::cmp::Eq for bitcoin_units::parse::PrefixedHexError impl core::cmp::Eq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Eq for bitcoin_units::sequence::Sequence impl core::cmp::Ord for bitcoin_units::Amount impl core::cmp::Ord for bitcoin_units::BlockTime impl core::cmp::Ord for bitcoin_units::FeeRate @@ -130,6 +153,7 @@ impl core::cmp::Ord for bitcoin_units::locktime::absolute::Height impl core::cmp::Ord for bitcoin_units::locktime::absolute::MedianTimePast impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::Ord for bitcoin_units::sequence::Sequence impl core::cmp::PartialEq for bitcoin_units::Amount impl core::cmp::PartialEq for bitcoin_units::BlockTime impl core::cmp::PartialEq for bitcoin_units::FeeRate @@ -155,19 +179,28 @@ impl core::cmp::PartialEq for bitcoin_units::block::BlockMtp impl core::cmp::PartialEq for bitcoin_units::block::BlockMtpInterval impl core::cmp::PartialEq for bitcoin_units::block::TooBigForRelativeHeightError impl core::cmp::PartialEq for bitcoin_units::fee_rate::serde::OverflowError -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ConversionError impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::LockTime impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::LockTime impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::cmp::PartialEq for bitcoin_units::parse::ParseIntError impl core::cmp::PartialEq for bitcoin_units::parse::PrefixedHexError impl core::cmp::PartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::PartialEq for bitcoin_units::sequence::Sequence impl core::cmp::PartialOrd for bitcoin_units::Amount impl core::cmp::PartialOrd for bitcoin_units::BlockTime impl core::cmp::PartialOrd for bitcoin_units::FeeRate @@ -181,6 +214,7 @@ impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::Height impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::MedianTimePast impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialOrd for bitcoin_units::sequence::Sequence impl core::convert::AsRef for bitcoin_units::parse::ParseIntError impl core::convert::From<&bitcoin_units::Amount> for bitcoin_units::NumOpResult impl core::convert::From<&bitcoin_units::SignedAmount> for bitcoin_units::NumOpResult @@ -206,12 +240,18 @@ impl core::convert::From for u32 impl core::convert::From for u32 impl core::convert::From for u32 impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::locktime::absolute::LockTime impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::locktime::absolute::LockTime +impl core::convert::From for bitcoin_units::sequence::Sequence impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::From for bitcoin_units::locktime::relative::LockTime impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::locktime::relative::LockTime impl core::convert::From for bitcoin_units::parse::PrefixedHexError impl core::convert::From for bitcoin_units::parse::UnprefixedHexError impl core::convert::From for core::num::error::ParseIntError +impl core::convert::From for u32 impl core::convert::From for bitcoin_units::amount::ParseAmountError impl core::convert::From for bitcoin_units::amount::ParseDenominationError impl core::convert::From for bitcoin_units::amount::ParseError @@ -230,37 +270,45 @@ impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtp impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom<&str> for bitcoin_units::sequence::Sequence impl core::convert::TryFrom> for bitcoin_units::Weight impl core::convert::TryFrom> for bitcoin_units::block::BlockHeight impl core::convert::TryFrom> for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom> for bitcoin_units::block::BlockMtp impl core::convert::TryFrom> for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom> for bitcoin_units::sequence::Sequence impl core::convert::TryFrom for bitcoin_units::Weight impl core::convert::TryFrom for bitcoin_units::block::BlockHeight impl core::convert::TryFrom for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom for bitcoin_units::block::BlockMtp impl core::convert::TryFrom for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::sequence::Sequence impl core::convert::TryFrom for bitcoin_units::Amount impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom for bitcoin_units::locktime::relative::LockTime impl core::default::Default for bitcoin_units::Amount impl core::default::Default for bitcoin_units::SignedAmount impl core::default::Default for bitcoin_units::block::BlockHeightInterval impl core::default::Default for bitcoin_units::block::BlockMtpInterval impl core::default::Default for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::default::Default for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::default::Default for bitcoin_units::sequence::Sequence impl core::error::Error for bitcoin_units::NumOpError impl core::error::Error for bitcoin_units::amount::InputTooLargeError impl core::error::Error for bitcoin_units::amount::InvalidCharacterError @@ -274,12 +322,18 @@ impl core::error::Error for bitcoin_units::amount::TooPreciseError impl core::error::Error for bitcoin_units::amount::UnknownDenominationError impl core::error::Error for bitcoin_units::block::TooBigForRelativeHeightError impl core::error::Error for bitcoin_units::fee_rate::serde::OverflowError -impl core::error::Error for bitcoin_units::locktime::absolute::ConversionError -impl core::error::Error for bitcoin_units::locktime::absolute::ParseHeightError -impl core::error::Error for bitcoin_units::locktime::absolute::ParseTimeError -impl core::error::Error for bitcoin_units::locktime::relative::InvalidHeightError -impl core::error::Error for bitcoin_units::locktime::relative::InvalidTimeError -impl core::error::Error for bitcoin_units::locktime::relative::TimeOverflowError +impl core::error::Error for bitcoin_units::locktime::absolute::error::ConversionError +impl core::error::Error for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::error::Error for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::error::Error for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::error::Error for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::error::Error for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::error::Error for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::error::Error for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::error::Error for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::error::Error for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::error::Error for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::error::Error for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::error::Error for bitcoin_units::parse::ParseIntError impl core::error::Error for bitcoin_units::parse::PrefixedHexError impl core::error::Error for bitcoin_units::parse::UnprefixedHexError @@ -309,19 +363,28 @@ impl core::fmt::Debug for bitcoin_units::block::BlockMtp impl core::fmt::Debug for bitcoin_units::block::BlockMtpInterval impl core::fmt::Debug for bitcoin_units::block::TooBigForRelativeHeightError impl core::fmt::Debug for bitcoin_units::fee_rate::serde::OverflowError -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ConversionError impl core::fmt::Debug for bitcoin_units::locktime::absolute::Height +impl core::fmt::Debug for bitcoin_units::locktime::absolute::LockTime impl core::fmt::Debug for bitcoin_units::locktime::absolute::MedianTimePast -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseHeightError -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseTimeError -impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidHeightError -impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ConversionError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::LockTime impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::fmt::Debug for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::fmt::Debug for bitcoin_units::parse::ParseIntError impl core::fmt::Debug for bitcoin_units::parse::PrefixedHexError impl core::fmt::Debug for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Debug for bitcoin_units::sequence::Sequence impl core::fmt::Display for bitcoin_units::Amount impl core::fmt::Display for bitcoin_units::MathOp impl core::fmt::Display for bitcoin_units::NumOpError @@ -345,19 +408,30 @@ impl core::fmt::Display for bitcoin_units::block::BlockMtp impl core::fmt::Display for bitcoin_units::block::BlockMtpInterval impl core::fmt::Display for bitcoin_units::block::TooBigForRelativeHeightError impl core::fmt::Display for bitcoin_units::fee_rate::serde::OverflowError -impl core::fmt::Display for bitcoin_units::locktime::absolute::ConversionError impl core::fmt::Display for bitcoin_units::locktime::absolute::Height +impl core::fmt::Display for bitcoin_units::locktime::absolute::LockTime impl core::fmt::Display for bitcoin_units::locktime::absolute::MedianTimePast -impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseHeightError -impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseTimeError -impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidHeightError -impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ConversionError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::LockTime impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::fmt::Display for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::fmt::Display for bitcoin_units::parse::ParseIntError impl core::fmt::Display for bitcoin_units::parse::PrefixedHexError impl core::fmt::Display for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Display for bitcoin_units::sequence::Sequence +impl core::fmt::LowerHex for bitcoin_units::sequence::Sequence +impl core::fmt::UpperHex for bitcoin_units::sequence::Sequence impl core::hash::Hash for bitcoin_units::Amount impl core::hash::Hash for bitcoin_units::BlockTime impl core::hash::Hash for bitcoin_units::FeeRate @@ -369,9 +443,12 @@ impl core::hash::Hash for bitcoin_units::block::BlockHeightInterval impl core::hash::Hash for bitcoin_units::block::BlockMtp impl core::hash::Hash for bitcoin_units::block::BlockMtpInterval impl core::hash::Hash for bitcoin_units::locktime::absolute::Height +impl core::hash::Hash for bitcoin_units::locktime::absolute::LockTime impl core::hash::Hash for bitcoin_units::locktime::absolute::MedianTimePast +impl core::hash::Hash for bitcoin_units::locktime::relative::LockTime impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::hash::Hash for bitcoin_units::sequence::Sequence impl core::iter::traits::accum::Sum for bitcoin_units::FeeRate impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult @@ -392,9 +469,12 @@ impl core::marker::Copy for bitcoin_units::block::BlockHeightInterval impl core::marker::Copy for bitcoin_units::block::BlockMtp impl core::marker::Copy for bitcoin_units::block::BlockMtpInterval impl core::marker::Copy for bitcoin_units::locktime::absolute::Height +impl core::marker::Copy for bitcoin_units::locktime::absolute::LockTime impl core::marker::Copy for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Copy for bitcoin_units::locktime::relative::LockTime impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Copy for bitcoin_units::sequence::Sequence impl core::marker::Freeze for bitcoin_units::Amount impl core::marker::Freeze for bitcoin_units::BlockTime impl core::marker::Freeze for bitcoin_units::FeeRate @@ -421,19 +501,28 @@ impl core::marker::Freeze for bitcoin_units::block::BlockMtp impl core::marker::Freeze for bitcoin_units::block::BlockMtpInterval impl core::marker::Freeze for bitcoin_units::block::TooBigForRelativeHeightError impl core::marker::Freeze for bitcoin_units::fee_rate::serde::OverflowError -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Freeze for bitcoin_units::locktime::absolute::Height +impl core::marker::Freeze for bitcoin_units::locktime::absolute::LockTime impl core::marker::Freeze for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::LockTime impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Freeze for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Freeze for bitcoin_units::parse::ParseIntError impl core::marker::Freeze for bitcoin_units::parse::PrefixedHexError impl core::marker::Freeze for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Freeze for bitcoin_units::sequence::Sequence impl core::marker::Send for bitcoin_units::Amount impl core::marker::Send for bitcoin_units::BlockTime impl core::marker::Send for bitcoin_units::FeeRate @@ -460,19 +549,28 @@ impl core::marker::Send for bitcoin_units::block::BlockMtp impl core::marker::Send for bitcoin_units::block::BlockMtpInterval impl core::marker::Send for bitcoin_units::block::TooBigForRelativeHeightError impl core::marker::Send for bitcoin_units::fee_rate::serde::OverflowError -impl core::marker::Send for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Send for bitcoin_units::locktime::absolute::Height +impl core::marker::Send for bitcoin_units::locktime::absolute::LockTime impl core::marker::Send for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Send for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Send for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Send for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Send for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::LockTime impl core::marker::Send for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Send for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Send for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Send for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Send for bitcoin_units::parse::ParseIntError impl core::marker::Send for bitcoin_units::parse::PrefixedHexError impl core::marker::Send for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Send for bitcoin_units::sequence::Sequence impl core::marker::StructuralPartialEq for bitcoin_units::Amount impl core::marker::StructuralPartialEq for bitcoin_units::BlockTime impl core::marker::StructuralPartialEq for bitcoin_units::FeeRate @@ -498,19 +596,28 @@ impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtp impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtpInterval impl core::marker::StructuralPartialEq for bitcoin_units::block::TooBigForRelativeHeightError impl core::marker::StructuralPartialEq for bitcoin_units::fee_rate::serde::OverflowError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ConversionError impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::Height +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::LockTime impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::LockTime impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::StructuralPartialEq for bitcoin_units::parse::ParseIntError impl core::marker::StructuralPartialEq for bitcoin_units::parse::PrefixedHexError impl core::marker::StructuralPartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::sequence::Sequence impl core::marker::Sync for bitcoin_units::Amount impl core::marker::Sync for bitcoin_units::BlockTime impl core::marker::Sync for bitcoin_units::FeeRate @@ -537,19 +644,28 @@ impl core::marker::Sync for bitcoin_units::block::BlockMtp impl core::marker::Sync for bitcoin_units::block::BlockMtpInterval impl core::marker::Sync for bitcoin_units::block::TooBigForRelativeHeightError impl core::marker::Sync for bitcoin_units::fee_rate::serde::OverflowError -impl core::marker::Sync for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Sync for bitcoin_units::locktime::absolute::Height +impl core::marker::Sync for bitcoin_units::locktime::absolute::LockTime impl core::marker::Sync for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::LockTime impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Sync for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Sync for bitcoin_units::parse::ParseIntError impl core::marker::Sync for bitcoin_units::parse::PrefixedHexError impl core::marker::Sync for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Sync for bitcoin_units::sequence::Sequence impl core::marker::Unpin for bitcoin_units::Amount impl core::marker::Unpin for bitcoin_units::BlockTime impl core::marker::Unpin for bitcoin_units::FeeRate @@ -576,19 +692,28 @@ impl core::marker::Unpin for bitcoin_units::block::BlockMtp impl core::marker::Unpin for bitcoin_units::block::BlockMtpInterval impl core::marker::Unpin for bitcoin_units::block::TooBigForRelativeHeightError impl core::marker::Unpin for bitcoin_units::fee_rate::serde::OverflowError -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Unpin for bitcoin_units::locktime::absolute::Height +impl core::marker::Unpin for bitcoin_units::locktime::absolute::LockTime impl core::marker::Unpin for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::LockTime impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Unpin for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Unpin for bitcoin_units::parse::ParseIntError impl core::marker::Unpin for bitcoin_units::parse::PrefixedHexError impl core::marker::Unpin for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Unpin for bitcoin_units::sequence::Sequence impl core::ops::arith::Add for bitcoin_units::Amount impl core::ops::arith::Add for bitcoin_units::FeeRate impl core::ops::arith::Add for bitcoin_units::SignedAmount @@ -841,19 +966,28 @@ impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtp impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtpInterval impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::fee_rate::serde::OverflowError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ConversionError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::LockTime impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ConversionError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::LockTime impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::ParseIntError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::PrefixedHexError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::sequence::Sequence impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Amount impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::BlockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::FeeRate @@ -880,19 +1014,28 @@ impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtp impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtpInterval impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::fee_rate::serde::OverflowError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ConversionError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::LockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ConversionError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::LockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::ParseIntError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::PrefixedHexError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::sequence::Sequence impl core::str::traits::FromStr for bitcoin_units::Amount impl core::str::traits::FromStr for bitcoin_units::SignedAmount impl core::str::traits::FromStr for bitcoin_units::Weight @@ -902,15 +1045,20 @@ impl core::str::traits::FromStr for bitcoin_units::block::BlockHeightInterval impl core::str::traits::FromStr for bitcoin_units::block::BlockMtp impl core::str::traits::FromStr for bitcoin_units::block::BlockMtpInterval impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::Height +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::LockTime impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::MedianTimePast impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::str::traits::FromStr for bitcoin_units::sequence::Sequence impl serde::ser::Serialize for bitcoin_units::BlockTime impl serde::ser::Serialize for bitcoin_units::Weight impl serde::ser::Serialize for bitcoin_units::block::BlockHeight impl serde::ser::Serialize for bitcoin_units::block::BlockHeightInterval impl serde::ser::Serialize for bitcoin_units::block::BlockMtp impl serde::ser::Serialize for bitcoin_units::block::BlockMtpInterval +impl serde::ser::Serialize for bitcoin_units::locktime::absolute::LockTime +impl serde::ser::Serialize for bitcoin_units::locktime::relative::LockTime +impl serde::ser::Serialize for bitcoin_units::sequence::Sequence impl<'a, T: arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for bitcoin_units::NumOpResult impl<'a, T> core::ops::arith::Add<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> impl<'a, T> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> @@ -928,9 +1076,11 @@ impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockHeightInterval impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockMtp impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockMtpInterval impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::Height +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::LockTime impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::MedianTimePast impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::relative::NumberOf512Seconds impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::relative::NumberOfBlocks +impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::sequence::Sequence impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::FeeRate> for bitcoin_units::FeeRate impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::NumOpResult> for bitcoin_units::NumOpResult @@ -1009,15 +1159,15 @@ impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockHeight impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockHeightInterval impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockMtp impl<'de> serde::de::Deserialize<'de> for bitcoin_units::block::BlockMtpInterval +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::locktime::absolute::LockTime +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::locktime::relative::LockTime +impl<'de> serde::de::Deserialize<'de> for bitcoin_units::sequence::Sequence impl core::clone::Clone for bitcoin_units::NumOpResult impl core::cmp::Eq for bitcoin_units::NumOpResult impl core::cmp::PartialEq for bitcoin_units::NumOpResult impl bitcoin_units::NumOpResult impl core::fmt::Debug for bitcoin_units::NumOpResult impl core::marker::Copy for bitcoin_units::NumOpResult -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator impl bitcoin_units::NumOpResult impl core::marker::Freeze for bitcoin_units::NumOpResult where T: core::marker::Freeze impl core::marker::Send for bitcoin_units::NumOpResult where T: core::marker::Send @@ -1046,6 +1196,8 @@ pub bitcoin_units::MathOp::Rem pub bitcoin_units::MathOp::Sub pub bitcoin_units::NumOpResult::Error(bitcoin_units::NumOpError) pub bitcoin_units::NumOpResult::Valid(T) +pub bitcoin_units::absolute::LockTime::Blocks(bitcoin_units::locktime::absolute::Height) +pub bitcoin_units::absolute::LockTime::Seconds(bitcoin_units::locktime::absolute::MedianTimePast) pub bitcoin_units::amount::Denomination::Bit pub bitcoin_units::amount::Denomination::Bitcoin pub bitcoin_units::amount::Denomination::CentiBitcoin @@ -1054,6 +1206,36 @@ pub bitcoin_units::amount::Denomination::MilliBitcoin pub bitcoin_units::amount::Denomination::Satoshi pub bitcoin_units::amount::ParseDenominationError::PossiblyConfusing(bitcoin_units::amount::PossiblyConfusingDenominationError) pub bitcoin_units::amount::ParseDenominationError::Unknown(bitcoin_units::amount::UnknownDenominationError) +pub bitcoin_units::locktime::absolute::LockTime::Blocks(bitcoin_units::locktime::absolute::Height) +pub bitcoin_units::locktime::absolute::LockTime::Seconds(bitcoin_units::locktime::absolute::MedianTimePast) +pub bitcoin_units::locktime::relative::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::LockTime::Blocks(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::LockTime::Time(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::LockTime::Blocks(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::LockTime::Time(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::error::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::error::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::error::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::error::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::error::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::error::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) pub const bitcoin_units::Amount::FIFTY_BTC: Self pub const bitcoin_units::Amount::MAX: Self pub const bitcoin_units::Amount::MAX_MONEY: Self @@ -1080,6 +1262,7 @@ pub const bitcoin_units::Weight::MIN: bitcoin_units::Weight pub const bitcoin_units::Weight::MIN_TRANSACTION: bitcoin_units::Weight pub const bitcoin_units::Weight::WITNESS_SCALE_FACTOR: u64 pub const bitcoin_units::Weight::ZERO: bitcoin_units::Weight +pub const bitcoin_units::absolute::LOCK_TIME_THRESHOLD: u32 pub const bitcoin_units::amount::Denomination::BTC: Self pub const bitcoin_units::amount::Denomination::SAT: Self pub const bitcoin_units::block::BlockHeight::MAX: Self @@ -1098,14 +1281,25 @@ pub const bitcoin_units::locktime::absolute::Height::MAX: Self pub const bitcoin_units::locktime::absolute::Height::MIN: Self pub const bitcoin_units::locktime::absolute::Height::ZERO: Self pub const bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD: u32 +pub const bitcoin_units::locktime::absolute::LockTime::SIZE: usize +pub const bitcoin_units::locktime::absolute::LockTime::ZERO: bitcoin_units::locktime::absolute::LockTime pub const bitcoin_units::locktime::absolute::MedianTimePast::MAX: Self pub const bitcoin_units::locktime::absolute::MedianTimePast::MIN: Self +pub const bitcoin_units::locktime::relative::LockTime::SIZE: usize +pub const bitcoin_units::locktime::relative::LockTime::ZERO: bitcoin_units::locktime::relative::LockTime pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MAX: Self pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MIN: Self pub const bitcoin_units::locktime::relative::NumberOf512Seconds::ZERO: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::MAX: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::MIN: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::ZERO: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_LOCKTIME_AND_RBF: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_LOCKTIME_NO_RBF: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_RBF_NO_LOCKTIME: Self +pub const bitcoin_units::sequence::Sequence::FINAL: Self +pub const bitcoin_units::sequence::Sequence::MAX: Self +pub const bitcoin_units::sequence::Sequence::SIZE: usize +pub const bitcoin_units::sequence::Sequence::ZERO: Self pub const bitcoin_units::weight::WITNESS_SCALE_FACTOR: usize pub const fn bitcoin_units::Amount::checked_add(self, rhs: Self) -> core::option::Option pub const fn bitcoin_units::Amount::checked_div(self, rhs: u64) -> core::option::Option @@ -1168,6 +1362,8 @@ pub const fn bitcoin_units::Weight::to_kwu_floor(self) -> u64 pub const fn bitcoin_units::Weight::to_vbytes_ceil(self) -> u64 pub const fn bitcoin_units::Weight::to_vbytes_floor(self) -> u64 pub const fn bitcoin_units::Weight::to_wu(self) -> u64 +pub const fn bitcoin_units::absolute::is_block_height(n: u32) -> bool +pub const fn bitcoin_units::absolute::is_block_time(n: u32) -> bool pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockHeightInterval::from_u32(inner: u32) -> Self @@ -1175,18 +1371,28 @@ pub const fn bitcoin_units::block::BlockHeightInterval::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockMtp::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockMtp::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockMtpInterval::from_u32(inner: u32) -> Self -pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result -pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result pub const fn bitcoin_units::block::BlockMtpInterval::to_u32(self) -> u32 -pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result pub const fn bitcoin_units::locktime::absolute::Height::to_u32(self) -> u32 -pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::LockTime::is_block_height(self) -> bool +pub const fn bitcoin_units::locktime::absolute::LockTime::is_block_time(self) -> bool +pub const fn bitcoin_units::locktime::absolute::LockTime::is_same_unit(self, other: bitcoin_units::locktime::absolute::LockTime) -> bool +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result pub const fn bitcoin_units::locktime::absolute::MedianTimePast::to_u32(self) -> u32 pub const fn bitcoin_units::locktime::absolute::is_block_height(n: u32) -> bool pub const fn bitcoin_units::locktime::absolute::is_block_time(n: u32) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::from_512_second_intervals(intervals: u16) -> Self +pub const fn bitcoin_units::locktime::relative::LockTime::from_height(n: u16) -> Self +pub const fn bitcoin_units::locktime::relative::LockTime::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::LockTime::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::LockTime::is_block_height(self) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::is_block_time(self) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::is_same_unit(self, other: bitcoin_units::locktime::relative::LockTime) -> bool pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_512_second_intervals(intervals: u16) -> Self -pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result -pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_512_second_intervals(self) -> u16 pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_consensus_u32(self) -> u32 pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_seconds(self) -> u32 @@ -1194,6 +1400,22 @@ pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::from_height(bloc pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_consensus_u32(self) -> u32 pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_height(self) -> u16 pub enum bitcoin_units::NumOpResult +pub enum bitcoin_units::absolute::LockTime +pub enum bitcoin_units::locktime::absolute::LockTime +pub enum bitcoin_units::locktime::relative::IsSatisfiedByError +pub enum bitcoin_units::locktime::relative::IsSatisfiedByHeightError +pub enum bitcoin_units::locktime::relative::IsSatisfiedByTimeError +pub enum bitcoin_units::locktime::relative::LockTime +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByError +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +pub enum bitcoin_units::relative::IsSatisfiedByError +pub enum bitcoin_units::relative::IsSatisfiedByHeightError +pub enum bitcoin_units::relative::IsSatisfiedByTimeError +pub enum bitcoin_units::relative::LockTime +pub enum bitcoin_units::relative::error::IsSatisfiedByError +pub enum bitcoin_units::relative::error::IsSatisfiedByHeightError +pub enum bitcoin_units::relative::error::IsSatisfiedByTimeError pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1334,9 +1556,6 @@ pub fn &u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output -pub fn T::checked_sum(self) -> core::option::Option -pub fn T::checked_sum(self) -> core::option::Option -pub fn T::checked_sum(self) -> core::option::Option pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1345,9 +1564,6 @@ pub fn bitcoin_units::Amount::arbitrary(u: &mut arbitrary::unstructured::Unstruc pub fn bitcoin_units::Amount::clone(&self) -> bitcoin_units::Amount pub fn bitcoin_units::Amount::cmp(&self, other: &bitcoin_units::Amount) -> core::cmp::Ordering pub fn bitcoin_units::Amount::default() -> Self -pub fn bitcoin_units::Amount::des_btc<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::Amount::des_sat<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::Amount::des_str<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> pub fn bitcoin_units::Amount::display_dynamic(self) -> bitcoin_units::amount::Display pub fn bitcoin_units::Amount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display pub fn bitcoin_units::Amount::div(self, rhs: &bitcoin_units::Amount) -> Self::Output @@ -1378,12 +1594,6 @@ pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output -pub fn bitcoin_units::Amount::ser_btc(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::Amount::ser_btc_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::Amount::ser_sat(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::Amount::ser_sat_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::Amount::ser_str(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::Amount::ser_str_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1394,7 +1604,6 @@ pub fn bitcoin_units::Amount::to_signed(self) -> bitcoin_units::SignedAmount pub fn bitcoin_units::Amount::to_string_in(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String pub fn bitcoin_units::Amount::to_string_with_denomination(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String pub fn bitcoin_units::Amount::try_from(value: bitcoin_units::SignedAmount) -> core::result::Result -pub fn bitcoin_units::Amount::type_prefix(_: bitcoin_units::amount::serde::private::Token) -> &'static str pub fn bitcoin_units::BlockTime::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result pub fn bitcoin_units::BlockTime::clone(&self) -> bitcoin_units::BlockTime pub fn bitcoin_units::BlockTime::cmp(&self, other: &bitcoin_units::BlockTime) -> core::cmp::Ordering @@ -1405,7 +1614,6 @@ pub fn bitcoin_units::BlockTime::from(t: u32) -> Self pub fn bitcoin_units::BlockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::BlockTime::partial_cmp(&self, other: &bitcoin_units::BlockTime) -> core::option::Option pub fn bitcoin_units::BlockTime::serialize(&self, s: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer -pub fn bitcoin_units::CheckedSum::checked_sum(self) -> core::option::Option pub fn bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output pub fn bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: &bitcoin_units::FeeRate) @@ -1522,9 +1730,6 @@ pub fn bitcoin_units::SignedAmount::arbitrary(u: &mut arbitrary::unstructured::U pub fn bitcoin_units::SignedAmount::clone(&self) -> bitcoin_units::SignedAmount pub fn bitcoin_units::SignedAmount::cmp(&self, other: &bitcoin_units::SignedAmount) -> core::cmp::Ordering pub fn bitcoin_units::SignedAmount::default() -> Self -pub fn bitcoin_units::SignedAmount::des_btc<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::SignedAmount::des_sat<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::SignedAmount::des_str<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> pub fn bitcoin_units::SignedAmount::display_dynamic(self) -> bitcoin_units::amount::Display pub fn bitcoin_units::SignedAmount::display_in(self, denomination: bitcoin_units::amount::Denomination) -> bitcoin_units::amount::Display pub fn bitcoin_units::SignedAmount::div(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output @@ -1552,12 +1757,6 @@ pub fn bitcoin_units::SignedAmount::partial_cmp(&self, other: &bitcoin_units::Si pub fn bitcoin_units::SignedAmount::positive_sub(self, rhs: Self) -> core::option::Option pub fn bitcoin_units::SignedAmount::rem(self, modulus: i64) -> Self::Output pub fn bitcoin_units::SignedAmount::rem(self, rhs: &i64) -> Self::Output -pub fn bitcoin_units::SignedAmount::ser_btc(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::SignedAmount::ser_btc_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::SignedAmount::ser_sat(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::SignedAmount::ser_sat_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::SignedAmount::ser_str(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::SignedAmount::ser_str_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> pub fn bitcoin_units::SignedAmount::signum(self) -> i64 pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::SignedAmount::sub(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output @@ -1568,7 +1767,6 @@ pub fn bitcoin_units::SignedAmount::to_float_in(self, denom: bitcoin_units::amou pub fn bitcoin_units::SignedAmount::to_string_in(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String pub fn bitcoin_units::SignedAmount::to_string_with_denomination(self, denom: bitcoin_units::amount::Denomination) -> alloc::string::String pub fn bitcoin_units::SignedAmount::to_unsigned(self) -> core::result::Result -pub fn bitcoin_units::SignedAmount::type_prefix(_: bitcoin_units::amount::serde::private::Token) -> &'static str pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount pub fn bitcoin_units::Weight::add(self, rhs: &bitcoin_units::Weight) -> Self::Output pub fn bitcoin_units::Weight::add(self, rhs: bitcoin_units::Weight) -> Self::Output @@ -1677,28 +1875,18 @@ pub fn bitcoin_units::amount::UnknownDenominationError::clone(&self) -> bitcoin_ pub fn bitcoin_units::amount::UnknownDenominationError::eq(&self, other: &bitcoin_units::amount::UnknownDenominationError) -> bool pub fn bitcoin_units::amount::UnknownDenominationError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::amount::UnknownDenominationError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> -pub fn bitcoin_units::amount::serde::SerdeAmount::des_btc<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::amount::serde::SerdeAmount::des_sat<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::amount::serde::SerdeAmount::des_str<'d, D: serde::de::Deserializer<'d>>(d: D, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result::Error> -pub fn bitcoin_units::amount::serde::SerdeAmount::ser_btc(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::SerdeAmount::ser_sat(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::SerdeAmount::ser_str(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::ser_btc_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::ser_sat_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::ser_str_opt(self, s: S, _: bitcoin_units::amount::serde::private::Token) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::SerdeAmountForOpt::type_prefix(_: bitcoin_units::amount::serde::private::Token) -> &'static str -pub fn bitcoin_units::amount::serde::as_btc::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmount, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> -pub fn bitcoin_units::amount::serde::as_btc::opt::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmountForOpt, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> -pub fn bitcoin_units::amount::serde::as_btc::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::as_btc::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::as_sat::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmount, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> -pub fn bitcoin_units::amount::serde::as_sat::opt::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmountForOpt, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> -pub fn bitcoin_units::amount::serde::as_sat::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::as_sat::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::as_str::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmount, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> -pub fn bitcoin_units::amount::serde::as_str::opt::deserialize<'d, A: bitcoin_units::amount::serde::SerdeAmountForOpt, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> -pub fn bitcoin_units::amount::serde::as_str::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::amount::serde::as_str::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> +pub fn bitcoin_units::amount::serde::as_btc::deserialize<'d, A, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> where A: core::convert::TryFrom, >::Error: core::fmt::Display +pub fn bitcoin_units::amount::serde::as_btc::opt::deserialize<'d, A, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> where A: core::convert::TryFrom, >::Error: core::fmt::Display +pub fn bitcoin_units::amount::serde::as_btc::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> where A: core::convert::Into + core::marker::Copy +pub fn bitcoin_units::amount::serde::as_btc::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> where A: core::convert::Into + core::marker::Copy +pub fn bitcoin_units::amount::serde::as_sat::deserialize<'d, A, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> where A: core::convert::TryFrom, >::Error: core::fmt::Display +pub fn bitcoin_units::amount::serde::as_sat::opt::deserialize<'d, A, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> where A: core::convert::TryFrom, >::Error: core::fmt::Display +pub fn bitcoin_units::amount::serde::as_sat::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> where A: core::convert::Into + core::marker::Copy +pub fn bitcoin_units::amount::serde::as_sat::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> where A: core::convert::Into + core::marker::Copy +pub fn bitcoin_units::amount::serde::as_str::deserialize<'d, A, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result::Error> where A: core::convert::TryFrom, >::Error: core::fmt::Display +pub fn bitcoin_units::amount::serde::as_str::opt::deserialize<'d, A, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> where A: core::convert::TryFrom, >::Error: core::fmt::Display +pub fn bitcoin_units::amount::serde::as_str::opt::serialize(a: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> where A: core::convert::Into + core::marker::Copy +pub fn bitcoin_units::amount::serde::as_str::serialize(a: &A, s: S) -> core::result::Result<::Ok, ::Error> where A: core::convert::Into + core::marker::Copy pub fn bitcoin_units::block::BlockHeight::add(self, rhs: &bitcoin_units::block::BlockHeightInterval) -> Self::Output pub fn bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockHeightInterval) -> Self::Output pub fn bitcoin_units::block::BlockHeight::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result @@ -1821,16 +2009,12 @@ pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::deserialize<'d, D: s pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::opt::deserialize<'d, D: serde::de::Deserializer<'d>>(d: D) -> core::result::Result, ::Error> pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::opt::serialize(f: &core::option::Option, s: S) -> core::result::Result<::Ok, ::Error> pub fn bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::serialize(f: &bitcoin_units::FeeRate, s: S) -> core::result::Result<::Ok, ::Error> -pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::ConversionError -pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool -pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ConversionError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> pub fn bitcoin_units::locktime::absolute::Height::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering pub fn bitcoin_units::locktime::absolute::Height::eq(&self, other: &bitcoin_units::locktime::absolute::Height) -> bool pub fn bitcoin_units::locktime::absolute::Height::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::locktime::absolute::Height::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height) -> bool @@ -1839,35 +2023,84 @@ pub fn bitcoin_units::locktime::absolute::Height::try_from(h: bitcoin_units::blo pub fn bitcoin_units::locktime::absolute::Height::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::locktime::absolute::LockTime::clone(&self) -> bitcoin_units::locktime::absolute::LockTime +pub fn bitcoin_units::locktime::absolute::LockTime::deserialize(deserializer: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::locktime::absolute::LockTime::eq(&self, other: &bitcoin_units::locktime::absolute::LockTime) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from(h: bitcoin_units::locktime::absolute::Height) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from(t: bitcoin_units::locktime::absolute::MedianTimePast) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from_consensus(n: u32) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from_height(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_mtp(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_unprefixed_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::LockTime::is_implied_by(self, other: bitcoin_units::locktime::absolute::LockTime) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height, mtp: bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by_height(self, height: bitcoin_units::locktime::absolute::Height) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by_time(self, mtp: bitcoin_units::locktime::absolute::MedianTimePast) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::serialize(&self, serializer: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::locktime::absolute::LockTime::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: alloc::string::String) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::clone(&self) -> bitcoin_units::locktime::absolute::MedianTimePast pub fn bitcoin_units::locktime::absolute::MedianTimePast::cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::cmp::Ordering pub fn bitcoin_units::locktime::absolute::MedianTimePast::eq(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> bool pub fn bitcoin_units::locktime::absolute::MedianTimePast::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::locktime::absolute::MedianTimePast::is_satisfied_by(self, time: bitcoin_units::locktime::absolute::MedianTimePast) -> bool -pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::option::Option pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(h: bitcoin_units::block::BlockMtp) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::string::String) -> core::result::Result -pub fn bitcoin_units::locktime::absolute::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::ParseHeightError -pub fn bitcoin_units::locktime::absolute::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseHeightError) -> bool -pub fn bitcoin_units::locktime::absolute::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ParseHeightError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> -pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::ParseTimeError -pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool -pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ParseTimeError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> -pub fn bitcoin_units::locktime::relative::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::InvalidHeightError -pub fn bitcoin_units::locktime::relative::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidHeightError) -> bool -pub fn bitcoin_units::locktime::relative::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::relative::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::InvalidTimeError -pub fn bitcoin_units::locktime::relative::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidTimeError) -> bool -pub fn bitcoin_units::locktime::relative::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::error::ConversionError +pub fn bitcoin_units::locktime::absolute::error::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ConversionError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ConversionError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::clone(&self) -> bitcoin_units::locktime::absolute::error::IncompatibleHeightError +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::error::IncompatibleHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::incompatible(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::lock(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::clone(&self) -> bitcoin_units::locktime::absolute::error::IncompatibleTimeError +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::error::IncompatibleTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::incompatible(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::lock(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::error::ParseHeightError +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ParseHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::error::ParseTimeError +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ParseTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::relative::LockTime::clone(&self) -> bitcoin_units::locktime::relative::LockTime +pub fn bitcoin_units::locktime::relative::LockTime::deserialize(deserializer: D) -> core::result::Result::Error> where D: serde::de::Deserializer<'de> +pub fn bitcoin_units::locktime::relative::LockTime::eq(&self, other: &bitcoin_units::locktime::relative::LockTime) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::LockTime::from(h: bitcoin_units::locktime::relative::NumberOfBlocks) -> Self +pub fn bitcoin_units::locktime::relative::LockTime::from(t: bitcoin_units::locktime::relative::NumberOf512Seconds) -> Self +pub fn bitcoin_units::locktime::relative::LockTime::from_consensus(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::from_sequence(n: bitcoin_units::sequence::Sequence) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::LockTime::is_implied_by(self, other: bitcoin_units::locktime::relative::LockTime) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::is_implied_by_sequence(self, other: bitcoin_units::sequence::Sequence) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by(self, chain_tip_height: bitcoin_units::block::BlockHeight, chain_tip_mtp: bitcoin_units::block::BlockMtp, utxo_mined_at_height: bitcoin_units::block::BlockHeight, utxo_mined_at_mtp: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by_height(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by_time(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::serialize(&self, serializer: S) -> core::result::Result<::Ok, ::Error> where S: serde::ser::Serializer +pub fn bitcoin_units::locktime::relative::LockTime::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::locktime::relative::LockTime::to_sequence(self) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::locktime::relative::LockTime::try_from(seq: bitcoin_units::sequence::Sequence) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::clone(&self) -> bitcoin_units::locktime::relative::NumberOf512Seconds pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::cmp::Ordering @@ -1876,7 +2109,7 @@ pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::eq(&self, other: & pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::hash<__H: core::hash::Hasher>(&self, state: &mut __H) -pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::option::Option pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: alloc::boxed::Box) -> core::result::Result @@ -1890,15 +2123,37 @@ pub fn bitcoin_units::locktime::relative::NumberOfBlocks::fmt(&self, f: &mut cor pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from(value: u16) -> Self pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::hash<__H: core::hash::Hasher>(&self, state: &mut __H) -pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::option::Option pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(h: bitcoin_units::block::BlockHeightInterval) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::string::String) -> core::result::Result -pub fn bitcoin_units::locktime::relative::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::TimeOverflowError -pub fn bitcoin_units::locktime::relative::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::TimeOverflowError) -> bool -pub fn bitcoin_units::locktime::relative::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::DisabledLockTimeError +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::disabled_locktime_value(&self) -> u32 +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::DisabledLockTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::error::InvalidHeightError +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::error::InvalidHeightError) -> bool +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::InvalidTimeError +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::InvalidTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::error::TimeOverflowError +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::error::TimeOverflowError) -> bool +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::parse::ParseIntError::as_ref(&self) -> &core::num::error::ParseIntError pub fn bitcoin_units::parse::ParseIntError::clone(&self) -> bitcoin_units::parse::ParseIntError pub fn bitcoin_units::parse::ParseIntError::eq(&self, other: &bitcoin_units::parse::ParseIntError) -> bool @@ -1929,6 +2184,37 @@ pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result pub fn bitcoin_units::parse::int_from_box(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::parse::int_from_str(s: &str) -> core::result::Result pub fn bitcoin_units::parse::int_from_string(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result +pub fn bitcoin_units::sequence::Sequence::clone(&self) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::sequence::Sequence::cmp(&self, other: &bitcoin_units::sequence::Sequence) -> core::cmp::Ordering +pub fn bitcoin_units::sequence::Sequence::default() -> Self +pub fn bitcoin_units::sequence::Sequence::deserialize<__D>(__deserializer: __D) -> core::result::Result::Error> where __D: serde::de::Deserializer<'de> +pub fn bitcoin_units::sequence::Sequence::enables_absolute_lock_time(self) -> bool +pub fn bitcoin_units::sequence::Sequence::eq(&self, other: &bitcoin_units::sequence::Sequence) -> bool +pub fn bitcoin_units::sequence::Sequence::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::sequence::Sequence::from(lt: bitcoin_units::locktime::relative::LockTime) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::sequence::Sequence::from_512_second_intervals(intervals: u16) -> Self +pub fn bitcoin_units::sequence::Sequence::from_consensus(n: u32) -> Self +pub fn bitcoin_units::sequence::Sequence::from_height(height: u16) -> Self +pub fn bitcoin_units::sequence::Sequence::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_seconds_ceil(seconds: u32) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_seconds_floor(seconds: u32) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_unprefixed_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::sequence::Sequence::is_final(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_height_locked(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_rbf(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_relative_lock_time(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_time_locked(self) -> bool +pub fn bitcoin_units::sequence::Sequence::partial_cmp(&self, other: &bitcoin_units::sequence::Sequence) -> core::option::Option +pub fn bitcoin_units::sequence::Sequence::serialize<__S>(&self, __serializer: __S) -> core::result::Result<<__S as serde::ser::Serializer>::Ok, <__S as serde::ser::Serializer>::Error> where __S: serde::ser::Serializer +pub fn bitcoin_units::sequence::Sequence::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::sequence::Sequence::to_hex(self) -> alloc::string::String +pub fn bitcoin_units::sequence::Sequence::to_relative_lock_time(self) -> core::option::Option +pub fn bitcoin_units::sequence::Sequence::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::try_from(s: alloc::string::String) -> core::result::Result pub fn core::num::error::ParseIntError::from(value: bitcoin_units::parse::ParseIntError) -> Self pub fn i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output @@ -1938,6 +2224,7 @@ pub fn u32::from(height: bitcoin_units::block::BlockHeight) -> Self pub fn u32::from(height: bitcoin_units::block::BlockHeightInterval) -> Self pub fn u32::from(height: bitcoin_units::block::BlockMtp) -> Self pub fn u32::from(height: bitcoin_units::block::BlockMtpInterval) -> Self +pub fn u32::from(sequence: bitcoin_units::sequence::Sequence) -> u32 pub fn u32::from(t: bitcoin_units::BlockTime) -> Self pub fn u64::from(value: bitcoin_units::Weight) -> Self pub fn u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output @@ -1947,6 +2234,8 @@ pub fn u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output pub fn u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output pub fn u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output pub mod bitcoin_units +pub mod bitcoin_units::absolute +pub mod bitcoin_units::absolute::error pub mod bitcoin_units::amount pub mod bitcoin_units::amount::serde pub mod bitcoin_units::amount::serde::as_btc @@ -1967,8 +2256,13 @@ pub mod bitcoin_units::fee_rate::serde::as_sat_per_vb_floor pub mod bitcoin_units::fee_rate::serde::as_sat_per_vb_floor::opt pub mod bitcoin_units::locktime pub mod bitcoin_units::locktime::absolute +pub mod bitcoin_units::locktime::absolute::error pub mod bitcoin_units::locktime::relative +pub mod bitcoin_units::locktime::relative::error pub mod bitcoin_units::parse +pub mod bitcoin_units::relative +pub mod bitcoin_units::relative::error +pub mod bitcoin_units::sequence pub mod bitcoin_units::time pub mod bitcoin_units::weight pub struct bitcoin_units::Amount(_) @@ -1978,8 +2272,19 @@ pub struct bitcoin_units::BlockMtp(_) pub struct bitcoin_units::BlockMtpInterval(_) pub struct bitcoin_units::BlockTime(_) pub struct bitcoin_units::FeeRate(_) +pub struct bitcoin_units::Sequence(pub u32) pub struct bitcoin_units::SignedAmount(_) pub struct bitcoin_units::Weight(_) +pub struct bitcoin_units::absolute::Height(_) +pub struct bitcoin_units::absolute::IncompatibleHeightError +pub struct bitcoin_units::absolute::IncompatibleTimeError +pub struct bitcoin_units::absolute::MedianTimePast(_) +pub struct bitcoin_units::absolute::ParseHeightError(_) +pub struct bitcoin_units::absolute::ParseTimeError(_) +pub struct bitcoin_units::absolute::error::IncompatibleHeightError +pub struct bitcoin_units::absolute::error::IncompatibleTimeError +pub struct bitcoin_units::absolute::error::ParseHeightError(_) +pub struct bitcoin_units::absolute::error::ParseTimeError(_) pub struct bitcoin_units::amount::Amount(_) pub struct bitcoin_units::amount::Display pub struct bitcoin_units::amount::InputTooLargeError @@ -1997,21 +2302,40 @@ pub struct bitcoin_units::block::BlockMtpInterval(_) pub struct bitcoin_units::block::TooBigForRelativeHeightError(_) pub struct bitcoin_units::fee_rate::FeeRate(_) pub struct bitcoin_units::locktime::absolute::Height(_) +pub struct bitcoin_units::locktime::absolute::IncompatibleHeightError +pub struct bitcoin_units::locktime::absolute::IncompatibleTimeError pub struct bitcoin_units::locktime::absolute::MedianTimePast(_) pub struct bitcoin_units::locktime::absolute::ParseHeightError(_) pub struct bitcoin_units::locktime::absolute::ParseTimeError(_) +pub struct bitcoin_units::locktime::absolute::error::IncompatibleHeightError +pub struct bitcoin_units::locktime::absolute::error::IncompatibleTimeError +pub struct bitcoin_units::locktime::absolute::error::ParseHeightError(_) +pub struct bitcoin_units::locktime::absolute::error::ParseTimeError(_) +pub struct bitcoin_units::locktime::relative::DisabledLockTimeError(_) pub struct bitcoin_units::locktime::relative::InvalidHeightError pub struct bitcoin_units::locktime::relative::InvalidTimeError pub struct bitcoin_units::locktime::relative::NumberOf512Seconds(_) pub struct bitcoin_units::locktime::relative::NumberOfBlocks(_) pub struct bitcoin_units::locktime::relative::TimeOverflowError +pub struct bitcoin_units::locktime::relative::error::DisabledLockTimeError(_) +pub struct bitcoin_units::locktime::relative::error::InvalidHeightError +pub struct bitcoin_units::locktime::relative::error::InvalidTimeError +pub struct bitcoin_units::locktime::relative::error::TimeOverflowError pub struct bitcoin_units::parse::PrefixedHexError(_) pub struct bitcoin_units::parse::UnprefixedHexError(_) +pub struct bitcoin_units::relative::DisabledLockTimeError(_) +pub struct bitcoin_units::relative::InvalidHeightError +pub struct bitcoin_units::relative::InvalidTimeError +pub struct bitcoin_units::relative::NumberOf512Seconds(_) +pub struct bitcoin_units::relative::NumberOfBlocks(_) +pub struct bitcoin_units::relative::TimeOverflowError +pub struct bitcoin_units::relative::error::DisabledLockTimeError(_) +pub struct bitcoin_units::relative::error::InvalidHeightError +pub struct bitcoin_units::relative::error::InvalidTimeError +pub struct bitcoin_units::relative::error::TimeOverflowError +pub struct bitcoin_units::sequence::Sequence(pub u32) pub struct bitcoin_units::time::BlockTime(_) pub struct bitcoin_units::weight::Weight(_) -pub trait bitcoin_units::CheckedSum: bitcoin_units::sealed::Sealed -pub trait bitcoin_units::amount::serde::SerdeAmount: core::marker::Copy + core::marker::Sized -pub trait bitcoin_units::amount::serde::SerdeAmountForOpt: core::marker::Copy + core::marker::Sized + bitcoin_units::amount::serde::SerdeAmount pub trait bitcoin_units::parse::Integer: core::str::traits::FromStr + core::convert::TryFrom + core::marker::Sized + bitcoin_units::parse::sealed::Sealed pub type &bitcoin_units::Amount::Output = >>::Output pub type &bitcoin_units::Amount::Output = ::Output @@ -2188,17 +2512,22 @@ pub type bitcoin_units::block::BlockMtpInterval::Error = bitcoin_units::parse::P pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output pub type bitcoin_units::block::BlockMtpInterval::Output = bitcoin_units::block::BlockMtpInterval -pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::ParseHeightError -pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ConversionError -pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ParseHeightError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::ParseTimeError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ConversionError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::error::ParseHeightError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::error::ConversionError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::error::ParseHeightError +pub type bitcoin_units::locktime::absolute::LockTime::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::absolute::LockTime::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::error::ParseTimeError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::error::ConversionError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::error::ParseTimeError +pub type bitcoin_units::locktime::relative::LockTime::Error = bitcoin_units::locktime::relative::error::DisabledLockTimeError pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Err = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Error = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Err = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::block::TooBigForRelativeHeightError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::sequence::Sequence::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::sequence::Sequence::Error = bitcoin_units::parse::ParseIntError pub type i64::Output = >>::Output pub type i64::Output = >::Output pub type i64::Output = bitcoin_units::NumOpResult diff --git a/api/units/alloc-only.txt b/api/units/alloc-only.txt index 55fd6ef2b5..8bcfde5461 100644 --- a/api/units/alloc-only.txt +++ b/api/units/alloc-only.txt @@ -2,10 +2,13 @@ #[non_exhaustive] pub enum bitcoin_units::amount::Denomination #[non_exhaustive] pub enum bitcoin_units::amount::ParseDenominationError #[non_exhaustive] pub struct bitcoin_units::NumOpError(_) +#[non_exhaustive] pub struct bitcoin_units::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::absolute::error::ConversionError #[non_exhaustive] pub struct bitcoin_units::amount::MissingDenominationError #[non_exhaustive] pub struct bitcoin_units::amount::PossiblyConfusingDenominationError(_) #[non_exhaustive] pub struct bitcoin_units::amount::UnknownDenominationError(_) #[non_exhaustive] pub struct bitcoin_units::locktime::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::locktime::absolute::error::ConversionError #[non_exhaustive] pub struct bitcoin_units::parse::ParseIntError impl bitcoin_units::Amount impl bitcoin_units::BlockTime @@ -22,9 +25,14 @@ impl bitcoin_units::block::BlockHeightInterval impl bitcoin_units::block::BlockMtp impl bitcoin_units::block::BlockMtpInterval impl bitcoin_units::locktime::absolute::Height +impl bitcoin_units::locktime::absolute::LockTime impl bitcoin_units::locktime::absolute::MedianTimePast +impl bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl bitcoin_units::locktime::relative::LockTime impl bitcoin_units::locktime::relative::NumberOf512Seconds impl bitcoin_units::locktime::relative::NumberOfBlocks +impl bitcoin_units::locktime::relative::error::DisabledLockTimeError impl bitcoin_units::parse::Integer for i128 impl bitcoin_units::parse::Integer for i16 impl bitcoin_units::parse::Integer for i32 @@ -35,6 +43,7 @@ impl bitcoin_units::parse::Integer for u16 impl bitcoin_units::parse::Integer for u32 impl bitcoin_units::parse::Integer for u64 impl bitcoin_units::parse::Integer for u8 +impl bitcoin_units::sequence::Sequence impl core::clone::Clone for bitcoin_units::Amount impl core::clone::Clone for bitcoin_units::BlockTime impl core::clone::Clone for bitcoin_units::FeeRate @@ -60,19 +69,28 @@ impl core::clone::Clone for bitcoin_units::block::BlockHeightInterval impl core::clone::Clone for bitcoin_units::block::BlockMtp impl core::clone::Clone for bitcoin_units::block::BlockMtpInterval impl core::clone::Clone for bitcoin_units::block::TooBigForRelativeHeightError -impl core::clone::Clone for bitcoin_units::locktime::absolute::ConversionError impl core::clone::Clone for bitcoin_units::locktime::absolute::Height +impl core::clone::Clone for bitcoin_units::locktime::absolute::LockTime impl core::clone::Clone for bitcoin_units::locktime::absolute::MedianTimePast -impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseHeightError -impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseTimeError -impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidHeightError -impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ConversionError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::LockTime impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::clone::Clone for bitcoin_units::locktime::relative::TimeOverflowError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::clone::Clone for bitcoin_units::parse::ParseIntError impl core::clone::Clone for bitcoin_units::parse::PrefixedHexError impl core::clone::Clone for bitcoin_units::parse::UnprefixedHexError +impl core::clone::Clone for bitcoin_units::sequence::Sequence impl core::cmp::Eq for bitcoin_units::Amount impl core::cmp::Eq for bitcoin_units::BlockTime impl core::cmp::Eq for bitcoin_units::FeeRate @@ -97,19 +115,28 @@ impl core::cmp::Eq for bitcoin_units::block::BlockHeightInterval impl core::cmp::Eq for bitcoin_units::block::BlockMtp impl core::cmp::Eq for bitcoin_units::block::BlockMtpInterval impl core::cmp::Eq for bitcoin_units::block::TooBigForRelativeHeightError -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ConversionError impl core::cmp::Eq for bitcoin_units::locktime::absolute::Height +impl core::cmp::Eq for bitcoin_units::locktime::absolute::LockTime impl core::cmp::Eq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::LockTime impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::cmp::Eq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::cmp::Eq for bitcoin_units::parse::ParseIntError impl core::cmp::Eq for bitcoin_units::parse::PrefixedHexError impl core::cmp::Eq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Eq for bitcoin_units::sequence::Sequence impl core::cmp::Ord for bitcoin_units::Amount impl core::cmp::Ord for bitcoin_units::BlockTime impl core::cmp::Ord for bitcoin_units::FeeRate @@ -123,6 +150,7 @@ impl core::cmp::Ord for bitcoin_units::locktime::absolute::Height impl core::cmp::Ord for bitcoin_units::locktime::absolute::MedianTimePast impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::Ord for bitcoin_units::sequence::Sequence impl core::cmp::PartialEq for bitcoin_units::Amount impl core::cmp::PartialEq for bitcoin_units::BlockTime impl core::cmp::PartialEq for bitcoin_units::FeeRate @@ -147,19 +175,28 @@ impl core::cmp::PartialEq for bitcoin_units::block::BlockHeightInterval impl core::cmp::PartialEq for bitcoin_units::block::BlockMtp impl core::cmp::PartialEq for bitcoin_units::block::BlockMtpInterval impl core::cmp::PartialEq for bitcoin_units::block::TooBigForRelativeHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ConversionError impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::LockTime impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::LockTime impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::cmp::PartialEq for bitcoin_units::parse::ParseIntError impl core::cmp::PartialEq for bitcoin_units::parse::PrefixedHexError impl core::cmp::PartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::PartialEq for bitcoin_units::sequence::Sequence impl core::cmp::PartialOrd for bitcoin_units::Amount impl core::cmp::PartialOrd for bitcoin_units::BlockTime impl core::cmp::PartialOrd for bitcoin_units::FeeRate @@ -173,6 +210,7 @@ impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::Height impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::MedianTimePast impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialOrd for bitcoin_units::sequence::Sequence impl core::convert::AsRef for bitcoin_units::parse::ParseIntError impl core::convert::From<&bitcoin_units::Amount> for bitcoin_units::NumOpResult impl core::convert::From<&bitcoin_units::SignedAmount> for bitcoin_units::NumOpResult @@ -198,12 +236,18 @@ impl core::convert::From for u32 impl core::convert::From for u32 impl core::convert::From for u32 impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::locktime::absolute::LockTime impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::locktime::absolute::LockTime +impl core::convert::From for bitcoin_units::sequence::Sequence impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::From for bitcoin_units::locktime::relative::LockTime impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::locktime::relative::LockTime impl core::convert::From for bitcoin_units::parse::PrefixedHexError impl core::convert::From for bitcoin_units::parse::UnprefixedHexError impl core::convert::From for core::num::error::ParseIntError +impl core::convert::From for u32 impl core::convert::From for bitcoin_units::amount::ParseAmountError impl core::convert::From for bitcoin_units::amount::ParseDenominationError impl core::convert::From for bitcoin_units::amount::ParseError @@ -221,37 +265,45 @@ impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtp impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom<&str> for bitcoin_units::sequence::Sequence impl core::convert::TryFrom> for bitcoin_units::Weight impl core::convert::TryFrom> for bitcoin_units::block::BlockHeight impl core::convert::TryFrom> for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom> for bitcoin_units::block::BlockMtp impl core::convert::TryFrom> for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom> for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom> for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom> for bitcoin_units::sequence::Sequence impl core::convert::TryFrom for bitcoin_units::Weight impl core::convert::TryFrom for bitcoin_units::block::BlockHeight impl core::convert::TryFrom for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom for bitcoin_units::block::BlockMtp impl core::convert::TryFrom for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::convert::TryFrom for bitcoin_units::sequence::Sequence impl core::convert::TryFrom for bitcoin_units::Amount impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom for bitcoin_units::locktime::relative::LockTime impl core::default::Default for bitcoin_units::Amount impl core::default::Default for bitcoin_units::SignedAmount impl core::default::Default for bitcoin_units::block::BlockHeightInterval impl core::default::Default for bitcoin_units::block::BlockMtpInterval impl core::default::Default for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::default::Default for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::default::Default for bitcoin_units::sequence::Sequence impl core::fmt::Debug for bitcoin_units::Amount impl core::fmt::Debug for bitcoin_units::BlockTime impl core::fmt::Debug for bitcoin_units::FeeRate @@ -277,19 +329,28 @@ impl core::fmt::Debug for bitcoin_units::block::BlockHeightInterval impl core::fmt::Debug for bitcoin_units::block::BlockMtp impl core::fmt::Debug for bitcoin_units::block::BlockMtpInterval impl core::fmt::Debug for bitcoin_units::block::TooBigForRelativeHeightError -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ConversionError impl core::fmt::Debug for bitcoin_units::locktime::absolute::Height +impl core::fmt::Debug for bitcoin_units::locktime::absolute::LockTime impl core::fmt::Debug for bitcoin_units::locktime::absolute::MedianTimePast -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseHeightError -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseTimeError -impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidHeightError -impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ConversionError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::LockTime impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::fmt::Debug for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::fmt::Debug for bitcoin_units::parse::ParseIntError impl core::fmt::Debug for bitcoin_units::parse::PrefixedHexError impl core::fmt::Debug for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Debug for bitcoin_units::sequence::Sequence impl core::fmt::Display for bitcoin_units::Amount impl core::fmt::Display for bitcoin_units::MathOp impl core::fmt::Display for bitcoin_units::NumOpError @@ -312,19 +373,30 @@ impl core::fmt::Display for bitcoin_units::block::BlockHeightInterval impl core::fmt::Display for bitcoin_units::block::BlockMtp impl core::fmt::Display for bitcoin_units::block::BlockMtpInterval impl core::fmt::Display for bitcoin_units::block::TooBigForRelativeHeightError -impl core::fmt::Display for bitcoin_units::locktime::absolute::ConversionError impl core::fmt::Display for bitcoin_units::locktime::absolute::Height +impl core::fmt::Display for bitcoin_units::locktime::absolute::LockTime impl core::fmt::Display for bitcoin_units::locktime::absolute::MedianTimePast -impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseHeightError -impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseTimeError -impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidHeightError -impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ConversionError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::LockTime impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::fmt::Display for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::fmt::Display for bitcoin_units::parse::ParseIntError impl core::fmt::Display for bitcoin_units::parse::PrefixedHexError impl core::fmt::Display for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Display for bitcoin_units::sequence::Sequence +impl core::fmt::LowerHex for bitcoin_units::sequence::Sequence +impl core::fmt::UpperHex for bitcoin_units::sequence::Sequence impl core::hash::Hash for bitcoin_units::Amount impl core::hash::Hash for bitcoin_units::BlockTime impl core::hash::Hash for bitcoin_units::FeeRate @@ -336,9 +408,12 @@ impl core::hash::Hash for bitcoin_units::block::BlockHeightInterval impl core::hash::Hash for bitcoin_units::block::BlockMtp impl core::hash::Hash for bitcoin_units::block::BlockMtpInterval impl core::hash::Hash for bitcoin_units::locktime::absolute::Height +impl core::hash::Hash for bitcoin_units::locktime::absolute::LockTime impl core::hash::Hash for bitcoin_units::locktime::absolute::MedianTimePast +impl core::hash::Hash for bitcoin_units::locktime::relative::LockTime impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::hash::Hash for bitcoin_units::sequence::Sequence impl core::iter::traits::accum::Sum for bitcoin_units::FeeRate impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult @@ -359,9 +434,12 @@ impl core::marker::Copy for bitcoin_units::block::BlockHeightInterval impl core::marker::Copy for bitcoin_units::block::BlockMtp impl core::marker::Copy for bitcoin_units::block::BlockMtpInterval impl core::marker::Copy for bitcoin_units::locktime::absolute::Height +impl core::marker::Copy for bitcoin_units::locktime::absolute::LockTime impl core::marker::Copy for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Copy for bitcoin_units::locktime::relative::LockTime impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Copy for bitcoin_units::sequence::Sequence impl core::marker::Freeze for bitcoin_units::Amount impl core::marker::Freeze for bitcoin_units::BlockTime impl core::marker::Freeze for bitcoin_units::FeeRate @@ -387,19 +465,28 @@ impl core::marker::Freeze for bitcoin_units::block::BlockHeightInterval impl core::marker::Freeze for bitcoin_units::block::BlockMtp impl core::marker::Freeze for bitcoin_units::block::BlockMtpInterval impl core::marker::Freeze for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Freeze for bitcoin_units::locktime::absolute::Height +impl core::marker::Freeze for bitcoin_units::locktime::absolute::LockTime impl core::marker::Freeze for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::LockTime impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Freeze for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Freeze for bitcoin_units::parse::ParseIntError impl core::marker::Freeze for bitcoin_units::parse::PrefixedHexError impl core::marker::Freeze for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Freeze for bitcoin_units::sequence::Sequence impl core::marker::Send for bitcoin_units::Amount impl core::marker::Send for bitcoin_units::BlockTime impl core::marker::Send for bitcoin_units::FeeRate @@ -425,19 +512,28 @@ impl core::marker::Send for bitcoin_units::block::BlockHeightInterval impl core::marker::Send for bitcoin_units::block::BlockMtp impl core::marker::Send for bitcoin_units::block::BlockMtpInterval impl core::marker::Send for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Send for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Send for bitcoin_units::locktime::absolute::Height +impl core::marker::Send for bitcoin_units::locktime::absolute::LockTime impl core::marker::Send for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Send for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Send for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Send for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Send for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::LockTime impl core::marker::Send for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Send for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Send for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Send for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Send for bitcoin_units::parse::ParseIntError impl core::marker::Send for bitcoin_units::parse::PrefixedHexError impl core::marker::Send for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Send for bitcoin_units::sequence::Sequence impl core::marker::StructuralPartialEq for bitcoin_units::Amount impl core::marker::StructuralPartialEq for bitcoin_units::BlockTime impl core::marker::StructuralPartialEq for bitcoin_units::FeeRate @@ -462,19 +558,28 @@ impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeightInte impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtp impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtpInterval impl core::marker::StructuralPartialEq for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ConversionError impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::Height +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::LockTime impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::LockTime impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::StructuralPartialEq for bitcoin_units::parse::ParseIntError impl core::marker::StructuralPartialEq for bitcoin_units::parse::PrefixedHexError impl core::marker::StructuralPartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::sequence::Sequence impl core::marker::Sync for bitcoin_units::Amount impl core::marker::Sync for bitcoin_units::BlockTime impl core::marker::Sync for bitcoin_units::FeeRate @@ -500,19 +605,28 @@ impl core::marker::Sync for bitcoin_units::block::BlockHeightInterval impl core::marker::Sync for bitcoin_units::block::BlockMtp impl core::marker::Sync for bitcoin_units::block::BlockMtpInterval impl core::marker::Sync for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Sync for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Sync for bitcoin_units::locktime::absolute::Height +impl core::marker::Sync for bitcoin_units::locktime::absolute::LockTime impl core::marker::Sync for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::LockTime impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Sync for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Sync for bitcoin_units::parse::ParseIntError impl core::marker::Sync for bitcoin_units::parse::PrefixedHexError impl core::marker::Sync for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Sync for bitcoin_units::sequence::Sequence impl core::marker::Unpin for bitcoin_units::Amount impl core::marker::Unpin for bitcoin_units::BlockTime impl core::marker::Unpin for bitcoin_units::FeeRate @@ -538,19 +652,28 @@ impl core::marker::Unpin for bitcoin_units::block::BlockHeightInterval impl core::marker::Unpin for bitcoin_units::block::BlockMtp impl core::marker::Unpin for bitcoin_units::block::BlockMtpInterval impl core::marker::Unpin for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Unpin for bitcoin_units::locktime::absolute::Height +impl core::marker::Unpin for bitcoin_units::locktime::absolute::LockTime impl core::marker::Unpin for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::LockTime impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Unpin for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Unpin for bitcoin_units::parse::ParseIntError impl core::marker::Unpin for bitcoin_units::parse::PrefixedHexError impl core::marker::Unpin for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Unpin for bitcoin_units::sequence::Sequence impl core::ops::arith::Add for bitcoin_units::Amount impl core::ops::arith::Add for bitcoin_units::FeeRate impl core::ops::arith::Add for bitcoin_units::SignedAmount @@ -802,19 +925,28 @@ impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeig impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtp impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtpInterval impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ConversionError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::LockTime impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ConversionError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::LockTime impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::ParseIntError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::PrefixedHexError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::sequence::Sequence impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Amount impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::BlockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::FeeRate @@ -840,19 +972,28 @@ impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeightI impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtp impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtpInterval impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ConversionError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::LockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ConversionError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::LockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::ParseIntError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::PrefixedHexError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::sequence::Sequence impl core::str::traits::FromStr for bitcoin_units::Amount impl core::str::traits::FromStr for bitcoin_units::SignedAmount impl core::str::traits::FromStr for bitcoin_units::Weight @@ -862,9 +1003,11 @@ impl core::str::traits::FromStr for bitcoin_units::block::BlockHeightInterval impl core::str::traits::FromStr for bitcoin_units::block::BlockMtp impl core::str::traits::FromStr for bitcoin_units::block::BlockMtpInterval impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::Height +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::LockTime impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::MedianTimePast impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::str::traits::FromStr for bitcoin_units::sequence::Sequence impl<'a, T> core::ops::arith::Add<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add, Output = bitcoin_units::NumOpResult> impl<'a, T> core::ops::arith::Add<&'a bitcoin_units::NumOpResult> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Add> impl<'a, T> core::ops::arith::Sub<&'a T> for &bitcoin_units::NumOpResult where T: core::marker::Copy + core::ops::arith::Sub> @@ -947,9 +1090,6 @@ impl core::cmp::PartialEq for bitcoin_units::NumOpResul impl bitcoin_units::NumOpResult impl core::fmt::Debug for bitcoin_units::NumOpResult impl core::marker::Copy for bitcoin_units::NumOpResult -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator impl bitcoin_units::NumOpResult impl core::marker::Freeze for bitcoin_units::NumOpResult where T: core::marker::Freeze impl core::marker::Send for bitcoin_units::NumOpResult where T: core::marker::Send @@ -978,6 +1118,8 @@ pub bitcoin_units::MathOp::Rem pub bitcoin_units::MathOp::Sub pub bitcoin_units::NumOpResult::Error(bitcoin_units::NumOpError) pub bitcoin_units::NumOpResult::Valid(T) +pub bitcoin_units::absolute::LockTime::Blocks(bitcoin_units::locktime::absolute::Height) +pub bitcoin_units::absolute::LockTime::Seconds(bitcoin_units::locktime::absolute::MedianTimePast) pub bitcoin_units::amount::Denomination::Bit pub bitcoin_units::amount::Denomination::Bitcoin pub bitcoin_units::amount::Denomination::CentiBitcoin @@ -986,6 +1128,36 @@ pub bitcoin_units::amount::Denomination::MilliBitcoin pub bitcoin_units::amount::Denomination::Satoshi pub bitcoin_units::amount::ParseDenominationError::PossiblyConfusing(bitcoin_units::amount::PossiblyConfusingDenominationError) pub bitcoin_units::amount::ParseDenominationError::Unknown(bitcoin_units::amount::UnknownDenominationError) +pub bitcoin_units::locktime::absolute::LockTime::Blocks(bitcoin_units::locktime::absolute::Height) +pub bitcoin_units::locktime::absolute::LockTime::Seconds(bitcoin_units::locktime::absolute::MedianTimePast) +pub bitcoin_units::locktime::relative::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::LockTime::Blocks(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::LockTime::Time(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::LockTime::Blocks(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::LockTime::Time(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::error::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::error::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::error::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::error::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::error::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::error::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) pub const bitcoin_units::Amount::FIFTY_BTC: Self pub const bitcoin_units::Amount::MAX: Self pub const bitcoin_units::Amount::MAX_MONEY: Self @@ -1012,6 +1184,7 @@ pub const bitcoin_units::Weight::MIN: bitcoin_units::Weight pub const bitcoin_units::Weight::MIN_TRANSACTION: bitcoin_units::Weight pub const bitcoin_units::Weight::WITNESS_SCALE_FACTOR: u64 pub const bitcoin_units::Weight::ZERO: bitcoin_units::Weight +pub const bitcoin_units::absolute::LOCK_TIME_THRESHOLD: u32 pub const bitcoin_units::amount::Denomination::BTC: Self pub const bitcoin_units::amount::Denomination::SAT: Self pub const bitcoin_units::block::BlockHeight::MAX: Self @@ -1030,14 +1203,25 @@ pub const bitcoin_units::locktime::absolute::Height::MAX: Self pub const bitcoin_units::locktime::absolute::Height::MIN: Self pub const bitcoin_units::locktime::absolute::Height::ZERO: Self pub const bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD: u32 +pub const bitcoin_units::locktime::absolute::LockTime::SIZE: usize +pub const bitcoin_units::locktime::absolute::LockTime::ZERO: bitcoin_units::locktime::absolute::LockTime pub const bitcoin_units::locktime::absolute::MedianTimePast::MAX: Self pub const bitcoin_units::locktime::absolute::MedianTimePast::MIN: Self +pub const bitcoin_units::locktime::relative::LockTime::SIZE: usize +pub const bitcoin_units::locktime::relative::LockTime::ZERO: bitcoin_units::locktime::relative::LockTime pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MAX: Self pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MIN: Self pub const bitcoin_units::locktime::relative::NumberOf512Seconds::ZERO: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::MAX: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::MIN: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::ZERO: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_LOCKTIME_AND_RBF: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_LOCKTIME_NO_RBF: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_RBF_NO_LOCKTIME: Self +pub const bitcoin_units::sequence::Sequence::FINAL: Self +pub const bitcoin_units::sequence::Sequence::MAX: Self +pub const bitcoin_units::sequence::Sequence::SIZE: usize +pub const bitcoin_units::sequence::Sequence::ZERO: Self pub const bitcoin_units::weight::WITNESS_SCALE_FACTOR: usize pub const fn bitcoin_units::Amount::checked_add(self, rhs: Self) -> core::option::Option pub const fn bitcoin_units::Amount::checked_div(self, rhs: u64) -> core::option::Option @@ -1100,6 +1284,8 @@ pub const fn bitcoin_units::Weight::to_kwu_floor(self) -> u64 pub const fn bitcoin_units::Weight::to_vbytes_ceil(self) -> u64 pub const fn bitcoin_units::Weight::to_vbytes_floor(self) -> u64 pub const fn bitcoin_units::Weight::to_wu(self) -> u64 +pub const fn bitcoin_units::absolute::is_block_height(n: u32) -> bool +pub const fn bitcoin_units::absolute::is_block_time(n: u32) -> bool pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockHeightInterval::from_u32(inner: u32) -> Self @@ -1107,18 +1293,28 @@ pub const fn bitcoin_units::block::BlockHeightInterval::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockMtp::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockMtp::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockMtpInterval::from_u32(inner: u32) -> Self -pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result -pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result pub const fn bitcoin_units::block::BlockMtpInterval::to_u32(self) -> u32 -pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result pub const fn bitcoin_units::locktime::absolute::Height::to_u32(self) -> u32 -pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::LockTime::is_block_height(self) -> bool +pub const fn bitcoin_units::locktime::absolute::LockTime::is_block_time(self) -> bool +pub const fn bitcoin_units::locktime::absolute::LockTime::is_same_unit(self, other: bitcoin_units::locktime::absolute::LockTime) -> bool +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result pub const fn bitcoin_units::locktime::absolute::MedianTimePast::to_u32(self) -> u32 pub const fn bitcoin_units::locktime::absolute::is_block_height(n: u32) -> bool pub const fn bitcoin_units::locktime::absolute::is_block_time(n: u32) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::from_512_second_intervals(intervals: u16) -> Self +pub const fn bitcoin_units::locktime::relative::LockTime::from_height(n: u16) -> Self +pub const fn bitcoin_units::locktime::relative::LockTime::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::LockTime::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::LockTime::is_block_height(self) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::is_block_time(self) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::is_same_unit(self, other: bitcoin_units::locktime::relative::LockTime) -> bool pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_512_second_intervals(intervals: u16) -> Self -pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result -pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_512_second_intervals(self) -> u16 pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_consensus_u32(self) -> u32 pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_seconds(self) -> u32 @@ -1126,6 +1322,22 @@ pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::from_height(bloc pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_consensus_u32(self) -> u32 pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_height(self) -> u16 pub enum bitcoin_units::NumOpResult +pub enum bitcoin_units::absolute::LockTime +pub enum bitcoin_units::locktime::absolute::LockTime +pub enum bitcoin_units::locktime::relative::IsSatisfiedByError +pub enum bitcoin_units::locktime::relative::IsSatisfiedByHeightError +pub enum bitcoin_units::locktime::relative::IsSatisfiedByTimeError +pub enum bitcoin_units::locktime::relative::LockTime +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByError +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +pub enum bitcoin_units::relative::IsSatisfiedByError +pub enum bitcoin_units::relative::IsSatisfiedByHeightError +pub enum bitcoin_units::relative::IsSatisfiedByTimeError +pub enum bitcoin_units::relative::LockTime +pub enum bitcoin_units::relative::error::IsSatisfiedByError +pub enum bitcoin_units::relative::error::IsSatisfiedByHeightError +pub enum bitcoin_units::relative::error::IsSatisfiedByTimeError pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1266,9 +1478,6 @@ pub fn &u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output -pub fn T::checked_sum(self) -> core::option::Option -pub fn T::checked_sum(self) -> core::option::Option -pub fn T::checked_sum(self) -> core::option::Option pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1323,7 +1532,6 @@ pub fn bitcoin_units::BlockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> pub fn bitcoin_units::BlockTime::from(t: u32) -> Self pub fn bitcoin_units::BlockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::BlockTime::partial_cmp(&self, other: &bitcoin_units::BlockTime) -> core::option::Option -pub fn bitcoin_units::CheckedSum::checked_sum(self) -> core::option::Option pub fn bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output pub fn bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: &bitcoin_units::FeeRate) @@ -1666,14 +1874,11 @@ pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: alloc::string::String pub fn bitcoin_units::block::TooBigForRelativeHeightError::clone(&self) -> bitcoin_units::block::TooBigForRelativeHeightError pub fn bitcoin_units::block::TooBigForRelativeHeightError::eq(&self, other: &bitcoin_units::block::TooBigForRelativeHeightError) -> bool pub fn bitcoin_units::block::TooBigForRelativeHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::ConversionError -pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool -pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering pub fn bitcoin_units::locktime::absolute::Height::eq(&self, other: &bitcoin_units::locktime::absolute::Height) -> bool pub fn bitcoin_units::locktime::absolute::Height::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::locktime::absolute::Height::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height) -> bool @@ -1682,32 +1887,75 @@ pub fn bitcoin_units::locktime::absolute::Height::try_from(h: bitcoin_units::blo pub fn bitcoin_units::locktime::absolute::Height::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::try_from(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::clone(&self) -> bitcoin_units::locktime::absolute::LockTime +pub fn bitcoin_units::locktime::absolute::LockTime::eq(&self, other: &bitcoin_units::locktime::absolute::LockTime) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from(h: bitcoin_units::locktime::absolute::Height) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from(t: bitcoin_units::locktime::absolute::MedianTimePast) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from_consensus(n: u32) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from_height(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_mtp(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_unprefixed_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::LockTime::is_implied_by(self, other: bitcoin_units::locktime::absolute::LockTime) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height, mtp: bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by_height(self, height: bitcoin_units::locktime::absolute::Height) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by_time(self, mtp: bitcoin_units::locktime::absolute::MedianTimePast) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: alloc::string::String) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::clone(&self) -> bitcoin_units::locktime::absolute::MedianTimePast pub fn bitcoin_units::locktime::absolute::MedianTimePast::cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::cmp::Ordering pub fn bitcoin_units::locktime::absolute::MedianTimePast::eq(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> bool pub fn bitcoin_units::locktime::absolute::MedianTimePast::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::locktime::absolute::MedianTimePast::is_satisfied_by(self, time: bitcoin_units::locktime::absolute::MedianTimePast) -> bool -pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::option::Option pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(h: bitcoin_units::block::BlockMtp) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: alloc::string::String) -> core::result::Result -pub fn bitcoin_units::locktime::absolute::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::ParseHeightError -pub fn bitcoin_units::locktime::absolute::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseHeightError) -> bool -pub fn bitcoin_units::locktime::absolute::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::ParseTimeError -pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool -pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::relative::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::InvalidHeightError -pub fn bitcoin_units::locktime::relative::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidHeightError) -> bool -pub fn bitcoin_units::locktime::relative::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::relative::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::InvalidTimeError -pub fn bitcoin_units::locktime::relative::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidTimeError) -> bool -pub fn bitcoin_units::locktime::relative::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::error::ConversionError +pub fn bitcoin_units::locktime::absolute::error::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ConversionError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::clone(&self) -> bitcoin_units::locktime::absolute::error::IncompatibleHeightError +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::error::IncompatibleHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::incompatible(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::lock(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::clone(&self) -> bitcoin_units::locktime::absolute::error::IncompatibleTimeError +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::error::IncompatibleTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::incompatible(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::lock(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::error::ParseHeightError +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ParseHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::error::ParseTimeError +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ParseTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::LockTime::clone(&self) -> bitcoin_units::locktime::relative::LockTime +pub fn bitcoin_units::locktime::relative::LockTime::eq(&self, other: &bitcoin_units::locktime::relative::LockTime) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::LockTime::from(h: bitcoin_units::locktime::relative::NumberOfBlocks) -> Self +pub fn bitcoin_units::locktime::relative::LockTime::from(t: bitcoin_units::locktime::relative::NumberOf512Seconds) -> Self +pub fn bitcoin_units::locktime::relative::LockTime::from_consensus(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::from_sequence(n: bitcoin_units::sequence::Sequence) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::LockTime::is_implied_by(self, other: bitcoin_units::locktime::relative::LockTime) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::is_implied_by_sequence(self, other: bitcoin_units::sequence::Sequence) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by(self, chain_tip_height: bitcoin_units::block::BlockHeight, chain_tip_mtp: bitcoin_units::block::BlockMtp, utxo_mined_at_height: bitcoin_units::block::BlockHeight, utxo_mined_at_mtp: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by_height(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by_time(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::locktime::relative::LockTime::to_sequence(self) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::locktime::relative::LockTime::try_from(seq: bitcoin_units::sequence::Sequence) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::clone(&self) -> bitcoin_units::locktime::relative::NumberOf512Seconds pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::cmp::Ordering pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::default() -> bitcoin_units::locktime::relative::NumberOf512Seconds @@ -1715,7 +1963,7 @@ pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::eq(&self, other: & pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::hash<__H: core::hash::Hasher>(&self, state: &mut __H) -pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::option::Option pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: alloc::boxed::Box) -> core::result::Result @@ -1728,15 +1976,34 @@ pub fn bitcoin_units::locktime::relative::NumberOfBlocks::fmt(&self, f: &mut cor pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from(value: u16) -> Self pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::hash<__H: core::hash::Hasher>(&self, state: &mut __H) -pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::option::Option pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(h: bitcoin_units::block::BlockHeightInterval) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: alloc::string::String) -> core::result::Result -pub fn bitcoin_units::locktime::relative::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::TimeOverflowError -pub fn bitcoin_units::locktime::relative::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::TimeOverflowError) -> bool -pub fn bitcoin_units::locktime::relative::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::DisabledLockTimeError +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::disabled_locktime_value(&self) -> u32 +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::DisabledLockTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::error::InvalidHeightError +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::error::InvalidHeightError) -> bool +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::InvalidTimeError +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::InvalidTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::error::TimeOverflowError +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::error::TimeOverflowError) -> bool +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::parse::ParseIntError::as_ref(&self) -> &core::num::error::ParseIntError pub fn bitcoin_units::parse::ParseIntError::clone(&self) -> bitcoin_units::parse::ParseIntError pub fn bitcoin_units::parse::ParseIntError::eq(&self, other: &bitcoin_units::parse::ParseIntError) -> bool @@ -1764,6 +2031,34 @@ pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result pub fn bitcoin_units::parse::int_from_box(s: alloc::boxed::Box) -> core::result::Result pub fn bitcoin_units::parse::int_from_str(s: &str) -> core::result::Result pub fn bitcoin_units::parse::int_from_string(s: alloc::string::String) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::clone(&self) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::sequence::Sequence::cmp(&self, other: &bitcoin_units::sequence::Sequence) -> core::cmp::Ordering +pub fn bitcoin_units::sequence::Sequence::default() -> Self +pub fn bitcoin_units::sequence::Sequence::enables_absolute_lock_time(self) -> bool +pub fn bitcoin_units::sequence::Sequence::eq(&self, other: &bitcoin_units::sequence::Sequence) -> bool +pub fn bitcoin_units::sequence::Sequence::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::sequence::Sequence::from(lt: bitcoin_units::locktime::relative::LockTime) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::sequence::Sequence::from_512_second_intervals(intervals: u16) -> Self +pub fn bitcoin_units::sequence::Sequence::from_consensus(n: u32) -> Self +pub fn bitcoin_units::sequence::Sequence::from_height(height: u16) -> Self +pub fn bitcoin_units::sequence::Sequence::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_seconds_ceil(seconds: u32) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_seconds_floor(seconds: u32) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_unprefixed_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::sequence::Sequence::is_final(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_height_locked(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_rbf(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_relative_lock_time(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_time_locked(self) -> bool +pub fn bitcoin_units::sequence::Sequence::partial_cmp(&self, other: &bitcoin_units::sequence::Sequence) -> core::option::Option +pub fn bitcoin_units::sequence::Sequence::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::sequence::Sequence::to_hex(self) -> alloc::string::String +pub fn bitcoin_units::sequence::Sequence::to_relative_lock_time(self) -> core::option::Option +pub fn bitcoin_units::sequence::Sequence::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::try_from(s: alloc::boxed::Box) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::try_from(s: alloc::string::String) -> core::result::Result pub fn core::num::error::ParseIntError::from(value: bitcoin_units::parse::ParseIntError) -> Self pub fn i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output @@ -1773,6 +2068,7 @@ pub fn u32::from(height: bitcoin_units::block::BlockHeight) -> Self pub fn u32::from(height: bitcoin_units::block::BlockHeightInterval) -> Self pub fn u32::from(height: bitcoin_units::block::BlockMtp) -> Self pub fn u32::from(height: bitcoin_units::block::BlockMtpInterval) -> Self +pub fn u32::from(sequence: bitcoin_units::sequence::Sequence) -> u32 pub fn u32::from(t: bitcoin_units::BlockTime) -> Self pub fn u64::from(value: bitcoin_units::Weight) -> Self pub fn u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output @@ -1782,14 +2078,21 @@ pub fn u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output pub fn u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output pub fn u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output pub mod bitcoin_units +pub mod bitcoin_units::absolute +pub mod bitcoin_units::absolute::error pub mod bitcoin_units::amount pub mod bitcoin_units::block pub mod bitcoin_units::fee pub mod bitcoin_units::fee_rate pub mod bitcoin_units::locktime pub mod bitcoin_units::locktime::absolute +pub mod bitcoin_units::locktime::absolute::error pub mod bitcoin_units::locktime::relative +pub mod bitcoin_units::locktime::relative::error pub mod bitcoin_units::parse +pub mod bitcoin_units::relative +pub mod bitcoin_units::relative::error +pub mod bitcoin_units::sequence pub mod bitcoin_units::time pub mod bitcoin_units::weight pub struct bitcoin_units::Amount(_) @@ -1799,8 +2102,19 @@ pub struct bitcoin_units::BlockMtp(_) pub struct bitcoin_units::BlockMtpInterval(_) pub struct bitcoin_units::BlockTime(_) pub struct bitcoin_units::FeeRate(_) +pub struct bitcoin_units::Sequence(pub u32) pub struct bitcoin_units::SignedAmount(_) pub struct bitcoin_units::Weight(_) +pub struct bitcoin_units::absolute::Height(_) +pub struct bitcoin_units::absolute::IncompatibleHeightError +pub struct bitcoin_units::absolute::IncompatibleTimeError +pub struct bitcoin_units::absolute::MedianTimePast(_) +pub struct bitcoin_units::absolute::ParseHeightError(_) +pub struct bitcoin_units::absolute::ParseTimeError(_) +pub struct bitcoin_units::absolute::error::IncompatibleHeightError +pub struct bitcoin_units::absolute::error::IncompatibleTimeError +pub struct bitcoin_units::absolute::error::ParseHeightError(_) +pub struct bitcoin_units::absolute::error::ParseTimeError(_) pub struct bitcoin_units::amount::Amount(_) pub struct bitcoin_units::amount::Display pub struct bitcoin_units::amount::InputTooLargeError @@ -1818,19 +2132,40 @@ pub struct bitcoin_units::block::BlockMtpInterval(_) pub struct bitcoin_units::block::TooBigForRelativeHeightError(_) pub struct bitcoin_units::fee_rate::FeeRate(_) pub struct bitcoin_units::locktime::absolute::Height(_) +pub struct bitcoin_units::locktime::absolute::IncompatibleHeightError +pub struct bitcoin_units::locktime::absolute::IncompatibleTimeError pub struct bitcoin_units::locktime::absolute::MedianTimePast(_) pub struct bitcoin_units::locktime::absolute::ParseHeightError(_) pub struct bitcoin_units::locktime::absolute::ParseTimeError(_) +pub struct bitcoin_units::locktime::absolute::error::IncompatibleHeightError +pub struct bitcoin_units::locktime::absolute::error::IncompatibleTimeError +pub struct bitcoin_units::locktime::absolute::error::ParseHeightError(_) +pub struct bitcoin_units::locktime::absolute::error::ParseTimeError(_) +pub struct bitcoin_units::locktime::relative::DisabledLockTimeError(_) pub struct bitcoin_units::locktime::relative::InvalidHeightError pub struct bitcoin_units::locktime::relative::InvalidTimeError pub struct bitcoin_units::locktime::relative::NumberOf512Seconds(_) pub struct bitcoin_units::locktime::relative::NumberOfBlocks(_) pub struct bitcoin_units::locktime::relative::TimeOverflowError +pub struct bitcoin_units::locktime::relative::error::DisabledLockTimeError(_) +pub struct bitcoin_units::locktime::relative::error::InvalidHeightError +pub struct bitcoin_units::locktime::relative::error::InvalidTimeError +pub struct bitcoin_units::locktime::relative::error::TimeOverflowError pub struct bitcoin_units::parse::PrefixedHexError(_) pub struct bitcoin_units::parse::UnprefixedHexError(_) +pub struct bitcoin_units::relative::DisabledLockTimeError(_) +pub struct bitcoin_units::relative::InvalidHeightError +pub struct bitcoin_units::relative::InvalidTimeError +pub struct bitcoin_units::relative::NumberOf512Seconds(_) +pub struct bitcoin_units::relative::NumberOfBlocks(_) +pub struct bitcoin_units::relative::TimeOverflowError +pub struct bitcoin_units::relative::error::DisabledLockTimeError(_) +pub struct bitcoin_units::relative::error::InvalidHeightError +pub struct bitcoin_units::relative::error::InvalidTimeError +pub struct bitcoin_units::relative::error::TimeOverflowError +pub struct bitcoin_units::sequence::Sequence(pub u32) pub struct bitcoin_units::time::BlockTime(_) pub struct bitcoin_units::weight::Weight(_) -pub trait bitcoin_units::CheckedSum: bitcoin_units::sealed::Sealed pub trait bitcoin_units::parse::Integer: core::str::traits::FromStr + core::convert::TryFrom + core::marker::Sized + bitcoin_units::parse::sealed::Sealed pub type &bitcoin_units::Amount::Output = >>::Output pub type &bitcoin_units::Amount::Output = ::Output @@ -2007,17 +2342,22 @@ pub type bitcoin_units::block::BlockMtpInterval::Error = bitcoin_units::parse::P pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output pub type bitcoin_units::block::BlockMtpInterval::Output = bitcoin_units::block::BlockMtpInterval -pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::ParseHeightError -pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ConversionError -pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ParseHeightError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::ParseTimeError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ConversionError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::error::ParseHeightError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::error::ConversionError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::error::ParseHeightError +pub type bitcoin_units::locktime::absolute::LockTime::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::absolute::LockTime::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::error::ParseTimeError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::error::ConversionError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::error::ParseTimeError +pub type bitcoin_units::locktime::relative::LockTime::Error = bitcoin_units::locktime::relative::error::DisabledLockTimeError pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Err = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Error = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Err = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::block::TooBigForRelativeHeightError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::sequence::Sequence::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::sequence::Sequence::Error = bitcoin_units::parse::ParseIntError pub type i64::Output = >>::Output pub type i64::Output = >::Output pub type i64::Output = bitcoin_units::NumOpResult diff --git a/api/units/no-features.txt b/api/units/no-features.txt index 483c305a5d..a7362c7bc6 100644 --- a/api/units/no-features.txt +++ b/api/units/no-features.txt @@ -2,10 +2,13 @@ #[non_exhaustive] pub enum bitcoin_units::amount::Denomination #[non_exhaustive] pub enum bitcoin_units::amount::ParseDenominationError #[non_exhaustive] pub struct bitcoin_units::NumOpError(_) +#[non_exhaustive] pub struct bitcoin_units::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::absolute::error::ConversionError #[non_exhaustive] pub struct bitcoin_units::amount::MissingDenominationError #[non_exhaustive] pub struct bitcoin_units::amount::PossiblyConfusingDenominationError(_) #[non_exhaustive] pub struct bitcoin_units::amount::UnknownDenominationError(_) #[non_exhaustive] pub struct bitcoin_units::locktime::absolute::ConversionError +#[non_exhaustive] pub struct bitcoin_units::locktime::absolute::error::ConversionError #[non_exhaustive] pub struct bitcoin_units::parse::ParseIntError impl bitcoin_units::Amount impl bitcoin_units::BlockTime @@ -22,9 +25,14 @@ impl bitcoin_units::block::BlockHeightInterval impl bitcoin_units::block::BlockMtp impl bitcoin_units::block::BlockMtpInterval impl bitcoin_units::locktime::absolute::Height +impl bitcoin_units::locktime::absolute::LockTime impl bitcoin_units::locktime::absolute::MedianTimePast +impl bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl bitcoin_units::locktime::relative::LockTime impl bitcoin_units::locktime::relative::NumberOf512Seconds impl bitcoin_units::locktime::relative::NumberOfBlocks +impl bitcoin_units::locktime::relative::error::DisabledLockTimeError impl bitcoin_units::parse::Integer for i128 impl bitcoin_units::parse::Integer for i16 impl bitcoin_units::parse::Integer for i32 @@ -35,6 +43,7 @@ impl bitcoin_units::parse::Integer for u16 impl bitcoin_units::parse::Integer for u32 impl bitcoin_units::parse::Integer for u64 impl bitcoin_units::parse::Integer for u8 +impl bitcoin_units::sequence::Sequence impl core::clone::Clone for bitcoin_units::Amount impl core::clone::Clone for bitcoin_units::BlockTime impl core::clone::Clone for bitcoin_units::FeeRate @@ -60,19 +69,28 @@ impl core::clone::Clone for bitcoin_units::block::BlockHeightInterval impl core::clone::Clone for bitcoin_units::block::BlockMtp impl core::clone::Clone for bitcoin_units::block::BlockMtpInterval impl core::clone::Clone for bitcoin_units::block::TooBigForRelativeHeightError -impl core::clone::Clone for bitcoin_units::locktime::absolute::ConversionError impl core::clone::Clone for bitcoin_units::locktime::absolute::Height +impl core::clone::Clone for bitcoin_units::locktime::absolute::LockTime impl core::clone::Clone for bitcoin_units::locktime::absolute::MedianTimePast -impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseHeightError -impl core::clone::Clone for bitcoin_units::locktime::absolute::ParseTimeError -impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidHeightError -impl core::clone::Clone for bitcoin_units::locktime::relative::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ConversionError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::clone::Clone for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::LockTime impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::clone::Clone for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::clone::Clone for bitcoin_units::locktime::relative::TimeOverflowError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::clone::Clone for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::clone::Clone for bitcoin_units::parse::ParseIntError impl core::clone::Clone for bitcoin_units::parse::PrefixedHexError impl core::clone::Clone for bitcoin_units::parse::UnprefixedHexError +impl core::clone::Clone for bitcoin_units::sequence::Sequence impl core::cmp::Eq for bitcoin_units::Amount impl core::cmp::Eq for bitcoin_units::BlockTime impl core::cmp::Eq for bitcoin_units::FeeRate @@ -97,19 +115,28 @@ impl core::cmp::Eq for bitcoin_units::block::BlockHeightInterval impl core::cmp::Eq for bitcoin_units::block::BlockMtp impl core::cmp::Eq for bitcoin_units::block::BlockMtpInterval impl core::cmp::Eq for bitcoin_units::block::TooBigForRelativeHeightError -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ConversionError impl core::cmp::Eq for bitcoin_units::locktime::absolute::Height +impl core::cmp::Eq for bitcoin_units::locktime::absolute::LockTime impl core::cmp::Eq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::cmp::Eq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::cmp::Eq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::cmp::Eq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::LockTime impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::Eq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::cmp::Eq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::cmp::Eq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::cmp::Eq for bitcoin_units::parse::ParseIntError impl core::cmp::Eq for bitcoin_units::parse::PrefixedHexError impl core::cmp::Eq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::Eq for bitcoin_units::sequence::Sequence impl core::cmp::Ord for bitcoin_units::Amount impl core::cmp::Ord for bitcoin_units::BlockTime impl core::cmp::Ord for bitcoin_units::FeeRate @@ -123,6 +150,7 @@ impl core::cmp::Ord for bitcoin_units::locktime::absolute::Height impl core::cmp::Ord for bitcoin_units::locktime::absolute::MedianTimePast impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::Ord for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::Ord for bitcoin_units::sequence::Sequence impl core::cmp::PartialEq for bitcoin_units::Amount impl core::cmp::PartialEq for bitcoin_units::BlockTime impl core::cmp::PartialEq for bitcoin_units::FeeRate @@ -147,19 +175,28 @@ impl core::cmp::PartialEq for bitcoin_units::block::BlockHeightInterval impl core::cmp::PartialEq for bitcoin_units::block::BlockMtp impl core::cmp::PartialEq for bitcoin_units::block::BlockMtpInterval impl core::cmp::PartialEq for bitcoin_units::block::TooBigForRelativeHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ConversionError impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::Height +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::LockTime impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::LockTime impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::PartialEq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::cmp::PartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::cmp::PartialEq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::cmp::PartialEq for bitcoin_units::parse::ParseIntError impl core::cmp::PartialEq for bitcoin_units::parse::PrefixedHexError impl core::cmp::PartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::cmp::PartialEq for bitcoin_units::sequence::Sequence impl core::cmp::PartialOrd for bitcoin_units::Amount impl core::cmp::PartialOrd for bitcoin_units::BlockTime impl core::cmp::PartialOrd for bitcoin_units::FeeRate @@ -173,6 +210,7 @@ impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::Height impl core::cmp::PartialOrd for bitcoin_units::locktime::absolute::MedianTimePast impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::cmp::PartialOrd for bitcoin_units::sequence::Sequence impl core::convert::AsRef for bitcoin_units::parse::ParseIntError impl core::convert::From<&bitcoin_units::Amount> for bitcoin_units::NumOpResult impl core::convert::From<&bitcoin_units::SignedAmount> for bitcoin_units::NumOpResult @@ -198,12 +236,18 @@ impl core::convert::From for u32 impl core::convert::From for u32 impl core::convert::From for u32 impl core::convert::From for bitcoin_units::block::BlockHeight +impl core::convert::From for bitcoin_units::locktime::absolute::LockTime impl core::convert::From for bitcoin_units::block::BlockMtp +impl core::convert::From for bitcoin_units::locktime::absolute::LockTime +impl core::convert::From for bitcoin_units::sequence::Sequence impl core::convert::From for bitcoin_units::block::BlockMtpInterval +impl core::convert::From for bitcoin_units::locktime::relative::LockTime impl core::convert::From for bitcoin_units::block::BlockHeightInterval +impl core::convert::From for bitcoin_units::locktime::relative::LockTime impl core::convert::From for bitcoin_units::parse::PrefixedHexError impl core::convert::From for bitcoin_units::parse::UnprefixedHexError impl core::convert::From for core::num::error::ParseIntError +impl core::convert::From for u32 impl core::convert::From for bitcoin_units::amount::ParseAmountError impl core::convert::From for bitcoin_units::amount::ParseDenominationError impl core::convert::From for bitcoin_units::amount::ParseError @@ -221,6 +265,7 @@ impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockHeightInterval impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtp impl core::convert::TryFrom<&str> for bitcoin_units::block::BlockMtpInterval impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Height +impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::LockTime impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::MedianTimePast impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::NumberOfBlocks @@ -228,12 +273,14 @@ impl core::convert::TryFrom for bitcoin_units::Amou impl core::convert::TryFrom for bitcoin_units::locktime::absolute::Height impl core::convert::TryFrom for bitcoin_units::locktime::relative::NumberOfBlocks impl core::convert::TryFrom for bitcoin_units::locktime::absolute::MedianTimePast +impl core::convert::TryFrom for bitcoin_units::locktime::relative::LockTime impl core::default::Default for bitcoin_units::Amount impl core::default::Default for bitcoin_units::SignedAmount impl core::default::Default for bitcoin_units::block::BlockHeightInterval impl core::default::Default for bitcoin_units::block::BlockMtpInterval impl core::default::Default for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::default::Default for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::default::Default for bitcoin_units::sequence::Sequence impl core::fmt::Debug for bitcoin_units::Amount impl core::fmt::Debug for bitcoin_units::BlockTime impl core::fmt::Debug for bitcoin_units::FeeRate @@ -259,19 +306,28 @@ impl core::fmt::Debug for bitcoin_units::block::BlockHeightInterval impl core::fmt::Debug for bitcoin_units::block::BlockMtp impl core::fmt::Debug for bitcoin_units::block::BlockMtpInterval impl core::fmt::Debug for bitcoin_units::block::TooBigForRelativeHeightError -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ConversionError impl core::fmt::Debug for bitcoin_units::locktime::absolute::Height +impl core::fmt::Debug for bitcoin_units::locktime::absolute::LockTime impl core::fmt::Debug for bitcoin_units::locktime::absolute::MedianTimePast -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseHeightError -impl core::fmt::Debug for bitcoin_units::locktime::absolute::ParseTimeError -impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidHeightError -impl core::fmt::Debug for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ConversionError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::fmt::Debug for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::LockTime impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::fmt::Debug for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::fmt::Debug for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::fmt::Debug for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::fmt::Debug for bitcoin_units::parse::ParseIntError impl core::fmt::Debug for bitcoin_units::parse::PrefixedHexError impl core::fmt::Debug for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Debug for bitcoin_units::sequence::Sequence impl core::fmt::Display for bitcoin_units::Amount impl core::fmt::Display for bitcoin_units::MathOp impl core::fmt::Display for bitcoin_units::NumOpError @@ -294,19 +350,30 @@ impl core::fmt::Display for bitcoin_units::block::BlockHeightInterval impl core::fmt::Display for bitcoin_units::block::BlockMtp impl core::fmt::Display for bitcoin_units::block::BlockMtpInterval impl core::fmt::Display for bitcoin_units::block::TooBigForRelativeHeightError -impl core::fmt::Display for bitcoin_units::locktime::absolute::ConversionError impl core::fmt::Display for bitcoin_units::locktime::absolute::Height +impl core::fmt::Display for bitcoin_units::locktime::absolute::LockTime impl core::fmt::Display for bitcoin_units::locktime::absolute::MedianTimePast -impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseHeightError -impl core::fmt::Display for bitcoin_units::locktime::absolute::ParseTimeError -impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidHeightError -impl core::fmt::Display for bitcoin_units::locktime::relative::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ConversionError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::fmt::Display for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::LockTime impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::fmt::Display for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::fmt::Display for bitcoin_units::locktime::relative::TimeOverflowError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::fmt::Display for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::fmt::Display for bitcoin_units::parse::ParseIntError impl core::fmt::Display for bitcoin_units::parse::PrefixedHexError impl core::fmt::Display for bitcoin_units::parse::UnprefixedHexError +impl core::fmt::Display for bitcoin_units::sequence::Sequence +impl core::fmt::LowerHex for bitcoin_units::sequence::Sequence +impl core::fmt::UpperHex for bitcoin_units::sequence::Sequence impl core::hash::Hash for bitcoin_units::Amount impl core::hash::Hash for bitcoin_units::BlockTime impl core::hash::Hash for bitcoin_units::FeeRate @@ -318,9 +385,12 @@ impl core::hash::Hash for bitcoin_units::block::BlockHeightInterval impl core::hash::Hash for bitcoin_units::block::BlockMtp impl core::hash::Hash for bitcoin_units::block::BlockMtpInterval impl core::hash::Hash for bitcoin_units::locktime::absolute::Height +impl core::hash::Hash for bitcoin_units::locktime::absolute::LockTime impl core::hash::Hash for bitcoin_units::locktime::absolute::MedianTimePast +impl core::hash::Hash for bitcoin_units::locktime::relative::LockTime impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::hash::Hash for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::hash::Hash for bitcoin_units::sequence::Sequence impl core::iter::traits::accum::Sum for bitcoin_units::FeeRate impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult impl core::iter::traits::accum::Sum for bitcoin_units::NumOpResult @@ -341,9 +411,12 @@ impl core::marker::Copy for bitcoin_units::block::BlockHeightInterval impl core::marker::Copy for bitcoin_units::block::BlockMtp impl core::marker::Copy for bitcoin_units::block::BlockMtpInterval impl core::marker::Copy for bitcoin_units::locktime::absolute::Height +impl core::marker::Copy for bitcoin_units::locktime::absolute::LockTime impl core::marker::Copy for bitcoin_units::locktime::absolute::MedianTimePast +impl core::marker::Copy for bitcoin_units::locktime::relative::LockTime impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Copy for bitcoin_units::locktime::relative::NumberOfBlocks +impl core::marker::Copy for bitcoin_units::sequence::Sequence impl core::marker::Freeze for bitcoin_units::Amount impl core::marker::Freeze for bitcoin_units::BlockTime impl core::marker::Freeze for bitcoin_units::FeeRate @@ -369,19 +442,28 @@ impl core::marker::Freeze for bitcoin_units::block::BlockHeightInterval impl core::marker::Freeze for bitcoin_units::block::BlockMtp impl core::marker::Freeze for bitcoin_units::block::BlockMtpInterval impl core::marker::Freeze for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Freeze for bitcoin_units::locktime::absolute::Height +impl core::marker::Freeze for bitcoin_units::locktime::absolute::LockTime impl core::marker::Freeze for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Freeze for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Freeze for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Freeze for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::LockTime impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Freeze for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Freeze for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Freeze for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Freeze for bitcoin_units::parse::ParseIntError impl core::marker::Freeze for bitcoin_units::parse::PrefixedHexError impl core::marker::Freeze for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Freeze for bitcoin_units::sequence::Sequence impl core::marker::Send for bitcoin_units::Amount impl core::marker::Send for bitcoin_units::BlockTime impl core::marker::Send for bitcoin_units::FeeRate @@ -407,19 +489,28 @@ impl core::marker::Send for bitcoin_units::block::BlockHeightInterval impl core::marker::Send for bitcoin_units::block::BlockMtp impl core::marker::Send for bitcoin_units::block::BlockMtpInterval impl core::marker::Send for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Send for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Send for bitcoin_units::locktime::absolute::Height +impl core::marker::Send for bitcoin_units::locktime::absolute::LockTime impl core::marker::Send for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Send for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Send for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Send for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Send for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Send for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::LockTime impl core::marker::Send for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Send for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Send for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Send for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Send for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Send for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Send for bitcoin_units::parse::ParseIntError impl core::marker::Send for bitcoin_units::parse::PrefixedHexError impl core::marker::Send for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Send for bitcoin_units::sequence::Sequence impl core::marker::StructuralPartialEq for bitcoin_units::Amount impl core::marker::StructuralPartialEq for bitcoin_units::BlockTime impl core::marker::StructuralPartialEq for bitcoin_units::FeeRate @@ -444,19 +535,28 @@ impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockHeightInte impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtp impl core::marker::StructuralPartialEq for bitcoin_units::block::BlockMtpInterval impl core::marker::StructuralPartialEq for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ConversionError impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::Height +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::LockTime impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::LockTime impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::StructuralPartialEq for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::StructuralPartialEq for bitcoin_units::parse::ParseIntError impl core::marker::StructuralPartialEq for bitcoin_units::parse::PrefixedHexError impl core::marker::StructuralPartialEq for bitcoin_units::parse::UnprefixedHexError +impl core::marker::StructuralPartialEq for bitcoin_units::sequence::Sequence impl core::marker::Sync for bitcoin_units::Amount impl core::marker::Sync for bitcoin_units::BlockTime impl core::marker::Sync for bitcoin_units::FeeRate @@ -482,19 +582,28 @@ impl core::marker::Sync for bitcoin_units::block::BlockHeightInterval impl core::marker::Sync for bitcoin_units::block::BlockMtp impl core::marker::Sync for bitcoin_units::block::BlockMtpInterval impl core::marker::Sync for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Sync for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Sync for bitcoin_units::locktime::absolute::Height +impl core::marker::Sync for bitcoin_units::locktime::absolute::LockTime impl core::marker::Sync for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Sync for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Sync for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Sync for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::LockTime impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Sync for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Sync for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Sync for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Sync for bitcoin_units::parse::ParseIntError impl core::marker::Sync for bitcoin_units::parse::PrefixedHexError impl core::marker::Sync for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Sync for bitcoin_units::sequence::Sequence impl core::marker::Unpin for bitcoin_units::Amount impl core::marker::Unpin for bitcoin_units::BlockTime impl core::marker::Unpin for bitcoin_units::FeeRate @@ -520,19 +629,28 @@ impl core::marker::Unpin for bitcoin_units::block::BlockHeightInterval impl core::marker::Unpin for bitcoin_units::block::BlockMtp impl core::marker::Unpin for bitcoin_units::block::BlockMtpInterval impl core::marker::Unpin for bitcoin_units::block::TooBigForRelativeHeightError -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ConversionError impl core::marker::Unpin for bitcoin_units::locktime::absolute::Height +impl core::marker::Unpin for bitcoin_units::locktime::absolute::LockTime impl core::marker::Unpin for bitcoin_units::locktime::absolute::MedianTimePast -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseHeightError -impl core::marker::Unpin for bitcoin_units::locktime::absolute::ParseTimeError -impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidHeightError -impl core::marker::Unpin for bitcoin_units::locktime::relative::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ConversionError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::marker::Unpin for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::LockTime impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::marker::Unpin for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::marker::Unpin for bitcoin_units::locktime::relative::TimeOverflowError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::marker::Unpin for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::marker::Unpin for bitcoin_units::parse::ParseIntError impl core::marker::Unpin for bitcoin_units::parse::PrefixedHexError impl core::marker::Unpin for bitcoin_units::parse::UnprefixedHexError +impl core::marker::Unpin for bitcoin_units::sequence::Sequence impl core::ops::arith::Add for bitcoin_units::Amount impl core::ops::arith::Add for bitcoin_units::FeeRate impl core::ops::arith::Add for bitcoin_units::SignedAmount @@ -784,19 +902,28 @@ impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockHeig impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtp impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::BlockMtpInterval impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ConversionError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::LockTime impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ConversionError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::LockTime impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::ParseIntError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::PrefixedHexError impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::RefUnwindSafe for bitcoin_units::sequence::Sequence impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::Amount impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::BlockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::FeeRate @@ -822,19 +949,28 @@ impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockHeightI impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtp impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::BlockMtpInterval impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::block::TooBigForRelativeHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ConversionError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::Height +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::LockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::MedianTimePast -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::ParseTimeError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidHeightError -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ConversionError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::IncompatibleTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ParseHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::absolute::error::ParseTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::LockTime impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::NumberOfBlocks -impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::TimeOverflowError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::DisabledLockTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::InvalidHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::InvalidTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::locktime::relative::error::TimeOverflowError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::ParseIntError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::PrefixedHexError impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::parse::UnprefixedHexError +impl core::panic::unwind_safe::UnwindSafe for bitcoin_units::sequence::Sequence impl core::str::traits::FromStr for bitcoin_units::Amount impl core::str::traits::FromStr for bitcoin_units::SignedAmount impl core::str::traits::FromStr for bitcoin_units::Weight @@ -844,6 +980,7 @@ impl core::str::traits::FromStr for bitcoin_units::block::BlockHeightInterval impl core::str::traits::FromStr for bitcoin_units::block::BlockMtp impl core::str::traits::FromStr for bitcoin_units::block::BlockMtpInterval impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::Height +impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::LockTime impl core::str::traits::FromStr for bitcoin_units::locktime::absolute::MedianTimePast impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOf512Seconds impl core::str::traits::FromStr for bitcoin_units::locktime::relative::NumberOfBlocks @@ -929,9 +1066,6 @@ impl core::cmp::PartialEq for bitcoin_units::NumOpResul impl bitcoin_units::NumOpResult impl core::fmt::Debug for bitcoin_units::NumOpResult impl core::marker::Copy for bitcoin_units::NumOpResult -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator -impl bitcoin_units::CheckedSum for T where T: core::iter::traits::iterator::Iterator impl bitcoin_units::NumOpResult impl core::marker::Freeze for bitcoin_units::NumOpResult where T: core::marker::Freeze impl core::marker::Send for bitcoin_units::NumOpResult where T: core::marker::Send @@ -960,6 +1094,8 @@ pub bitcoin_units::MathOp::Rem pub bitcoin_units::MathOp::Sub pub bitcoin_units::NumOpResult::Error(bitcoin_units::NumOpError) pub bitcoin_units::NumOpResult::Valid(T) +pub bitcoin_units::absolute::LockTime::Blocks(bitcoin_units::locktime::absolute::Height) +pub bitcoin_units::absolute::LockTime::Seconds(bitcoin_units::locktime::absolute::MedianTimePast) pub bitcoin_units::amount::Denomination::Bit pub bitcoin_units::amount::Denomination::Bitcoin pub bitcoin_units::amount::Denomination::CentiBitcoin @@ -968,6 +1104,36 @@ pub bitcoin_units::amount::Denomination::MilliBitcoin pub bitcoin_units::amount::Denomination::Satoshi pub bitcoin_units::amount::ParseDenominationError::PossiblyConfusing(bitcoin_units::amount::PossiblyConfusingDenominationError) pub bitcoin_units::amount::ParseDenominationError::Unknown(bitcoin_units::amount::UnknownDenominationError) +pub bitcoin_units::locktime::absolute::LockTime::Blocks(bitcoin_units::locktime::absolute::Height) +pub bitcoin_units::locktime::absolute::LockTime::Seconds(bitcoin_units::locktime::absolute::MedianTimePast) +pub bitcoin_units::locktime::relative::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::LockTime::Blocks(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::LockTime::Time(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::LockTime::Blocks(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::LockTime::Time(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::error::IsSatisfiedByError::Blocks(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::error::IsSatisfiedByError::Time(bitcoin_units::locktime::relative::error::InvalidTimeError) +pub bitcoin_units::relative::error::IsSatisfiedByHeightError::Incompatible(bitcoin_units::locktime::relative::NumberOf512Seconds) +pub bitcoin_units::relative::error::IsSatisfiedByHeightError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidHeightError) +pub bitcoin_units::relative::error::IsSatisfiedByTimeError::Incompatible(bitcoin_units::locktime::relative::NumberOfBlocks) +pub bitcoin_units::relative::error::IsSatisfiedByTimeError::Satisfaction(bitcoin_units::locktime::relative::error::InvalidTimeError) pub const bitcoin_units::Amount::FIFTY_BTC: Self pub const bitcoin_units::Amount::MAX: Self pub const bitcoin_units::Amount::MAX_MONEY: Self @@ -994,6 +1160,7 @@ pub const bitcoin_units::Weight::MIN: bitcoin_units::Weight pub const bitcoin_units::Weight::MIN_TRANSACTION: bitcoin_units::Weight pub const bitcoin_units::Weight::WITNESS_SCALE_FACTOR: u64 pub const bitcoin_units::Weight::ZERO: bitcoin_units::Weight +pub const bitcoin_units::absolute::LOCK_TIME_THRESHOLD: u32 pub const bitcoin_units::amount::Denomination::BTC: Self pub const bitcoin_units::amount::Denomination::SAT: Self pub const bitcoin_units::block::BlockHeight::MAX: Self @@ -1012,14 +1179,25 @@ pub const bitcoin_units::locktime::absolute::Height::MAX: Self pub const bitcoin_units::locktime::absolute::Height::MIN: Self pub const bitcoin_units::locktime::absolute::Height::ZERO: Self pub const bitcoin_units::locktime::absolute::LOCK_TIME_THRESHOLD: u32 +pub const bitcoin_units::locktime::absolute::LockTime::SIZE: usize +pub const bitcoin_units::locktime::absolute::LockTime::ZERO: bitcoin_units::locktime::absolute::LockTime pub const bitcoin_units::locktime::absolute::MedianTimePast::MAX: Self pub const bitcoin_units::locktime::absolute::MedianTimePast::MIN: Self +pub const bitcoin_units::locktime::relative::LockTime::SIZE: usize +pub const bitcoin_units::locktime::relative::LockTime::ZERO: bitcoin_units::locktime::relative::LockTime pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MAX: Self pub const bitcoin_units::locktime::relative::NumberOf512Seconds::MIN: Self pub const bitcoin_units::locktime::relative::NumberOf512Seconds::ZERO: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::MAX: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::MIN: Self pub const bitcoin_units::locktime::relative::NumberOfBlocks::ZERO: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_LOCKTIME_AND_RBF: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_LOCKTIME_NO_RBF: Self +pub const bitcoin_units::sequence::Sequence::ENABLE_RBF_NO_LOCKTIME: Self +pub const bitcoin_units::sequence::Sequence::FINAL: Self +pub const bitcoin_units::sequence::Sequence::MAX: Self +pub const bitcoin_units::sequence::Sequence::SIZE: usize +pub const bitcoin_units::sequence::Sequence::ZERO: Self pub const bitcoin_units::weight::WITNESS_SCALE_FACTOR: usize pub const fn bitcoin_units::Amount::checked_add(self, rhs: Self) -> core::option::Option pub const fn bitcoin_units::Amount::checked_div(self, rhs: u64) -> core::option::Option @@ -1082,6 +1260,8 @@ pub const fn bitcoin_units::Weight::to_kwu_floor(self) -> u64 pub const fn bitcoin_units::Weight::to_vbytes_ceil(self) -> u64 pub const fn bitcoin_units::Weight::to_vbytes_floor(self) -> u64 pub const fn bitcoin_units::Weight::to_wu(self) -> u64 +pub const fn bitcoin_units::absolute::is_block_height(n: u32) -> bool +pub const fn bitcoin_units::absolute::is_block_time(n: u32) -> bool pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockHeightInterval::from_u32(inner: u32) -> Self @@ -1089,18 +1269,28 @@ pub const fn bitcoin_units::block::BlockHeightInterval::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockMtp::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockMtp::to_u32(self) -> u32 pub const fn bitcoin_units::block::BlockMtpInterval::from_u32(inner: u32) -> Self -pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result -pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_ceil(self) -> core::result::Result +pub const fn bitcoin_units::block::BlockMtpInterval::to_relative_mtp_interval_floor(self) -> core::result::Result pub const fn bitcoin_units::block::BlockMtpInterval::to_u32(self) -> u32 -pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::Height::from_u32(n: u32) -> core::result::Result pub const fn bitcoin_units::locktime::absolute::Height::to_u32(self) -> u32 -pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::absolute::LockTime::is_block_height(self) -> bool +pub const fn bitcoin_units::locktime::absolute::LockTime::is_block_time(self) -> bool +pub const fn bitcoin_units::locktime::absolute::LockTime::is_same_unit(self, other: bitcoin_units::locktime::absolute::LockTime) -> bool +pub const fn bitcoin_units::locktime::absolute::MedianTimePast::from_u32(n: u32) -> core::result::Result pub const fn bitcoin_units::locktime::absolute::MedianTimePast::to_u32(self) -> u32 pub const fn bitcoin_units::locktime::absolute::is_block_height(n: u32) -> bool pub const fn bitcoin_units::locktime::absolute::is_block_time(n: u32) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::from_512_second_intervals(intervals: u16) -> Self +pub const fn bitcoin_units::locktime::relative::LockTime::from_height(n: u16) -> Self +pub const fn bitcoin_units::locktime::relative::LockTime::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::LockTime::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::LockTime::is_block_height(self) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::is_block_time(self) -> bool +pub const fn bitcoin_units::locktime::relative::LockTime::is_same_unit(self, other: bitcoin_units::locktime::relative::LockTime) -> bool pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_512_second_intervals(intervals: u16) -> Self -pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result -pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_ceil(seconds: u32) -> core::result::Result +pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_seconds_floor(seconds: u32) -> core::result::Result pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_512_second_intervals(self) -> u16 pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_consensus_u32(self) -> u32 pub const fn bitcoin_units::locktime::relative::NumberOf512Seconds::to_seconds(self) -> u32 @@ -1108,6 +1298,22 @@ pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::from_height(bloc pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_consensus_u32(self) -> u32 pub const fn bitcoin_units::locktime::relative::NumberOfBlocks::to_height(self) -> u16 pub enum bitcoin_units::NumOpResult +pub enum bitcoin_units::absolute::LockTime +pub enum bitcoin_units::locktime::absolute::LockTime +pub enum bitcoin_units::locktime::relative::IsSatisfiedByError +pub enum bitcoin_units::locktime::relative::IsSatisfiedByHeightError +pub enum bitcoin_units::locktime::relative::IsSatisfiedByTimeError +pub enum bitcoin_units::locktime::relative::LockTime +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByError +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +pub enum bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +pub enum bitcoin_units::relative::IsSatisfiedByError +pub enum bitcoin_units::relative::IsSatisfiedByHeightError +pub enum bitcoin_units::relative::IsSatisfiedByTimeError +pub enum bitcoin_units::relative::LockTime +pub enum bitcoin_units::relative::error::IsSatisfiedByError +pub enum bitcoin_units::relative::error::IsSatisfiedByHeightError +pub enum bitcoin_units::relative::error::IsSatisfiedByTimeError pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn &bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn &bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1248,9 +1454,6 @@ pub fn &u64::mul(self, rhs: &bitcoin_units::Weight) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output pub fn &u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output -pub fn T::checked_sum(self) -> core::option::Option -pub fn T::checked_sum(self) -> core::option::Option -pub fn T::checked_sum(self) -> core::option::Option pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::add(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::add(self, rhs: bitcoin_units::Amount) -> Self::Output @@ -1299,7 +1502,6 @@ pub fn bitcoin_units::BlockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> pub fn bitcoin_units::BlockTime::from(t: u32) -> Self pub fn bitcoin_units::BlockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::BlockTime::partial_cmp(&self, other: &bitcoin_units::BlockTime) -> core::option::Option -pub fn bitcoin_units::CheckedSum::checked_sum(self) -> core::option::Option pub fn bitcoin_units::FeeRate::add(self, rhs: &bitcoin_units::FeeRate) -> Self::Output pub fn bitcoin_units::FeeRate::add(self, rhs: bitcoin_units::FeeRate) -> Self::Output pub fn bitcoin_units::FeeRate::add_assign(&mut self, rhs: &bitcoin_units::FeeRate) @@ -1626,44 +1828,82 @@ pub fn bitcoin_units::block::BlockMtpInterval::try_from(s: &str) -> core::result pub fn bitcoin_units::block::TooBigForRelativeHeightError::clone(&self) -> bitcoin_units::block::TooBigForRelativeHeightError pub fn bitcoin_units::block::TooBigForRelativeHeightError::eq(&self, other: &bitcoin_units::block::TooBigForRelativeHeightError) -> bool pub fn bitcoin_units::block::TooBigForRelativeHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::ConversionError -pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool -pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering pub fn bitcoin_units::locktime::absolute::Height::eq(&self, other: &bitcoin_units::locktime::absolute::Height) -> bool pub fn bitcoin_units::locktime::absolute::Height::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::Height::from_hex(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::locktime::absolute::Height::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height) -> bool pub fn bitcoin_units::locktime::absolute::Height::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::option::Option pub fn bitcoin_units::locktime::absolute::Height::try_from(h: bitcoin_units::block::BlockHeight) -> core::result::Result pub fn bitcoin_units::locktime::absolute::Height::try_from(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::clone(&self) -> bitcoin_units::locktime::absolute::LockTime +pub fn bitcoin_units::locktime::absolute::LockTime::eq(&self, other: &bitcoin_units::locktime::absolute::LockTime) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from(h: bitcoin_units::locktime::absolute::Height) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from(t: bitcoin_units::locktime::absolute::MedianTimePast) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from_consensus(n: u32) -> Self +pub fn bitcoin_units::locktime::absolute::LockTime::from_height(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_mtp(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::from_unprefixed_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::absolute::LockTime::is_implied_by(self, other: bitcoin_units::locktime::absolute::LockTime) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by(self, height: bitcoin_units::locktime::absolute::Height, mtp: bitcoin_units::locktime::absolute::MedianTimePast) -> bool +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by_height(self, height: bitcoin_units::locktime::absolute::Height) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::is_satisfied_by_time(self, mtp: bitcoin_units::locktime::absolute::MedianTimePast) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::LockTime::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::locktime::absolute::LockTime::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::clone(&self) -> bitcoin_units::locktime::absolute::MedianTimePast pub fn bitcoin_units::locktime::absolute::MedianTimePast::cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::cmp::Ordering pub fn bitcoin_units::locktime::absolute::MedianTimePast::eq(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> bool pub fn bitcoin_units::locktime::absolute::MedianTimePast::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_hex(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::hash<__H: core::hash::Hasher>(&self, state: &mut __H) pub fn bitcoin_units::locktime::absolute::MedianTimePast::is_satisfied_by(self, time: bitcoin_units::locktime::absolute::MedianTimePast) -> bool -pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result +pub fn bitcoin_units::locktime::absolute::MedianTimePast::new(timestamps: [bitcoin_units::BlockTime; 11]) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::partial_cmp(&self, other: &bitcoin_units::locktime::absolute::MedianTimePast) -> core::option::Option pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(h: bitcoin_units::block::BlockMtp) -> core::result::Result pub fn bitcoin_units::locktime::absolute::MedianTimePast::try_from(s: &str) -> core::result::Result -pub fn bitcoin_units::locktime::absolute::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::ParseHeightError -pub fn bitcoin_units::locktime::absolute::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseHeightError) -> bool -pub fn bitcoin_units::locktime::absolute::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::ParseTimeError -pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool -pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::relative::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::InvalidHeightError -pub fn bitcoin_units::locktime::relative::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidHeightError) -> bool -pub fn bitcoin_units::locktime::relative::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn bitcoin_units::locktime::relative::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::InvalidTimeError -pub fn bitcoin_units::locktime::relative::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::InvalidTimeError) -> bool -pub fn bitcoin_units::locktime::relative::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ConversionError::clone(&self) -> bitcoin_units::locktime::absolute::error::ConversionError +pub fn bitcoin_units::locktime::absolute::error::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ConversionError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::clone(&self) -> bitcoin_units::locktime::absolute::error::IncompatibleHeightError +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::error::IncompatibleHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::incompatible(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::error::IncompatibleHeightError::lock(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::clone(&self) -> bitcoin_units::locktime::absolute::error::IncompatibleTimeError +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::error::IncompatibleTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::incompatible(&self) -> bitcoin_units::locktime::absolute::MedianTimePast +pub fn bitcoin_units::locktime::absolute::error::IncompatibleTimeError::lock(&self) -> bitcoin_units::locktime::absolute::Height +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::clone(&self) -> bitcoin_units::locktime::absolute::error::ParseHeightError +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ParseHeightError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ParseHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::clone(&self) -> bitcoin_units::locktime::absolute::error::ParseTimeError +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::error::ParseTimeError) -> bool +pub fn bitcoin_units::locktime::absolute::error::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::LockTime::clone(&self) -> bitcoin_units::locktime::relative::LockTime +pub fn bitcoin_units::locktime::relative::LockTime::eq(&self, other: &bitcoin_units::locktime::relative::LockTime) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::LockTime::from(h: bitcoin_units::locktime::relative::NumberOfBlocks) -> Self +pub fn bitcoin_units::locktime::relative::LockTime::from(t: bitcoin_units::locktime::relative::NumberOf512Seconds) -> Self +pub fn bitcoin_units::locktime::relative::LockTime::from_consensus(n: u32) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::from_sequence(n: bitcoin_units::sequence::Sequence) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::locktime::relative::LockTime::is_implied_by(self, other: bitcoin_units::locktime::relative::LockTime) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::is_implied_by_sequence(self, other: bitcoin_units::sequence::Sequence) -> bool +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by(self, chain_tip_height: bitcoin_units::block::BlockHeight, chain_tip_mtp: bitcoin_units::block::BlockMtp, utxo_mined_at_height: bitcoin_units::block::BlockHeight, utxo_mined_at_mtp: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by_height(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::is_satisfied_by_time(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::LockTime::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::locktime::relative::LockTime::to_sequence(self) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::locktime::relative::LockTime::try_from(seq: bitcoin_units::sequence::Sequence) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::clone(&self) -> bitcoin_units::locktime::relative::NumberOf512Seconds pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::cmp::Ordering pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::default() -> bitcoin_units::locktime::relative::NumberOf512Seconds @@ -1671,7 +1911,7 @@ pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::eq(&self, other: & pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::hash<__H: core::hash::Hasher>(&self, state: &mut __H) -pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockMtp, utxo_mined_at: bitcoin_units::block::BlockMtp) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOf512Seconds) -> core::option::Option pub fn bitcoin_units::locktime::relative::NumberOf512Seconds::try_from(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::clone(&self) -> bitcoin_units::locktime::relative::NumberOfBlocks @@ -1682,13 +1922,32 @@ pub fn bitcoin_units::locktime::relative::NumberOfBlocks::fmt(&self, f: &mut cor pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from(value: u16) -> Self pub fn bitcoin_units::locktime::relative::NumberOfBlocks::from_str(s: &str) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::hash<__H: core::hash::Hasher>(&self, state: &mut __H) -pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result +pub fn bitcoin_units::locktime::relative::NumberOfBlocks::is_satisfied_by(self, chain_tip: bitcoin_units::block::BlockHeight, utxo_mined_at: bitcoin_units::block::BlockHeight) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::partial_cmp(&self, other: &bitcoin_units::locktime::relative::NumberOfBlocks) -> core::option::Option pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(h: bitcoin_units::block::BlockHeightInterval) -> core::result::Result pub fn bitcoin_units::locktime::relative::NumberOfBlocks::try_from(s: &str) -> core::result::Result -pub fn bitcoin_units::locktime::relative::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::TimeOverflowError -pub fn bitcoin_units::locktime::relative::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::TimeOverflowError) -> bool -pub fn bitcoin_units::locktime::relative::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::DisabledLockTimeError +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::disabled_locktime_value(&self) -> u32 +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::DisabledLockTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::DisabledLockTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::clone(&self) -> bitcoin_units::locktime::relative::error::InvalidHeightError +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::eq(&self, other: &bitcoin_units::locktime::relative::error::InvalidHeightError) -> bool +pub fn bitcoin_units::locktime::relative::error::InvalidHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::InvalidTimeError +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::InvalidTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::InvalidTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByHeightError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::clone(&self) -> bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::eq(&self, other: &bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError) -> bool +pub fn bitcoin_units::locktime::relative::error::IsSatisfiedByTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::clone(&self) -> bitcoin_units::locktime::relative::error::TimeOverflowError +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::eq(&self, other: &bitcoin_units::locktime::relative::error::TimeOverflowError) -> bool +pub fn bitcoin_units::locktime::relative::error::TimeOverflowError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin_units::parse::ParseIntError::as_ref(&self) -> &core::num::error::ParseIntError pub fn bitcoin_units::parse::ParseIntError::clone(&self) -> bitcoin_units::parse::ParseIntError pub fn bitcoin_units::parse::ParseIntError::eq(&self, other: &bitcoin_units::parse::ParseIntError) -> bool @@ -1714,6 +1973,29 @@ pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result core::result::Result pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result pub fn bitcoin_units::parse::int_from_str(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::clone(&self) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::sequence::Sequence::cmp(&self, other: &bitcoin_units::sequence::Sequence) -> core::cmp::Ordering +pub fn bitcoin_units::sequence::Sequence::default() -> Self +pub fn bitcoin_units::sequence::Sequence::enables_absolute_lock_time(self) -> bool +pub fn bitcoin_units::sequence::Sequence::eq(&self, other: &bitcoin_units::sequence::Sequence) -> bool +pub fn bitcoin_units::sequence::Sequence::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn bitcoin_units::sequence::Sequence::from(lt: bitcoin_units::locktime::relative::LockTime) -> bitcoin_units::sequence::Sequence +pub fn bitcoin_units::sequence::Sequence::from_512_second_intervals(intervals: u16) -> Self +pub fn bitcoin_units::sequence::Sequence::from_consensus(n: u32) -> Self +pub fn bitcoin_units::sequence::Sequence::from_height(height: u16) -> Self +pub fn bitcoin_units::sequence::Sequence::from_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_seconds_ceil(seconds: u32) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_seconds_floor(seconds: u32) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::from_unprefixed_hex(s: &str) -> core::result::Result +pub fn bitcoin_units::sequence::Sequence::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +pub fn bitcoin_units::sequence::Sequence::is_final(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_height_locked(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_rbf(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_relative_lock_time(self) -> bool +pub fn bitcoin_units::sequence::Sequence::is_time_locked(self) -> bool +pub fn bitcoin_units::sequence::Sequence::partial_cmp(&self, other: &bitcoin_units::sequence::Sequence) -> core::option::Option +pub fn bitcoin_units::sequence::Sequence::to_consensus_u32(self) -> u32 +pub fn bitcoin_units::sequence::Sequence::to_relative_lock_time(self) -> core::option::Option pub fn core::num::error::ParseIntError::from(value: bitcoin_units::parse::ParseIntError) -> Self pub fn i64::mul(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn i64::mul(self, rhs: &bitcoin_units::SignedAmount) -> Self::Output @@ -1723,6 +2005,7 @@ pub fn u32::from(height: bitcoin_units::block::BlockHeight) -> Self pub fn u32::from(height: bitcoin_units::block::BlockHeightInterval) -> Self pub fn u32::from(height: bitcoin_units::block::BlockMtp) -> Self pub fn u32::from(height: bitcoin_units::block::BlockMtpInterval) -> Self +pub fn u32::from(sequence: bitcoin_units::sequence::Sequence) -> u32 pub fn u32::from(t: bitcoin_units::BlockTime) -> Self pub fn u64::from(value: bitcoin_units::Weight) -> Self pub fn u64::mul(self, rhs: &bitcoin_units::Amount) -> Self::Output @@ -1732,14 +2015,21 @@ pub fn u64::mul(self, rhs: bitcoin_units::Amount) -> Self::Output pub fn u64::mul(self, rhs: bitcoin_units::NumOpResult) -> Self::Output pub fn u64::mul(self, rhs: bitcoin_units::Weight) -> Self::Output pub mod bitcoin_units +pub mod bitcoin_units::absolute +pub mod bitcoin_units::absolute::error pub mod bitcoin_units::amount pub mod bitcoin_units::block pub mod bitcoin_units::fee pub mod bitcoin_units::fee_rate pub mod bitcoin_units::locktime pub mod bitcoin_units::locktime::absolute +pub mod bitcoin_units::locktime::absolute::error pub mod bitcoin_units::locktime::relative +pub mod bitcoin_units::locktime::relative::error pub mod bitcoin_units::parse +pub mod bitcoin_units::relative +pub mod bitcoin_units::relative::error +pub mod bitcoin_units::sequence pub mod bitcoin_units::time pub mod bitcoin_units::weight pub struct bitcoin_units::Amount(_) @@ -1749,8 +2039,19 @@ pub struct bitcoin_units::BlockMtp(_) pub struct bitcoin_units::BlockMtpInterval(_) pub struct bitcoin_units::BlockTime(_) pub struct bitcoin_units::FeeRate(_) +pub struct bitcoin_units::Sequence(pub u32) pub struct bitcoin_units::SignedAmount(_) pub struct bitcoin_units::Weight(_) +pub struct bitcoin_units::absolute::Height(_) +pub struct bitcoin_units::absolute::IncompatibleHeightError +pub struct bitcoin_units::absolute::IncompatibleTimeError +pub struct bitcoin_units::absolute::MedianTimePast(_) +pub struct bitcoin_units::absolute::ParseHeightError(_) +pub struct bitcoin_units::absolute::ParseTimeError(_) +pub struct bitcoin_units::absolute::error::IncompatibleHeightError +pub struct bitcoin_units::absolute::error::IncompatibleTimeError +pub struct bitcoin_units::absolute::error::ParseHeightError(_) +pub struct bitcoin_units::absolute::error::ParseTimeError(_) pub struct bitcoin_units::amount::Amount(_) pub struct bitcoin_units::amount::Display pub struct bitcoin_units::amount::InputTooLargeError @@ -1768,19 +2069,40 @@ pub struct bitcoin_units::block::BlockMtpInterval(_) pub struct bitcoin_units::block::TooBigForRelativeHeightError(_) pub struct bitcoin_units::fee_rate::FeeRate(_) pub struct bitcoin_units::locktime::absolute::Height(_) +pub struct bitcoin_units::locktime::absolute::IncompatibleHeightError +pub struct bitcoin_units::locktime::absolute::IncompatibleTimeError pub struct bitcoin_units::locktime::absolute::MedianTimePast(_) pub struct bitcoin_units::locktime::absolute::ParseHeightError(_) pub struct bitcoin_units::locktime::absolute::ParseTimeError(_) +pub struct bitcoin_units::locktime::absolute::error::IncompatibleHeightError +pub struct bitcoin_units::locktime::absolute::error::IncompatibleTimeError +pub struct bitcoin_units::locktime::absolute::error::ParseHeightError(_) +pub struct bitcoin_units::locktime::absolute::error::ParseTimeError(_) +pub struct bitcoin_units::locktime::relative::DisabledLockTimeError(_) pub struct bitcoin_units::locktime::relative::InvalidHeightError pub struct bitcoin_units::locktime::relative::InvalidTimeError pub struct bitcoin_units::locktime::relative::NumberOf512Seconds(_) pub struct bitcoin_units::locktime::relative::NumberOfBlocks(_) pub struct bitcoin_units::locktime::relative::TimeOverflowError +pub struct bitcoin_units::locktime::relative::error::DisabledLockTimeError(_) +pub struct bitcoin_units::locktime::relative::error::InvalidHeightError +pub struct bitcoin_units::locktime::relative::error::InvalidTimeError +pub struct bitcoin_units::locktime::relative::error::TimeOverflowError pub struct bitcoin_units::parse::PrefixedHexError(_) pub struct bitcoin_units::parse::UnprefixedHexError(_) +pub struct bitcoin_units::relative::DisabledLockTimeError(_) +pub struct bitcoin_units::relative::InvalidHeightError +pub struct bitcoin_units::relative::InvalidTimeError +pub struct bitcoin_units::relative::NumberOf512Seconds(_) +pub struct bitcoin_units::relative::NumberOfBlocks(_) +pub struct bitcoin_units::relative::TimeOverflowError +pub struct bitcoin_units::relative::error::DisabledLockTimeError(_) +pub struct bitcoin_units::relative::error::InvalidHeightError +pub struct bitcoin_units::relative::error::InvalidTimeError +pub struct bitcoin_units::relative::error::TimeOverflowError +pub struct bitcoin_units::sequence::Sequence(pub u32) pub struct bitcoin_units::time::BlockTime(_) pub struct bitcoin_units::weight::Weight(_) -pub trait bitcoin_units::CheckedSum: bitcoin_units::sealed::Sealed pub trait bitcoin_units::parse::Integer: core::str::traits::FromStr + core::convert::TryFrom + core::marker::Sized + bitcoin_units::parse::sealed::Sealed pub type &bitcoin_units::Amount::Output = >>::Output pub type &bitcoin_units::Amount::Output = ::Output @@ -1957,12 +2279,15 @@ pub type bitcoin_units::block::BlockMtpInterval::Error = bitcoin_units::parse::P pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output pub type bitcoin_units::block::BlockMtpInterval::Output = ::Output pub type bitcoin_units::block::BlockMtpInterval::Output = bitcoin_units::block::BlockMtpInterval -pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::ParseHeightError -pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ConversionError -pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::ParseHeightError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::ParseTimeError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ConversionError -pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::ParseTimeError +pub type bitcoin_units::locktime::absolute::Height::Err = bitcoin_units::locktime::absolute::error::ParseHeightError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::error::ConversionError +pub type bitcoin_units::locktime::absolute::Height::Error = bitcoin_units::locktime::absolute::error::ParseHeightError +pub type bitcoin_units::locktime::absolute::LockTime::Err = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::absolute::LockTime::Error = bitcoin_units::parse::ParseIntError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Err = bitcoin_units::locktime::absolute::error::ParseTimeError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::error::ConversionError +pub type bitcoin_units::locktime::absolute::MedianTimePast::Error = bitcoin_units::locktime::absolute::error::ParseTimeError +pub type bitcoin_units::locktime::relative::LockTime::Error = bitcoin_units::locktime::relative::error::DisabledLockTimeError pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Err = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOf512Seconds::Error = bitcoin_units::parse::ParseIntError pub type bitcoin_units::locktime::relative::NumberOfBlocks::Err = bitcoin_units::parse::ParseIntError From 73548df1d70a64d3e81ddee27243caef6f9771c8 Mon Sep 17 00:00:00 2001 From: anim001k <140460766+anim001k@users.noreply.github.com> Date: Thu, 31 Jul 2025 11:40:20 +0200 Subject: [PATCH 212/857] Update message_network.rs --- p2p/src/message_network.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/p2p/src/message_network.rs b/p2p/src/message_network.rs index 16dcc3bf3d..f8f240a5dc 100644 --- a/p2p/src/message_network.rs +++ b/p2p/src/message_network.rs @@ -147,20 +147,20 @@ impl_consensus_encoding!(Reject, message, ccode, reason, hash); /// A deprecated message type that was used to notify users of system changes. Due to a number of /// vulerabilities, alerts are no longer used. A final alert was sent as of Bitcoin Core 0.14.0, -/// and is sent to any node that is advertising a potentially vulerable protocol version. +/// and is sent to any node that is advertising a potentially vulnerable protocol version. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Alert(Vec); impl Alert { const FINAL_ALERT: [u8; 96] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0]; - /// Build the final alert to send to a potentially vulerable peer. + /// Build the final alert to send to a potentially vulnerable peer. pub fn final_alert() -> Self { Self(Self::FINAL_ALERT.into()) } /// The final alert advertised by Bitcoin Core. This alert is sent if the advertised protocol - /// version is vulerable to the alert-system vulerablities. + /// version is vulnerable to the alert-system vulerablities. pub fn is_final_alert(&self) -> bool { self.0.eq(&Self::FINAL_ALERT) } From ab662c30e872bfc8677df12929d39e2d3812633f Mon Sep 17 00:00:00 2001 From: sashass1315 Date: Thu, 31 Jul 2025 19:19:04 +0300 Subject: [PATCH 213/857] fix: correct method name in Decodable trait documentation --- bitcoin/src/consensus/encode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs index 4e6cd660f8..b9c2416609 100644 --- a/bitcoin/src/consensus/encode.rs +++ b/bitcoin/src/consensus/encode.rs @@ -284,7 +284,7 @@ pub trait Decodable: Sized { /// * Simple types that have a fixed size (own and member fields), don't have to overwrite /// this method, or be concern with it. /// * Types that deserialize using externally provided length should implement it: - /// * Make `consensus_decode` forward to `consensus_decode_bytes_from_finite_reader` with the + /// * Make `consensus_decode` forward to `consensus_decode_from_finite_reader` with the /// reader wrapped by `Take`. Failure to do so, without other forms of memory exhaustion /// protection might lead to resource exhaustion vulnerability. /// * Put a max cap on things like `Vec::with_capacity` to avoid oversized allocations, and From 7fa84f2b1c26248c44ed385c52a12004df099726 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 31 Jul 2025 10:17:00 +1000 Subject: [PATCH 214/857] bitcoin:: Use TBD in deprecation notice We do not know what the next version will be, by convention we use `TBD` in the deprecation attribute then set the version number right before release. --- bitcoin/src/blockdata/constants.rs | 2 +- bitcoin/src/network/params.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs index 6df7336e7d..7fe76a89d1 100644 --- a/bitcoin/src/blockdata/constants.rs +++ b/bitcoin/src/blockdata/constants.rs @@ -203,7 +203,7 @@ impl ChainHash { 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, ]); /// `ChainHash` for testnet3 bitcoin. - #[deprecated(since = "0.33.0", note = "use `TESTNET3` instead")] + #[deprecated(since = "TBD", note = "use `TESTNET3` instead")] pub const TESTNET: Self = Self([ 67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151, 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0, diff --git a/bitcoin/src/network/params.rs b/bitcoin/src/network/params.rs index fc745e455c..645c16ee9f 100644 --- a/bitcoin/src/network/params.rs +++ b/bitcoin/src/network/params.rs @@ -121,7 +121,7 @@ pub struct Params { /// [using-statics-or-consts]: pub static MAINNET: Params = Params::MAINNET; /// The testnet3 parameters. -#[deprecated(since = "0.33.0", note = "use `TESTNET3` instead")] +#[deprecated(since = "TBD", note = "use `TESTNET3` instead")] pub static TESTNET: Params = Params::TESTNET3; /// The testnet3 parameters. pub static TESTNET3: Params = Params::TESTNET3; @@ -155,7 +155,7 @@ impl Params { }; /// The testnet3 parameters. - #[deprecated(since = "0.33.0", note = "use `TESTNET3` instead")] + #[deprecated(since = "TBD", note = "use `TESTNET3` instead")] pub const TESTNET: Params = Params { network: Network::Testnet(TestnetVersion::V3), bip16_time: 1333238400, // Apr 1 2012 From 85fd704bfde712c82c949ad9bfb7663c8aa53441 Mon Sep 17 00:00:00 2001 From: Zeegaths Date: Wed, 30 Jul 2025 15:52:04 +0300 Subject: [PATCH 215/857] units: Add signed_sub method to Amount - Infallibly subtracts one Amount from another returning a SignedAmount - Uses existing to_signed() method for cleaner implementation - Since SignedAmount::MIN equals -Amount::MAX, subtraction cannot overflow - Includes comprehensive tests for overflow prevention - Resolves #4644 --- bitcoin/src/blockdata/transaction.rs | 6 ++-- units/src/amount/tests.rs | 44 ++++++++++++++++++++++++++++ units/src/amount/unsigned.rs | 10 +++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 3b1c19a90c..9fedd4b181 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -779,10 +779,8 @@ pub fn effective_value( ) -> SignedAmount { let weight = input_weight_prediction.total_weight(); let fee = fee_rate.to_fee(weight); - - // Cannot overflow because after conversion to signed Amount::MIN - Amount::MAX - // still fits in SignedAmount::MAX (0 - MAX = -MAX). - (value.to_signed() - fee.to_signed()).expect("cannot overflow") + + value.signed_sub(fee) } /// Predicts the weight of a to-be-constructed transaction. diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 6644ddb477..4daf35f7a6 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -1331,3 +1331,47 @@ fn signed_amount_div_nonzero() { assert_eq!(&signed / divisor, SignedAmount::from_sat(-25).unwrap()); assert_eq!(signed / &divisor, SignedAmount::from_sat(-25).unwrap()); } + +#[test] +fn signed_sub() { + // Test the core feature: cannot overflow unlike regular subtraction + let small = sat(100); + let large = sat(1000); + + // Regular checked_sub would fail (returns None) for small - large + assert_eq!(small.checked_sub(large), None); + + // But signed_sub works - this is the key feature! + let result = small.signed_sub(large); + assert_eq!(result.to_sat(), -900); + assert!(result.is_negative()); + + // Test positive result + let result2 = large.signed_sub(small); + assert_eq!(result2.to_sat(), 900); + assert!(result2.is_positive()); + + // Test zero result + let result3 = large.signed_sub(large); + assert_eq!(result3.to_sat(), 0); + + // Test edge cases with maximum amounts + let max_diff = Amount::MAX.signed_sub(Amount::ZERO); + assert_eq!(max_diff.to_sat(), Amount::MAX.to_sat() as i64); + + let min_diff = Amount::ZERO.signed_sub(Amount::MAX); + assert_eq!(min_diff.to_sat(), -(Amount::MAX.to_sat() as i64)); + + // Any two valid amounts will always produce a valid SignedAmount + // This demonstrates the "cannot overflow" property + let amt1 = Amount::MAX_MONEY; + let amt2 = sat(1); + + let diff1 = amt1.signed_sub(amt2); + let diff2 = amt2.signed_sub(amt1); + + assert!(diff1.is_positive()); + assert!(diff2.is_negative()); + assert_eq!(diff1.to_sat(), (Amount::MAX_MONEY.to_sat() - 1) as i64); + assert_eq!(diff2.to_sat(), -((Amount::MAX_MONEY.to_sat() - 1) as i64)); +} \ No newline at end of file diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 9102807921..125e693ead 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -405,6 +405,16 @@ impl Amount { SignedAmount::from_sat(self.to_sat() as i64) // Cast ok, signed amount and amount share positive range. .expect("range of Amount is within range of SignedAmount") } + + /// Infallibly subtracts one `Amount` from another returning a [`SignedAmount`]. + /// + /// Since `SignedAmount::MIN` is equivalent to `-Amount::MAX` subtraction of two signed amounts + /// can never overflow a `SignedAmount`. + #[must_use] + pub fn signed_sub(self, rhs: Amount) -> SignedAmount { + (self.to_signed() - rhs.to_signed()) + .expect("difference of two amounts is always within SignedAmount range") + } /// Checked weight floor division. /// From 448666c9fbb16cfad22752907f0571269d0092bb Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Sun, 27 Jul 2025 14:16:32 +0100 Subject: [PATCH 216/857] p2p: Use `FeeRate` in the feefilter message The previous `i64` is obviously not type-safe and I believe it is also wrong. BIP-133 states this value is encoded as a uint64_t. The `u64` is decoded of the wire and interpreted as sats per kvb. Given the `FeeRate` constructor accepts a `u32`, if the `try_into` overflows we can treat it as `u32::MAX`, which essentially says the remote node doesn't want any transactions from us. ref: https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki#specification --- p2p/src/message.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/p2p/src/message.rs b/p2p/src/message.rs index 942e258285..dcecf51726 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -15,6 +15,7 @@ use bitcoin::{block, transaction}; use hashes::sha256d; use internals::ToU64 as _; use io::{BufRead, Write}; +use units::FeeRate; use crate::address::{AddrV2Message, Address}; use crate::consensus::impl_vec_wrapper; @@ -250,7 +251,7 @@ pub enum NetworkMessage { /// `reject` Reject(message_network::Reject), /// `feefilter` - FeeFilter(i64), + FeeFilter(FeeRate), /// `wtxidrelay` WtxidRelay, /// `addrv2` @@ -423,7 +424,7 @@ impl Encodable for NetworkMessage { NetworkMessage::BlockTxn(ref dat) => dat.consensus_encode(writer), NetworkMessage::Alert(ref dat) => dat.consensus_encode(writer), NetworkMessage::Reject(ref dat) => dat.consensus_encode(writer), - NetworkMessage::FeeFilter(ref dat) => dat.consensus_encode(writer), + NetworkMessage::FeeFilter(ref dat) => dat.to_sat_per_kvb_ceil().consensus_encode(writer), NetworkMessage::AddrV2(ref dat) => dat.consensus_encode(writer), NetworkMessage::Verack | NetworkMessage::SendHeaders @@ -608,9 +609,16 @@ impl Decodable for RawNetworkMessage { NetworkMessage::Reject(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?), "alert" => NetworkMessage::Alert(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?), - "feefilter" => NetworkMessage::FeeFilter( - Decodable::consensus_decode_from_finite_reader(&mut mem_d)?, - ), + "feefilter" => { + NetworkMessage::FeeFilter( + u64::consensus_decode_from_finite_reader(&mut mem_d)? + .try_into() + .ok() + // Given some absurdly large value, using the maximum conveys that no + // transactions should be relayed to this peer. + .map_or(FeeRate::MAX, FeeRate::from_sat_per_kvb) + ) + }, "sendcmpct" => NetworkMessage::SendCmpct( Decodable::consensus_decode_from_finite_reader(&mut mem_d)?, ), @@ -669,7 +677,14 @@ impl Decodable for V2NetworkMessage { 2u8 => NetworkMessage::Block(Decodable::consensus_decode_from_finite_reader(r)?), 3u8 => NetworkMessage::BlockTxn(Decodable::consensus_decode_from_finite_reader(r)?), 4u8 => NetworkMessage::CmpctBlock(Decodable::consensus_decode_from_finite_reader(r)?), - 5u8 => NetworkMessage::FeeFilter(Decodable::consensus_decode_from_finite_reader(r)?), + 5u8 => NetworkMessage::FeeFilter( + u64::consensus_decode_from_finite_reader(r)? + .try_into() + .ok() + // Given some absurdly large value, using the maximum conveys that no + // transactions should be relayed to this peer. + .map_or(FeeRate::MAX, FeeRate::from_sat_per_kvb) + ), 6u8 => NetworkMessage::FilterAdd(Decodable::consensus_decode_from_finite_reader(r)?), 7u8 => NetworkMessage::FilterClear, 8u8 => NetworkMessage::FilterLoad(Decodable::consensus_decode_from_finite_reader(r)?), @@ -842,7 +857,7 @@ mod test { reason: "Cause".into(), hash: hash([255u8; 32]), }), - NetworkMessage::FeeFilter(1000), + NetworkMessage::FeeFilter(FeeRate::BROADCAST_MIN), NetworkMessage::WtxidRelay, NetworkMessage::AddrV2(AddrV2Payload(vec![AddrV2Message { addr: AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)), From edea5c841e9b0e2b2008d6ed4eba8a063208c317 Mon Sep 17 00:00:00 2001 From: Jakub Gladysz Date: Fri, 1 Aug 2025 19:40:13 +0200 Subject: [PATCH 217/857] Remove # from crate rustdoc titles rustdocs renders the title the same with and without the # Resolves: #4677 --- addresses/src/lib.rs | 2 +- bitcoin/src/lib.rs | 2 +- chacha20_poly1305/src/lib.rs | 2 +- fuzz/src/lib.rs | 2 +- hashes/src/lib.rs | 2 +- internals/src/lib.rs | 2 +- io/src/lib.rs | 2 +- p2p/src/lib.rs | 2 +- primitives/src/lib.rs | 2 +- units/src/lib.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addresses/src/lib.rs b/addresses/src/lib.rs index 06c99f4e99..63f6a8fe70 100644 --- a/addresses/src/lib.rs +++ b/addresses/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Bitcoin Addresses +//! Bitcoin Addresses //! //! Bitcoin addresses do not appear on chain; rather, they are conventions used by Bitcoin (wallet) //! software to communicate where coins should be sent and are based on the output type e.g., P2WPKH. diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index c920c12b39..d9bad2fe34 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin Library +//! Rust Bitcoin Library //! //! This is a library that supports the Bitcoin network protocol and associated primitives. It is //! designed for Rust programs built to work with the Bitcoin network. diff --git a/chacha20_poly1305/src/lib.rs b/chacha20_poly1305/src/lib.rs index 045a5b374c..bcd7b8cb34 100644 --- a/chacha20_poly1305/src/lib.rs +++ b/chacha20_poly1305/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # ChaCha20 - Poly1305 +//! ChaCha20 - Poly1305 //! //! Combine the ChaCha20 stream cipher with the Poly1305 message authentication code //! to form an authenticated encryption with additional data (AEAD) algorithm. diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index 1be440fab2..3421bc2240 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Fuzzing +//! Fuzzing pub mod fuzz_utils; diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index 3e8c41a6db..9258b1ad04 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin Hashes Library +//! Rust Bitcoin Hashes Library //! //! This library implements the hash functions needed by Bitcoin. As an ancillary thing, it exposes //! hexadecimal serialization and deserialization, since these are needed to display hashes. diff --git a/internals/src/lib.rs b/internals/src/lib.rs index e86dfda690..176b26f52c 100644 --- a/internals/src/lib.rs +++ b/internals/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin Internal +//! Rust Bitcoin Internal //! //! This crate is only meant to be used internally by crates in the //! [rust-bitcoin](https://github.com/rust-bitcoin) ecosystem. diff --git a/io/src/lib.rs b/io/src/lib.rs index 7e2bbb4427..0f4c27db2c 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin I/O Library +//! Rust Bitcoin I/O Library //! //! The [`std::io`] module is not exposed in `no-std` Rust so building `no-std` applications which //! require reading and writing objects via standard traits is not generally possible. Thus, this diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index aff12e7d44..1c7653ab50 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin Peer to Peer Message Types +//! Rust Bitcoin Peer to Peer Message Types // Experimental features we need. #![cfg_attr(docsrs, feature(doc_auto_cfg))] diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index c2e1072f92..5eab0d5155 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin - primitive types +//! Rust Bitcoin - primitive types //! //! Primitive data types that are used throughout the [`rust-bitcoin`] ecosystem. //! diff --git a/units/src/lib.rs b/units/src/lib.rs index b10e1a3b36..7e2acbe815 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: CC0-1.0 -//! # Rust Bitcoin - unit types +//! Rust Bitcoin - unit types //! //! This library provides basic types used by the Rust Bitcoin ecosystem. //! From cb978697ef039d8ff87a8d2a4b7f80e6eea59eaf Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sat, 2 Aug 2025 09:08:51 +1000 Subject: [PATCH 218/857] Update the API files Another PR slipped in before the check-api came into effect. Update the API files so CI is green again. --- api/units/all-features.txt | 1 + api/units/alloc-only.txt | 1 + api/units/no-features.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/api/units/all-features.txt b/api/units/all-features.txt index 67b20afebc..eef11f0cc5 100644 --- a/api/units/all-features.txt +++ b/api/units/all-features.txt @@ -1594,6 +1594,7 @@ pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::signed_sub(self, rhs: bitcoin_units::Amount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output diff --git a/api/units/alloc-only.txt b/api/units/alloc-only.txt index 8bcfde5461..ffc92bcf53 100644 --- a/api/units/alloc-only.txt +++ b/api/units/alloc-only.txt @@ -1515,6 +1515,7 @@ pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::signed_sub(self, rhs: bitcoin_units::Amount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output diff --git a/api/units/no-features.txt b/api/units/no-features.txt index a7362c7bc6..d800c7fc35 100644 --- a/api/units/no-features.txt +++ b/api/units/no-features.txt @@ -1489,6 +1489,7 @@ pub fn bitcoin_units::Amount::mul(self, rhs: u64) -> Self::Output pub fn bitcoin_units::Amount::partial_cmp(&self, other: &bitcoin_units::Amount) -> core::option::Option pub fn bitcoin_units::Amount::rem(self, modulus: u64) -> Self::Output pub fn bitcoin_units::Amount::rem(self, rhs: &u64) -> Self::Output +pub fn bitcoin_units::Amount::signed_sub(self, rhs: bitcoin_units::Amount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::Amount) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: &bitcoin_units::NumOpResult) -> Self::Output pub fn bitcoin_units::Amount::sub(self, rhs: bitcoin_units::Amount) -> Self::Output From f37c4ccbea144c705d12685e15f6648631a92c04 Mon Sep 17 00:00:00 2001 From: Update cargo-semver-checks Bot Date: Sat, 2 Aug 2025 01:20:39 +0000 Subject: [PATCH 219/857] Automated update to Github CI to cargo-semver-checks version-0.42.0 --- .github/workflows/cargo-semver-checks-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cargo-semver-checks-version b/.github/workflows/cargo-semver-checks-version index 72a8a6313b..787ffc30a8 100644 --- a/.github/workflows/cargo-semver-checks-version +++ b/.github/workflows/cargo-semver-checks-version @@ -1 +1 @@ -0.41.0 +0.42.0 From 00e474513bed44577cbb73f9da1f1afef8121fa6 Mon Sep 17 00:00:00 2001 From: Jakub Gladysz Date: Thu, 31 Jul 2025 16:26:42 +0200 Subject: [PATCH 220/857] Add const_casts module Replaces unclear `as` casts with explicit const functions that include platform-specific overflow checks to prevent silent data loss. Resolves: #4581 --- bitcoin/src/blockdata/transaction.rs | 4 ++-- internals/src/const_casts.rs | 26 ++++++++++++++++++++++++++ internals/src/lib.rs | 1 + units/src/amount/signed.rs | 3 ++- units/src/amount/unsigned.rs | 5 +++-- units/src/fee_rate/mod.rs | 7 ++++--- units/src/locktime/relative/mod.rs | 3 ++- units/src/weight.rs | 2 +- 8 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 internals/src/const_casts.rs diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 9fedd4b181..426abd4235 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -15,7 +15,7 @@ use core::fmt; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; use hashes::sha256d; -use internals::{compact_size, write_err, ToU64}; +use internals::{compact_size, const_casts, write_err, ToU64}; use io::{BufRead, Write}; use primitives::Sequence; @@ -1147,7 +1147,7 @@ impl InputWeightPrediction { /// See also [`InputWeightPrediction::total_weight`] pub const fn witness_weight(&self) -> Weight { let wu = self.script_size * 4 + self.witness_size; - let wu = wu as u64; // Can't use `ToU64` in const context. + let wu = const_casts::u32_to_u64(wu); Weight::from_wu(wu) } } diff --git a/internals/src/const_casts.rs b/internals/src/const_casts.rs new file mode 100644 index 0000000000..6e38dd031d --- /dev/null +++ b/internals/src/const_casts.rs @@ -0,0 +1,26 @@ +//! Const-compatible integer casting functions. +//! +//! This module provides explicit, const-compatible functions for integer type conversions +//! that would normally be done using the [`Into`] trait. Since trait methods cannot be used +//! in `const` contexts, these functions serve as alternatives that make conversion intent +//! clear while maintaining compile-time evaluation capabilities. + +/// Converts `u16` to `u64` +pub const fn u16_to_u64(value: u16) -> u64 { + value as u64 +} + +/// Converts `u32` to `u64` +pub const fn u32_to_u64(value: u32) -> u64 { + value as u64 +} + +/// Converts `i16` to `i64` +pub const fn i16_to_i64(value: i16) -> i64 { + value as i64 +} + +/// Converts `u16` to `u32` +pub const fn u16_to_u32(value: u16) -> u32 { + value as u32 +} \ No newline at end of file diff --git a/internals/src/lib.rs b/internals/src/lib.rs index e86dfda690..bbe287118c 100644 --- a/internals/src/lib.rs +++ b/internals/src/lib.rs @@ -55,6 +55,7 @@ pub mod wrap_debug; #[cfg(feature = "serde")] #[macro_use] pub mod serde; +pub mod const_casts; /// A conversion trait for unsigned integer types smaller than or equal to 64-bits. /// diff --git a/units/src/amount/signed.rs b/units/src/amount/signed.rs index 694f1a3c69..9377d1e872 100644 --- a/units/src/amount/signed.rs +++ b/units/src/amount/signed.rs @@ -95,6 +95,7 @@ mod encapsulate { } #[doc(inline)] pub use encapsulate::SignedAmount; +use internals::const_casts; impl SignedAmount { /// The zero amount. @@ -152,7 +153,7 @@ impl SignedAmount { /// in const context. #[allow(clippy::missing_panics_doc)] pub const fn from_btc_i16(whole_bitcoin: i16) -> Self { - let btc = whole_bitcoin as i64; // Can't call `into` in const context. + let btc = const_casts::i16_to_i64(whole_bitcoin); let sats = btc * 100_000_000; match Self::from_sat(sats) { diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 125e693ead..0f0ad9a927 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -17,6 +17,7 @@ use super::{ OutOfRangeError, ParseAmountError, ParseError, SignedAmount, }; use crate::{FeeRate, MathOp, NumOpError as E, NumOpResult, Weight}; +use internals::const_casts; mod encapsulate { use super::OutOfRangeError; @@ -116,7 +117,7 @@ impl Amount { /// represent roughly 0 to 42.95 BTC. #[allow(clippy::missing_panics_doc)] pub const fn from_sat_u32(satoshi: u32) -> Self { - let sats = satoshi as u64; // cannot use i64::from in a constfn + let sats = const_casts::u32_to_u64(satoshi); match Self::from_sat(sats) { Ok(amount) => amount, Err(_) => panic!("unreachable - 65,536 BTC is within range"), @@ -154,7 +155,7 @@ impl Amount { /// in const context. #[allow(clippy::missing_panics_doc)] pub const fn from_btc_u16(whole_bitcoin: u16) -> Self { - let btc = whole_bitcoin as u64; // Can't call `into` in const context. + let btc = const_casts::u16_to_u64(whole_bitcoin); let sats = btc * 100_000_000; match Self::from_sat(sats) { diff --git a/units/src/fee_rate/mod.rs b/units/src/fee_rate/mod.rs index 0403ce90e5..9c406c6e56 100644 --- a/units/src/fee_rate/mod.rs +++ b/units/src/fee_rate/mod.rs @@ -32,6 +32,7 @@ mod encapsulate { } #[doc(inline)] pub use encapsulate::FeeRate; +use internals::const_casts; impl FeeRate { /// The zero fee rate. @@ -57,7 +58,7 @@ impl FeeRate { /// Constructs a new [`FeeRate`] from satoshis per 1000 weight units. pub const fn from_sat_per_kwu(sat_kwu: u32) -> Self { - let fee_rate = (sat_kwu as u64) * 4_000; // No `Into` in const context. + let fee_rate = (const_casts::u32_to_u64(sat_kwu)) * 4_000; FeeRate::from_sat_per_mvb(fee_rate) } @@ -72,7 +73,7 @@ impl FeeRate { /// Constructs a new [`FeeRate`] from satoshis per virtual byte. pub const fn from_sat_per_vb(sat_vb: u32) -> Self { - let fee_rate = (sat_vb as u64) * 1_000_000; // No `Into` in const context. + let fee_rate = (const_casts::u32_to_u64(sat_vb)) * 1_000_000; FeeRate::from_sat_per_mvb(fee_rate) } @@ -87,7 +88,7 @@ impl FeeRate { /// Constructs a new [`FeeRate`] from satoshis per kilo virtual bytes (1,000 vbytes). pub const fn from_sat_per_kvb(sat_kvb: u32) -> Self { - let fee_rate = (sat_kvb as u64) * 1_000; // No `Into` in const context. + let fee_rate = (const_casts::u32_to_u64(sat_kvb)) * 1_000; FeeRate::from_sat_per_mvb(fee_rate) } diff --git a/units/src/locktime/relative/mod.rs b/units/src/locktime/relative/mod.rs index 81395783b2..0e653d012d 100644 --- a/units/src/locktime/relative/mod.rs +++ b/units/src/locktime/relative/mod.rs @@ -12,6 +12,7 @@ use core::{convert, fmt}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; +use internals::const_casts; #[cfg(doc)] use crate::relative; @@ -547,7 +548,7 @@ impl NumberOf512Seconds { /// Represents the [`NumberOf512Seconds`] as an integer number of seconds. #[inline] pub const fn to_seconds(self) -> u32 { - self.0 as u32 * 512 // u16->u32 cast ok, const context + const_casts::u16_to_u32(self.0) * 512 } /// Returns the inner `u16` value. diff --git a/units/src/weight.rs b/units/src/weight.rs index 800e4dcf99..e450978bdc 100644 --- a/units/src/weight.rs +++ b/units/src/weight.rs @@ -51,7 +51,7 @@ impl Weight { pub const MAX: Weight = Weight::from_wu(u64::MAX); /// The factor that non-witness serialization data is multiplied by during weight calculation. - pub const WITNESS_SCALE_FACTOR: u64 = WITNESS_SCALE_FACTOR as u64; + pub const WITNESS_SCALE_FACTOR: u64 = WITNESS_SCALE_FACTOR as u64; // this value is 4 /// The maximum allowed weight for a block, see BIP 141 (network rule). pub const MAX_BLOCK: Weight = Weight::from_wu(4_000_000); From 7be9dc8d65d68de759b57b73b871112de9556c74 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Mon, 28 Jul 2025 10:36:43 +0100 Subject: [PATCH 221/857] p2p: Stop assuming the protocol version The `crate::PROTOCOL_VERSION` is used implicitly in a few places. Presumably this is for convenience, but this may lead to unexpected results if the user advertises a particular protocol version then implicitly uses a lower version when requesting blocks/headers etc. I am not seeing the pain in providing the version explicitly as a user. --- p2p/examples/handshake.rs | 4 ++++ p2p/src/message.rs | 18 ++++++++++-------- p2p/src/message_blockdata.rs | 14 -------------- p2p/src/message_network.rs | 3 ++- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/p2p/examples/handshake.rs b/p2p/examples/handshake.rs index ad91945974..d60eeb61bd 100644 --- a/p2p/examples/handshake.rs +++ b/p2p/examples/handshake.rs @@ -69,6 +69,9 @@ fn build_version_message(address: SocketAddr) -> message::NetworkMessage { // Building version message, see https://en.bitcoin.it/wiki/Protocol_documentation#version let my_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0); + // The version of the p2p protocol this client will use + let protocol_version = 70001; + // "bitfield of features to be enabled for this connection" let services = ServiceFlags::NONE; @@ -93,6 +96,7 @@ fn build_version_message(address: SocketAddr) -> message::NetworkMessage { // Construct the message message::NetworkMessage::Version(message_network::VersionMessage::new( + protocol_version, services, timestamp as i64, addr_recv, diff --git a/p2p/src/message.rs b/p2p/src/message.rs index eec50752fb..ac6422caf5 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -793,20 +793,22 @@ mod test { Txid::from_byte_array(hash([45u8; 32]).to_byte_array()), )])), NetworkMessage::NotFound(InventoryPayload(vec![Inventory::Error([0u8; 32])])), - NetworkMessage::GetBlocks(GetBlocksMessage::new( - vec![ + NetworkMessage::GetBlocks(GetBlocksMessage { + version: 70001, + locator_hashes: vec![ BlockHash::from_byte_array(hash([1u8; 32]).to_byte_array()), BlockHash::from_byte_array(hash([4u8; 32]).to_byte_array()), ], - BlockHash::from_byte_array(hash([5u8; 32]).to_byte_array()), - )), - NetworkMessage::GetHeaders(GetHeadersMessage::new( - vec![ + stop_hash: BlockHash::from_byte_array(hash([5u8; 32]).to_byte_array()), + }), + NetworkMessage::GetHeaders(GetHeadersMessage { + version: 70001, + locator_hashes: vec![ BlockHash::from_byte_array(hash([10u8; 32]).to_byte_array()), BlockHash::from_byte_array(hash([40u8; 32]).to_byte_array()), ], - BlockHash::from_byte_array(hash([50u8; 32]).to_byte_array()), - )), + stop_hash: BlockHash::from_byte_array(hash([50u8; 32]).to_byte_array()), + }), NetworkMessage::MemPool, NetworkMessage::Tx(tx), NetworkMessage::Block(block), diff --git a/p2p/src/message_blockdata.rs b/p2p/src/message_blockdata.rs index bf010593c5..a5020ae1f1 100644 --- a/p2p/src/message_blockdata.rs +++ b/p2p/src/message_blockdata.rs @@ -123,22 +123,8 @@ pub struct GetHeadersMessage { pub stop_hash: BlockHash, } -impl GetBlocksMessage { - /// Construct a new `getblocks` message - pub fn new(locator_hashes: Vec, stop_hash: BlockHash) -> GetBlocksMessage { - GetBlocksMessage { version: crate::PROTOCOL_VERSION, locator_hashes, stop_hash } - } -} - impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash); -impl GetHeadersMessage { - /// Construct a new `getheaders` message - pub fn new(locator_hashes: Vec, stop_hash: BlockHash) -> GetHeadersMessage { - GetHeadersMessage { version: crate::PROTOCOL_VERSION, locator_hashes, stop_hash } - } -} - impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash); #[cfg(test)] diff --git a/p2p/src/message_network.rs b/p2p/src/message_network.rs index f8f240a5dc..c18d89d510 100644 --- a/p2p/src/message_network.rs +++ b/p2p/src/message_network.rs @@ -51,6 +51,7 @@ pub struct VersionMessage { impl VersionMessage { /// Constructs a new `version` message with `relay` set to false pub fn new( + version: u32, services: ServiceFlags, timestamp: i64, receiver: Address, @@ -60,7 +61,7 @@ impl VersionMessage { start_height: i32, ) -> VersionMessage { VersionMessage { - version: crate::PROTOCOL_VERSION, + version, services, timestamp, receiver, From 4c7fe55258ad5e2f0dcba993cb1a5ae33658a735 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Mon, 28 Jul 2025 10:48:10 +0100 Subject: [PATCH 222/857] p2p: Add a `ProtocolVersion` with named values Protocol versions should be comparable by name when considering if we would like to maintain a connection or not. For instance it is nice to be able to say "reject all connections below this feature". It is also nice to know you aren't sending some nonsense version (e.g. 70071) because of a typo. --- p2p/examples/handshake.rs | 6 +++-- p2p/src/lib.rs | 49 ++++++++++++++++++++++++++++++++++-- p2p/src/message.rs | 12 ++++----- p2p/src/message_blockdata.rs | 9 ++++--- p2p/src/message_network.rs | 8 +++--- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/p2p/examples/handshake.rs b/p2p/examples/handshake.rs index d60eeb61bd..5d6469a47e 100644 --- a/p2p/examples/handshake.rs +++ b/p2p/examples/handshake.rs @@ -4,7 +4,9 @@ use std::time::{SystemTime, UNIX_EPOCH}; use std::{env, process}; use bitcoin::consensus::{encode, Decodable}; -use bitcoin_p2p_messages::{self, address, message, message_network, Magic, ServiceFlags}; +use bitcoin_p2p_messages::{ + self, address, message, message_network, Magic, ProtocolVersion, ServiceFlags, +}; fn main() { // This example establishes a connection to a Bitcoin node, sends the initial @@ -70,7 +72,7 @@ fn build_version_message(address: SocketAddr) -> message::NetworkMessage { let my_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0); // The version of the p2p protocol this client will use - let protocol_version = 70001; + let protocol_version = ProtocolVersion::BIP0031_VERSION; // "bitfield of features to be enabled for this connection" let services = ServiceFlags::NONE; diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index 1c7653ab50..08c2fa3a8c 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -41,7 +41,7 @@ use io::{BufRead, Write}; #[doc(inline)] pub use self::{address::Address, network_ext::NetworkExt}; -/// Version of the protocol as appearing in network message headers. +/// Version of the protocol as appearing in network version handshakes and some message headers. /// /// This constant is used to signal to other peers which features you support. Increasing it implies /// that your software also supports every feature prior to this version. Doing so without support @@ -58,7 +58,52 @@ pub use self::{address::Address, network_ext::NetworkExt}; /// 70001 - Support bloom filter messages `filterload`, `filterclear` `filteradd`, `merkleblock` and FILTERED_BLOCK inventory type /// 60002 - Support `mempool` message /// 60001 - Support `pong` message and nonce in `ping` message -pub const PROTOCOL_VERSION: u32 = 70001; +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ProtocolVersion(u32); + +impl ProtocolVersion { + /// Support receiving `wtxidrelay` message between `version` and `verack` message + pub const WTXID_RELAY_VERSION: ProtocolVersion = ProtocolVersion(70016); + /// Support receiving invalid compact blocks from a peer without banning them + pub const INVALID_CB_NO_BAN_VERSION: ProtocolVersion = ProtocolVersion(70015); + /// Support compact block messages `sendcmpct`, `cmpctblock`, `getblocktxn` and `blocktxn` + pub const SHORT_IDS_BLOCKS_VERSION: ProtocolVersion = ProtocolVersion(70014); + /// Support `feefilter` message + pub const FEEFILTER_VERSION: ProtocolVersion = ProtocolVersion(70013); + /// Support `sendheaders` message and announce new blocks via headers rather than inv + pub const SENDHEADERS_VERSION: ProtocolVersion = ProtocolVersion(70012); + /// Support `pong` message and nonce in `ping` message + pub const BIP0031_VERSION: ProtocolVersion = ProtocolVersion(60000); + /// All connections will be terminated below this version. + pub const MIN_PEER_PROTO_VERSION: ProtocolVersion = ProtocolVersion(31800); +} + +impl ProtocolVersion { + /// Construct a protocol version that is not well-known. + pub fn from_nonstandard(version: u32) -> Self { + Self(version) + } +} + +impl From for u32 { + fn from(version: ProtocolVersion) -> Self { + version.0 + } +} + +impl Encodable for ProtocolVersion { + #[inline] + fn consensus_encode(&self, w: &mut W) -> Result { + self.0.consensus_encode(w) + } +} + +impl Decodable for ProtocolVersion { + #[inline] + fn consensus_decode(r: &mut R) -> Result { + Ok(ProtocolVersion(Decodable::consensus_decode(r)?)) + } +} /// Flags to indicate which network services a node supports. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/p2p/src/message.rs b/p2p/src/message.rs index ac6422caf5..429e982eaa 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -763,7 +763,7 @@ mod test { CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters, }; use crate::message_network::{Alert, Reject, RejectReason, VersionMessage}; - use crate::ServiceFlags; + use crate::{ProtocolVersion, ServiceFlags}; fn hash(array: [u8; 32]) -> sha256d::Hash { sha256d::Hash::from_byte_array(array) } @@ -794,7 +794,7 @@ mod test { )])), NetworkMessage::NotFound(InventoryPayload(vec![Inventory::Error([0u8; 32])])), NetworkMessage::GetBlocks(GetBlocksMessage { - version: 70001, + version: ProtocolVersion::from_nonstandard(70001), locator_hashes: vec![ BlockHash::from_byte_array(hash([1u8; 32]).to_byte_array()), BlockHash::from_byte_array(hash([4u8; 32]).to_byte_array()), @@ -802,7 +802,7 @@ mod test { stop_hash: BlockHash::from_byte_array(hash([5u8; 32]).to_byte_array()), }), NetworkMessage::GetHeaders(GetHeadersMessage { - version: 70001, + version: ProtocolVersion::from_nonstandard(70001), locator_hashes: vec![ BlockHash::from_byte_array(hash([10u8; 32]).to_byte_array()), BlockHash::from_byte_array(hash([40u8; 32]).to_byte_array()), @@ -1079,7 +1079,7 @@ mod test { let msg = msg.unwrap(); assert_eq!(msg.magic, Magic::BITCOIN); if let NetworkMessage::Version(version_msg) = msg.payload { - assert_eq!(version_msg.version, 70015); + assert_eq!(version_msg.version, ProtocolVersion::INVALID_CB_NO_BAN_VERSION); assert_eq!( version_msg.services, ServiceFlags::NETWORK @@ -1117,7 +1117,7 @@ mod test { ]).unwrap(); if let NetworkMessage::Version(version_msg) = msg.payload { - assert_eq!(version_msg.version, 70015); + assert_eq!(version_msg.version, ProtocolVersion::INVALID_CB_NO_BAN_VERSION); assert_eq!( version_msg.services, ServiceFlags::NETWORK @@ -1163,7 +1163,7 @@ mod test { assert_eq!(consumed, data.to_vec().len() - 2); assert_eq!(msg.magic, Magic::BITCOIN); if let NetworkMessage::Version(version_msg) = msg.payload { - assert_eq!(version_msg.version, 70015); + assert_eq!(version_msg.version, ProtocolVersion::INVALID_CB_NO_BAN_VERSION); assert_eq!( version_msg.services, ServiceFlags::NETWORK diff --git a/p2p/src/message_blockdata.rs b/p2p/src/message_blockdata.rs index a5020ae1f1..033dd5d501 100644 --- a/p2p/src/message_blockdata.rs +++ b/p2p/src/message_blockdata.rs @@ -11,6 +11,7 @@ use bitcoin::transaction::{Txid, Wtxid}; use io::{BufRead, Write}; use crate::consensus::impl_consensus_encoding; +use crate::ProtocolVersion; /// An inventory item. #[derive(PartialEq, Eq, Clone, Debug, Copy, Hash, PartialOrd, Ord)] @@ -101,7 +102,7 @@ impl Decodable for Inventory { #[derive(PartialEq, Eq, Clone, Debug)] pub struct GetBlocksMessage { /// The protocol version - pub version: u32, + pub version: ProtocolVersion, /// Locator hashes --- ordered newest to oldest. The remote peer will /// reply with its longest known chain, starting from a locator hash /// if possible and block 1 otherwise. @@ -114,7 +115,7 @@ pub struct GetBlocksMessage { #[derive(PartialEq, Eq, Clone, Debug)] pub struct GetHeadersMessage { /// The protocol version - pub version: u32, + pub version: ProtocolVersion, /// Locator hashes --- ordered newest to oldest. The remote peer will /// reply with its longest known chain, starting from a locator hash /// if possible and block 1 otherwise. @@ -142,7 +143,7 @@ mod tests { let decode: Result = deserialize(&from_sat); assert!(decode.is_ok()); let real_decode = decode.unwrap(); - assert_eq!(real_decode.version, 70002); + assert_eq!(real_decode.version.0, 70002); assert_eq!(real_decode.locator_hashes.len(), 1); assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); assert_eq!(real_decode.stop_hash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); @@ -158,7 +159,7 @@ mod tests { let decode: Result = deserialize(&from_sat); assert!(decode.is_ok()); let real_decode = decode.unwrap(); - assert_eq!(real_decode.version, 70002); + assert_eq!(real_decode.version.0, 70002); assert_eq!(real_decode.locator_hashes.len(), 1); assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); assert_eq!(real_decode.stop_hash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); diff --git a/p2p/src/message_network.rs b/p2p/src/message_network.rs index c18d89d510..c982c7895e 100644 --- a/p2p/src/message_network.rs +++ b/p2p/src/message_network.rs @@ -12,7 +12,7 @@ use io::{BufRead, Write}; use crate::address::Address; use crate::consensus::{impl_consensus_encoding, impl_vec_wrapper}; -use crate::ServiceFlags; +use crate::{ProtocolVersion, ServiceFlags}; // Some simple messages @@ -20,7 +20,7 @@ use crate::ServiceFlags; #[derive(PartialEq, Eq, Clone, Debug)] pub struct VersionMessage { /// The P2P network protocol version - pub version: u32, + pub version: ProtocolVersion, /// A bitmask describing the services supported by this node pub services: ServiceFlags, /// The time at which the `version` message was sent @@ -51,7 +51,7 @@ pub struct VersionMessage { impl VersionMessage { /// Constructs a new `version` message with `relay` set to false pub fn new( - version: u32, + version: ProtocolVersion, services: ServiceFlags, timestamp: i64, receiver: Address, @@ -184,7 +184,7 @@ mod tests { let decode: Result = deserialize(&from_sat); assert!(decode.is_ok()); let real_decode = decode.unwrap(); - assert_eq!(real_decode.version, 70002); + assert_eq!(real_decode.version.0, 70002); assert_eq!(real_decode.services, ServiceFlags::NETWORK); assert_eq!(real_decode.timestamp, 1401217254); // address decodes should be covered by Address tests From 37d914c2792769c9d21cb280507b0b221e6db5ea Mon Sep 17 00:00:00 2001 From: yancy Date: Sat, 2 Aug 2025 06:13:22 -0500 Subject: [PATCH 223/857] Add article and lower-case docs for Parameters heading Formalize parameter docs --- bitcoin/examples/sighash.rs | 18 +++++++++--------- bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/consensus_validation.rs | 28 ++++++++++++++-------------- chacha20_poly1305/src/lib.rs | 4 ++-- hashes/src/internal_macros.rs | 6 +++--- hashes/src/macros.rs | 6 +++--- internals/src/error/parse_error.rs | 4 ++-- units/src/parse.rs | 4 ++-- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/bitcoin/examples/sighash.rs b/bitcoin/examples/sighash.rs index bd4a4e4ccb..0a3ef64e3a 100644 --- a/bitcoin/examples/sighash.rs +++ b/bitcoin/examples/sighash.rs @@ -16,9 +16,9 @@ use hex_lit::hex; /// /// # Parameters /// -/// * `raw_tx` - spending tx hex -/// * `inp_idx` - spending tx input index -/// * `amount` - ref tx output value in sats +/// * `raw_tx` - the spending tx hex +/// * `inp_idx` - the spending tx input index +/// * `amount` - the ref tx output value in sats fn compute_sighash_p2wpkh(raw_tx: &[u8], inp_idx: usize, amount: Amount) { let tx: Transaction = consensus::deserialize(raw_tx).unwrap(); let inp = &tx.input[inp_idx]; @@ -55,9 +55,9 @@ fn compute_sighash_p2wpkh(raw_tx: &[u8], inp_idx: usize, amount: Amount) { /// /// # Parameters /// -/// * `raw_tx` - spending tx hex -/// * `inp_idx` - spending tx input index -/// * `script_pubkey_bytes_opt` - Option with scriptPubKey bytes. If None, it's p2sh case, i.e., reftx output's scriptPubKey.type is "scripthash". In this case scriptPubkey is extracted from the spending transaction's scriptSig. If Some(), it's p2ms case, i.e., reftx output's scriptPubKey.type is "multisig", and the scriptPubkey is supplied from the referenced output. +/// * `raw_tx` - the spending tx hex +/// * `inp_idx` - the spending tx input index +/// * `script_pubkey_bytes_opt` - the Option with scriptPubKey bytes. If None, it's p2sh case, i.e., reftx output's scriptPubKey.type is "scripthash". In this case scriptPubkey is extracted from the spending transaction's scriptSig. If Some(), it's p2ms case, i.e., reftx output's scriptPubKey.type is "multisig", and the scriptPubkey is supplied from the referenced output. fn compute_sighash_legacy(raw_tx: &[u8], inp_idx: usize, script_pubkey_bytes_opt: Option<&[u8]>) { let tx: Transaction = consensus::deserialize(raw_tx).unwrap(); let inp = &tx.input[inp_idx]; @@ -100,9 +100,9 @@ fn compute_sighash_legacy(raw_tx: &[u8], inp_idx: usize, script_pubkey_bytes_opt /// /// # Parameters /// -/// * `raw_tx` - spending tx hex -/// * `inp_idx` - spending tx input index -/// * `amount` - ref tx output value in sats +/// * `raw_tx` - the spending tx hex +/// * `inp_idx` - the spending tx input index +/// * `amount` - the ref tx output value in sats fn compute_sighash_p2wsh(raw_tx: &[u8], inp_idx: usize, amount: Amount) { let tx: Transaction = consensus::deserialize(raw_tx).unwrap(); let inp = &tx.input[inp_idx]; diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 9fedd4b181..122158dfce 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -771,7 +771,7 @@ impl Decodable for Transaction { /// /// * `fee_rate` - the fee rate of the transaction being created. /// * `input_weight_prediction` - the predicted input weight. -/// * `value` - The value of the output we are spending. +/// * `value` - the value of the output we are spending. pub fn effective_value( fee_rate: FeeRate, input_weight_prediction: InputWeightPrediction, diff --git a/bitcoin/src/consensus_validation.rs b/bitcoin/src/consensus_validation.rs index e80994f905..0c2f6e5dce 100644 --- a/bitcoin/src/consensus_validation.rs +++ b/bitcoin/src/consensus_validation.rs @@ -24,9 +24,9 @@ use crate::transaction::{OutPoint, Transaction, TxOut}; /// /// # Parameters /// -/// * `index` - The input index in spending which is spending this transaction. -/// * `amount` - The amount this script guards. -/// * `spending_tx` - The transaction that attempts to spend the output holding this script. +/// * `index` - the input index in spending which is spending this transaction. +/// * `amount` - the amount this script guards. +/// * `spending_tx` - the transaction that attempts to spend the output holding this script. /// /// [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`]: https://docs.rs/bitcoinconsensus/0.106.0+26.0/bitcoinconsensus/constant.VERIFY_ALL_PRE_TAPROOT.html pub fn verify_script( @@ -48,10 +48,10 @@ pub fn verify_script( /// /// # Parameters /// -/// * `index` - The input index in spending which is spending this transaction. -/// * `amount` - The amount this script guards. -/// * `spending_tx` - The transaction that attempts to spend the output holding this script. -/// * `flags` - Verification flags, see [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`] and similar. +/// * `index` - the input index in spending which is spending this transaction. +/// * `amount` - the amount this script guards. +/// * `spending_tx` - the transaction that attempts to spend the output holding this script. +/// * `flags` - the verification flags, see [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`] and similar. /// /// [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`]: https://docs.rs/bitcoinconsensus/0.106.0+26.0/bitcoinconsensus/constant.VERIFY_ALL_PRE_TAPROOT.html pub fn verify_script_with_flags>( @@ -126,9 +126,9 @@ define_extension_trait! { /// /// # Parameters /// - /// * `index` - The input index in spending which is spending this transaction. - /// * `amount` - The amount this script guards. - /// * `spending_tx` - The transaction that attempts to spend the output holding this script. + /// * `index` - the input index in spending which is spending this transaction. + /// * `amount` - the amount this script guards. + /// * `spending_tx` - the transaction that attempts to spend the output holding this script. /// /// [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`]: https://docs.rs/bitcoinconsensus/0.106.0+26.0/bitcoinconsensus/constant.VERIFY_ALL_PRE_TAPROOT.html fn verify( @@ -144,10 +144,10 @@ define_extension_trait! { /// /// # Parameters /// - /// * `index` - The input index in spending which is spending this transaction. - /// * `amount` - The amount this script guards. - /// * `spending_tx` - The transaction that attempts to spend the output holding this script. - /// * `flags` - Verification flags, see [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`] and similar. + /// * `index` - the input index in spending which is spending this transaction. + /// * `amount` - the amount this script guards. + /// * `spending_tx` - the transaction that attempts to spend the output holding this script. + /// * `flags` - the verification flags, see [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`] and similar. /// /// [`bitcoinconsensus::VERIFY_ALL_PRE_TAPROOT`]: https://docs.rs/bitcoinconsensus/0.106.0+26.0/bitcoinconsensus/constant.VERIFY_ALL_PRE_TAPROOT.html fn verify_with_flags( diff --git a/chacha20_poly1305/src/lib.rs b/chacha20_poly1305/src/lib.rs index bcd7b8cb34..e8632f51c8 100644 --- a/chacha20_poly1305/src/lib.rs +++ b/chacha20_poly1305/src/lib.rs @@ -78,8 +78,8 @@ impl ChaCha20Poly1305 { /// /// # Parameters /// - /// - `content` - Plaintext to be encrypted in place. - /// - `aad` - Optional metadata covered by the authentication tag. + /// - `content` - the plaintext to be encrypted in place. + /// - `aad` - the optional metadata covered by the authentication tag. /// /// # Returns /// diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index f3d2cecfb9..998db6b2ed 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -8,10 +8,10 @@ /// /// # Parameters /// -/// * `$bits` - number of bits this hash type has +/// * `$bits` - the number of bits this hash type has /// * `$reverse` - `bool` - `true` if the hash type should be displayed backwards, `false` /// otherwise. -/// * `$gen: $gent` - generic type(s) and trait bound(s) +/// * `$gen: $gent` - the generic type(s) and trait bound(s) /// /// Restrictions on usage: /// @@ -57,7 +57,7 @@ pub(crate) use hash_trait_impls; /// /// * `$bits` - the number of bits of the hash type /// * `$reverse` - `true` if the hash should be displayed backwards, `false` otherwise -/// * `$doc` - doc string to put on the type +/// * `$doc` - the doc string to put on the type /// /// Restrictions on usage: /// diff --git a/hashes/src/macros.rs b/hashes/src/macros.rs index 283a627030..654206f8fb 100644 --- a/hashes/src/macros.rs +++ b/hashes/src/macros.rs @@ -220,9 +220,9 @@ macro_rules! impl_debug_only_for_newtype { /// /// # Parameters /// -/// * `ty` - The bytelike type to implement the traits on. -/// * `$len` - The number of bytes this type has. -/// * `$gen: $gent` - generic type(s) and trait bound(s). +/// * `ty` - the bytelike type to implement the traits on. +/// * `$len` - the number of bytes this type has. +/// * `$gen: $gent` - the generic type(s) and trait bound(s). #[doc(hidden)] #[macro_export] macro_rules! impl_bytelike_traits { diff --git a/internals/src/error/parse_error.rs b/internals/src/error/parse_error.rs index 4a26427065..542f197c67 100644 --- a/internals/src/error/parse_error.rs +++ b/internals/src/error/parse_error.rs @@ -13,8 +13,8 @@ /// /// * `name` - the name of the error type /// * `source` - the type of the source type -/// * `subject` - English description of the type being parsed (e.g. "a bitcoin amount") -/// * `derive` - list of derives to add +/// * `subject` - the english description of the type being parsed (e.g. "a bitcoin amount") +/// * `derive` - the list of derives to add #[macro_export] macro_rules! parse_error_type { ($vis:vis $name:ident, $source:ty, $subject:expr $(, $derive:path)* $(,)?) => { diff --git a/units/src/parse.rs b/units/src/parse.rs index 502a4a1e7e..c0e0e8488b 100644 --- a/units/src/parse.rs +++ b/units/src/parse.rs @@ -143,7 +143,7 @@ fn int + Into>(s: S) -> Result for $to`. /// * `err` - the error type returned by `$inner_fn` (implies returned by `FromStr` and `TryFrom`). -/// * `fn`: The infallible conversion function to call to convert from an integer. +/// * `fn`: the infallible conversion function to call to convert from an integer. /// /// # Errors /// @@ -208,7 +208,7 @@ macro_rules! impl_parse_str_from_int_infallible { /// /// * `to` - the type converted to e.g., `impl From<&str> for $to`. /// * `err` - the error type returned by `$inner_fn` (implies returned by `FromStr` and `TryFrom`). -/// * `inner_fn`: The fallible conversion function to call to convert from a string reference. +/// * `inner_fn`: the fallible conversion function to call to convert from a string reference. /// /// # Errors /// From ea4c4ebc9325e09b7fa4f43d36097bc06b6bf969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?luory=20=E2=9C=9E?= Date: Sun, 3 Aug 2025 00:24:15 +0200 Subject: [PATCH 224/857] fix minor typos --- bitcoin/src/crypto/sighash.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index a4618093a3..6647819433 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -277,7 +277,7 @@ impl std::error::Error for PrevoutsSizeError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } -/// A single prevout was been provided but all prevouts are needed without `ANYONECANPAY`. +/// A single prevout was provided but all prevouts are needed without `ANYONECANPAY`. #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] pub struct PrevoutsKindError; @@ -343,8 +343,8 @@ impl<'s> ScriptPath<'s> { self.leaf_version .to_consensus() .consensus_encode(&mut enc) - .expect("writing to hash enging should never fail"); - self.script.consensus_encode(&mut enc).expect("writing to hash enging should never fail"); + .expect("writing to hash engine should never fail"); + self.script.consensus_encode(&mut enc).expect("writing to hash engine should never fail"); let inner = sha256t::Hash::::from_engine(enc); TapLeafHash::from_byte_array(inner.to_byte_array()) From 167d0b2c07c166ebd2285cce9047269766bdad0a Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 3 Aug 2025 01:54:55 +0000 Subject: [PATCH 225/857] 2025-08-03 automated rustfmt nightly --- bitcoin/src/bip152.rs | 10 ++++++++-- bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/psbt/raw.rs | 4 ++-- p2p/src/message.rs | 9 +++++---- p2p/src/message_network.rs | 16 +++++++++------- units/src/amount/tests.rs | 20 ++++++++++---------- units/src/amount/unsigned.rs | 2 +- 7 files changed, 36 insertions(+), 27 deletions(-) diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs index d454dfd555..289c7097c3 100644 --- a/bitcoin/src/bip152.rs +++ b/bitcoin/src/bip152.rs @@ -435,14 +435,20 @@ impl<'a> Arbitrary<'a> for HeaderAndShortIds { #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for BlockTransactions { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - Ok(BlockTransactions { block_hash: u.arbitrary()?, transactions: Vec::::arbitrary(u)? }) + Ok(BlockTransactions { + block_hash: u.arbitrary()?, + transactions: Vec::::arbitrary(u)?, + }) } } #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for BlockTransactionsRequest { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - Ok(BlockTransactionsRequest { block_hash: u.arbitrary()?, indexes: Vec::::arbitrary(u)? }) + Ok(BlockTransactionsRequest { + block_hash: u.arbitrary()?, + indexes: Vec::::arbitrary(u)?, + }) } } diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index e61c06f367..70dfb17e6a 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -779,7 +779,7 @@ pub fn effective_value( ) -> SignedAmount { let weight = input_weight_prediction.total_weight(); let fee = fee_rate.to_fee(weight); - + value.signed_sub(fee) } diff --git a/bitcoin/src/psbt/raw.rs b/bitcoin/src/psbt/raw.rs index c17766e603..df8dfa8443 100644 --- a/bitcoin/src/psbt/raw.rs +++ b/bitcoin/src/psbt/raw.rs @@ -6,9 +6,9 @@ //! . use core::fmt; + #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; - use internals::ToU64 as _; use io::{BufRead, Write}; @@ -197,7 +197,7 @@ impl<'a> Arbitrary<'a> for ProprietaryKey { Ok(ProprietaryKey { prefix: Vec::::arbitrary(u)?, subtype: u64::arbitrary(u)?, - key: Vec::::arbitrary(u)? + key: Vec::::arbitrary(u)?, }) } } diff --git a/p2p/src/message.rs b/p2p/src/message.rs index eec50752fb..953b69f933 100644 --- a/p2p/src/message.rs +++ b/p2p/src/message.rs @@ -439,7 +439,8 @@ impl Encodable for NetworkMessage { NetworkMessage::BlockTxn(ref dat) => dat.consensus_encode(writer), NetworkMessage::Alert(ref dat) => dat.consensus_encode(writer), NetworkMessage::Reject(ref dat) => dat.consensus_encode(writer), - NetworkMessage::FeeFilter(ref dat) => dat.to_sat_per_kvb_ceil().consensus_encode(writer), + NetworkMessage::FeeFilter(ref dat) => + dat.to_sat_per_kvb_ceil().consensus_encode(writer), NetworkMessage::AddrV2(ref dat) => dat.consensus_encode(writer), NetworkMessage::Verack | NetworkMessage::SendHeaders @@ -631,9 +632,9 @@ impl Decodable for RawNetworkMessage { .ok() // Given some absurdly large value, using the maximum conveys that no // transactions should be relayed to this peer. - .map_or(FeeRate::MAX, FeeRate::from_sat_per_kvb) + .map_or(FeeRate::MAX, FeeRate::from_sat_per_kvb), ) - }, + } "sendcmpct" => NetworkMessage::SendCmpct( Decodable::consensus_decode_from_finite_reader(&mut mem_d)?, ), @@ -698,7 +699,7 @@ impl Decodable for V2NetworkMessage { .ok() // Given some absurdly large value, using the maximum conveys that no // transactions should be relayed to this peer. - .map_or(FeeRate::MAX, FeeRate::from_sat_per_kvb) + .map_or(FeeRate::MAX, FeeRate::from_sat_per_kvb), ), 6u8 => NetworkMessage::FilterAdd(Decodable::consensus_decode_from_finite_reader(r)?), 7u8 => NetworkMessage::FilterClear, diff --git a/p2p/src/message_network.rs b/p2p/src/message_network.rs index f8f240a5dc..90ff6aec3d 100644 --- a/p2p/src/message_network.rs +++ b/p2p/src/message_network.rs @@ -152,18 +152,20 @@ impl_consensus_encoding!(Reject, message, ccode, reason, hash); pub struct Alert(Vec); impl Alert { - const FINAL_ALERT: [u8; 96] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0]; + const FINAL_ALERT: [u8; 96] = [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, + 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, + 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, + 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, + 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0, + ]; /// Build the final alert to send to a potentially vulnerable peer. - pub fn final_alert() -> Self { - Self(Self::FINAL_ALERT.into()) - } + pub fn final_alert() -> Self { Self(Self::FINAL_ALERT.into()) } /// The final alert advertised by Bitcoin Core. This alert is sent if the advertised protocol /// version is vulnerable to the alert-system vulerablities. - pub fn is_final_alert(&self) -> bool { - self.0.eq(&Self::FINAL_ALERT) - } + pub fn is_final_alert(&self) -> bool { self.0.eq(&Self::FINAL_ALERT) } } impl_vec_wrapper!(Alert, Vec); diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index 4daf35f7a6..b2a3993ca6 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -1337,41 +1337,41 @@ fn signed_sub() { // Test the core feature: cannot overflow unlike regular subtraction let small = sat(100); let large = sat(1000); - + // Regular checked_sub would fail (returns None) for small - large assert_eq!(small.checked_sub(large), None); - + // But signed_sub works - this is the key feature! let result = small.signed_sub(large); assert_eq!(result.to_sat(), -900); assert!(result.is_negative()); - + // Test positive result let result2 = large.signed_sub(small); assert_eq!(result2.to_sat(), 900); assert!(result2.is_positive()); - + // Test zero result let result3 = large.signed_sub(large); assert_eq!(result3.to_sat(), 0); - + // Test edge cases with maximum amounts let max_diff = Amount::MAX.signed_sub(Amount::ZERO); assert_eq!(max_diff.to_sat(), Amount::MAX.to_sat() as i64); - + let min_diff = Amount::ZERO.signed_sub(Amount::MAX); assert_eq!(min_diff.to_sat(), -(Amount::MAX.to_sat() as i64)); - + // Any two valid amounts will always produce a valid SignedAmount // This demonstrates the "cannot overflow" property let amt1 = Amount::MAX_MONEY; let amt2 = sat(1); - + let diff1 = amt1.signed_sub(amt2); let diff2 = amt2.signed_sub(amt1); - + assert!(diff1.is_positive()); assert!(diff2.is_negative()); assert_eq!(diff1.to_sat(), (Amount::MAX_MONEY.to_sat() - 1) as i64); assert_eq!(diff2.to_sat(), -((Amount::MAX_MONEY.to_sat() - 1) as i64)); -} \ No newline at end of file +} diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index 125e693ead..37c17414a2 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -405,7 +405,7 @@ impl Amount { SignedAmount::from_sat(self.to_sat() as i64) // Cast ok, signed amount and amount share positive range. .expect("range of Amount is within range of SignedAmount") } - + /// Infallibly subtracts one `Amount` from another returning a [`SignedAmount`]. /// /// Since `SignedAmount::MIN` is equivalent to `-Amount::MAX` subtraction of two signed amounts From 6515c22674122f7ac8e9920ef767e8b3f212d549 Mon Sep 17 00:00:00 2001 From: Gengar Date: Sun, 3 Aug 2025 18:05:12 +0300 Subject: [PATCH 226/857] Update owned.rs --- primitives/src/script/owned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/script/owned.rs b/primitives/src/script/owned.rs index c350b02f3e..783298db7c 100644 --- a/primitives/src/script/owned.rs +++ b/primitives/src/script/owned.rs @@ -19,7 +19,7 @@ use crate::prelude::{Box, Vec}; /// # Hexadecimal strings /// /// Scripts are consensus encoded with a length prefix and as a result of this in some places in the -/// eccosystem one will encounter hex strings that include the prefix while in other places the +/// ecosystem one will encounter hex strings that include the prefix while in other places the /// prefix is excluded. To support parsing and formatting scripts as hex we provide a bunch of /// different APIs and trait implementations. Please see [`examples/script.rs`] for a thorough /// example of all the APIs. From a151c62fd3b3ff533e2884a955c33b308c74d8d8 Mon Sep 17 00:00:00 2001 From: Gengar Date: Sun, 3 Aug 2025 18:06:29 +0300 Subject: [PATCH 227/857] Update mod.rs --- primitives/src/script/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs index 0e656fcc84..c71f727e72 100644 --- a/primitives/src/script/mod.rs +++ b/primitives/src/script/mod.rs @@ -246,7 +246,7 @@ impl<'a> From> for ScriptBuf { fn from(value: Cow<'a, Script>) -> Self { match value { Cow::Owned(owned) => owned, - Cow::Borrowed(borrwed) => borrwed.into(), + Cow::Borrowed(borrowed) => borrowed.into(), } } } @@ -256,7 +256,7 @@ impl<'a> From> for Box