diff --git a/api/units/all-features.txt b/api/units/all-features.txt index 6217193eb..0024bfd51 100644 --- a/api/units/all-features.txt +++ b/api/units/all-features.txt @@ -145,6 +145,7 @@ impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::Height impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::Time impl core::cmp::PartialOrd for bitcoin_units::weight::Weight impl core::convert::AsRef for bitcoin_units::parse::ParseIntError +impl core::convert::From for bitcoin_units::SignedAmount 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 @@ -198,7 +199,6 @@ impl core::convert::TryFrom for bitcoin_units::locktime:: impl core::convert::TryFrom for bitcoin_units::locktime::relative::Height impl core::convert::TryFrom for bitcoin_units::locktime::relative::Time impl core::convert::TryFrom for bitcoin_units::weight::Weight -impl core::convert::TryFrom for bitcoin_units::SignedAmount 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::Height @@ -723,6 +723,7 @@ pub const fn bitcoin_units::SignedAmount::checked_rem(self, rhs: i64) -> core::o pub const fn bitcoin_units::SignedAmount::checked_sub(self, rhs: bitcoin_units::SignedAmount) -> core::option::Option pub const fn bitcoin_units::SignedAmount::from_int_btc_const(whole_bitcoin: i64) -> bitcoin_units::SignedAmount pub const fn bitcoin_units::SignedAmount::from_sat(satoshi: i64) -> bitcoin_units::SignedAmount +pub const fn bitcoin_units::SignedAmount::from_sat_unchecked(satoshi: i64) -> bitcoin_units::SignedAmount pub const fn bitcoin_units::SignedAmount::to_sat(self) -> i64 pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 @@ -830,7 +831,7 @@ pub fn bitcoin_units::Amount::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator 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) -> core::result::Result +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 @@ -855,6 +856,7 @@ pub fn bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output pub fn bitcoin_units::SignedAmount::div_assign(&mut self, rhs: i64) 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) -> core::result::Result @@ -889,7 +891,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::try_from(value: bitcoin_units::Amount) -> core::result::Result pub fn bitcoin_units::SignedAmount::type_prefix(_: private::Token) -> &'static str pub fn bitcoin_units::SignedAmount::unchecked_add(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::SignedAmount::unchecked_sub(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount @@ -1254,7 +1255,6 @@ pub type bitcoin_units::Amount::Error = bitcoin_units::amount::OutOfRangeError pub type bitcoin_units::Amount::Output = bitcoin_units::Amount pub type bitcoin_units::Amount::Output = bitcoin_units::fee_rate::FeeRate pub type bitcoin_units::SignedAmount::Err = bitcoin_units::amount::ParseError -pub type bitcoin_units::SignedAmount::Error = bitcoin_units::amount::OutOfRangeError pub type bitcoin_units::SignedAmount::Output = bitcoin_units::SignedAmount pub type bitcoin_units::amount::Denomination::Err = bitcoin_units::amount::ParseDenominationError pub type bitcoin_units::block::BlockHeight::Err = bitcoin_units::parse::ParseIntError diff --git a/api/units/alloc-only.txt b/api/units/alloc-only.txt index 13e5cb270..79871eefc 100644 --- a/api/units/alloc-only.txt +++ b/api/units/alloc-only.txt @@ -141,6 +141,7 @@ impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::Height impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::Time impl core::cmp::PartialOrd for bitcoin_units::weight::Weight impl core::convert::AsRef for bitcoin_units::parse::ParseIntError +impl core::convert::From for bitcoin_units::SignedAmount 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 @@ -194,7 +195,6 @@ impl core::convert::TryFrom for bitcoin_units::locktime:: impl core::convert::TryFrom for bitcoin_units::locktime::relative::Height impl core::convert::TryFrom for bitcoin_units::locktime::relative::Time impl core::convert::TryFrom for bitcoin_units::weight::Weight -impl core::convert::TryFrom for bitcoin_units::SignedAmount 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::Height @@ -674,6 +674,7 @@ pub const fn bitcoin_units::SignedAmount::checked_rem(self, rhs: i64) -> core::o pub const fn bitcoin_units::SignedAmount::checked_sub(self, rhs: bitcoin_units::SignedAmount) -> core::option::Option pub const fn bitcoin_units::SignedAmount::from_int_btc_const(whole_bitcoin: i64) -> bitcoin_units::SignedAmount pub const fn bitcoin_units::SignedAmount::from_sat(satoshi: i64) -> bitcoin_units::SignedAmount +pub const fn bitcoin_units::SignedAmount::from_sat_unchecked(satoshi: i64) -> bitcoin_units::SignedAmount pub const fn bitcoin_units::SignedAmount::to_sat(self) -> i64 pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 @@ -771,7 +772,7 @@ pub fn bitcoin_units::Amount::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator 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) -> core::result::Result +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 @@ -791,6 +792,7 @@ pub fn bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output pub fn bitcoin_units::SignedAmount::div_assign(&mut self, rhs: i64) 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) -> core::result::Result @@ -819,7 +821,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::try_from(value: bitcoin_units::Amount) -> core::result::Result pub fn bitcoin_units::SignedAmount::unchecked_add(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::SignedAmount::unchecked_sub(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount @@ -1116,7 +1117,6 @@ pub type bitcoin_units::Amount::Error = bitcoin_units::amount::OutOfRangeError pub type bitcoin_units::Amount::Output = bitcoin_units::Amount pub type bitcoin_units::Amount::Output = bitcoin_units::fee_rate::FeeRate pub type bitcoin_units::SignedAmount::Err = bitcoin_units::amount::ParseError -pub type bitcoin_units::SignedAmount::Error = bitcoin_units::amount::OutOfRangeError pub type bitcoin_units::SignedAmount::Output = bitcoin_units::SignedAmount pub type bitcoin_units::amount::Denomination::Err = bitcoin_units::amount::ParseDenominationError pub type bitcoin_units::block::BlockHeight::Err = bitcoin_units::parse::ParseIntError diff --git a/api/units/no-features.txt b/api/units/no-features.txt index 17a93af28..48178dccc 100644 --- a/api/units/no-features.txt +++ b/api/units/no-features.txt @@ -141,6 +141,7 @@ impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::Height impl core::cmp::PartialOrd for bitcoin_units::locktime::relative::Time impl core::cmp::PartialOrd for bitcoin_units::weight::Weight impl core::convert::AsRef for bitcoin_units::parse::ParseIntError +impl core::convert::From for bitcoin_units::SignedAmount 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 @@ -178,7 +179,6 @@ impl core::convert::TryFrom<&str> for bitcoin_units::locktime::absolute::Time impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::Height impl core::convert::TryFrom<&str> for bitcoin_units::locktime::relative::Time impl core::convert::TryFrom<&str> for bitcoin_units::weight::Weight -impl core::convert::TryFrom for bitcoin_units::SignedAmount 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::Height @@ -656,6 +656,7 @@ pub const fn bitcoin_units::SignedAmount::checked_rem(self, rhs: i64) -> core::o pub const fn bitcoin_units::SignedAmount::checked_sub(self, rhs: bitcoin_units::SignedAmount) -> core::option::Option pub const fn bitcoin_units::SignedAmount::from_int_btc_const(whole_bitcoin: i64) -> bitcoin_units::SignedAmount pub const fn bitcoin_units::SignedAmount::from_sat(satoshi: i64) -> bitcoin_units::SignedAmount +pub const fn bitcoin_units::SignedAmount::from_sat_unchecked(satoshi: i64) -> bitcoin_units::SignedAmount pub const fn bitcoin_units::SignedAmount::to_sat(self) -> i64 pub const fn bitcoin_units::block::BlockHeight::from_u32(inner: u32) -> Self pub const fn bitcoin_units::block::BlockHeight::to_u32(self) -> u32 @@ -749,7 +750,7 @@ pub fn bitcoin_units::Amount::sub_assign(&mut self, rhs: &bitcoin_units::Amount) pub fn bitcoin_units::Amount::sub_assign(&mut self, rhs: bitcoin_units::Amount) pub fn bitcoin_units::Amount::sum>(iter: I) -> Self pub fn bitcoin_units::Amount::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator -pub fn bitcoin_units::Amount::to_signed(self) -> core::result::Result +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::Amount::unchecked_add(self, rhs: bitcoin_units::Amount) -> bitcoin_units::Amount pub fn bitcoin_units::Amount::unchecked_sub(self, rhs: bitcoin_units::Amount) -> bitcoin_units::Amount @@ -767,6 +768,7 @@ pub fn bitcoin_units::SignedAmount::div(self, rhs: i64) -> Self::Output pub fn bitcoin_units::SignedAmount::div_assign(&mut self, rhs: i64) 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) -> core::result::Result 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 @@ -789,7 +791,6 @@ pub fn bitcoin_units::SignedAmount::sub_assign(&mut self, rhs: bitcoin_units::Si pub fn bitcoin_units::SignedAmount::sum>(iter: I) -> Self pub fn bitcoin_units::SignedAmount::sum(iter: I) -> Self where I: core::iter::traits::iterator::Iterator pub fn bitcoin_units::SignedAmount::to_unsigned(self) -> core::result::Result -pub fn bitcoin_units::SignedAmount::try_from(value: bitcoin_units::Amount) -> core::result::Result pub fn bitcoin_units::SignedAmount::unchecked_add(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::SignedAmount::unchecked_sub(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount @@ -1070,7 +1071,6 @@ pub type bitcoin_units::Amount::Error = bitcoin_units::amount::OutOfRangeError pub type bitcoin_units::Amount::Output = bitcoin_units::Amount pub type bitcoin_units::Amount::Output = bitcoin_units::fee_rate::FeeRate pub type bitcoin_units::SignedAmount::Err = bitcoin_units::amount::ParseError -pub type bitcoin_units::SignedAmount::Error = bitcoin_units::amount::OutOfRangeError pub type bitcoin_units::SignedAmount::Output = bitcoin_units::SignedAmount pub type bitcoin_units::amount::Denomination::Err = bitcoin_units::amount::ParseDenominationError pub type bitcoin_units::block::BlockHeight::Err = bitcoin_units::parse::ParseIntError diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 84c53de7e..5dea49ba9 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -790,8 +790,8 @@ pub fn effective_value( value: Amount, ) -> Option { let weight = satisfaction_weight.checked_add(TX_IN_BASE_WEIGHT)?; - let signed_input_fee = fee_rate.checked_mul_by_weight(weight)?.to_signed().ok()?; - value.to_signed().ok()?.checked_sub(signed_input_fee) + let signed_input_fee = fee_rate.checked_mul_by_weight(weight)?.to_signed(); + value.to_signed().checked_sub(signed_input_fee) } /// Predicts the weight of a to-be-constructed transaction. @@ -1673,7 +1673,7 @@ mod tests { // 10 sat/kwu * (204wu + BASE_WEIGHT) = 4 sats let expected_fee = "4 sats".parse::().unwrap(); - let expected_effective_value = value.to_signed().unwrap() - expected_fee; + let expected_effective_value = value.to_signed() - expected_fee; assert_eq!(effective_value, expected_effective_value); } diff --git a/units/src/amount/signed.rs b/units/src/amount/signed.rs index 2faa7e45f..3c9df7f60 100644 --- a/units/src/amount/signed.rs +++ b/units/src/amount/signed.rs @@ -83,6 +83,15 @@ impl SignedAmount { /// ``` pub const fn to_sat(self) -> i64 { self.0 } + /// Constructs a new [`SignedAmount`] with satoshi precision and the given number of satoshis. + /// + /// Caller to guarantee that `satoshi` is within valid range. + /// + /// See [`Self::MIN`] and [`Self::MAX_MONEY`]. + pub const fn from_sat_unchecked(satoshi: i64) -> SignedAmount { + SignedAmount(satoshi) + } + /// Converts from a value expressing a decimal number of bitcoin to a [`SignedAmount`]. /// /// # Errors @@ -557,10 +566,11 @@ impl FromStr for SignedAmount { } } -impl TryFrom for SignedAmount { - type Error = OutOfRangeError; - - fn try_from(value: Amount) -> Result { value.to_signed() } +impl From for SignedAmount { + fn from(value: Amount) -> Self { + let v = value.to_sat() as i64; // Cast ok, signed amount and amount share positive range. + SignedAmount::from_sat_unchecked(v) + } } impl core::iter::Sum for SignedAmount { diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs index d5e939477..19b32ffec 100644 --- a/units/src/amount/tests.rs +++ b/units/src/amount/tests.rs @@ -71,13 +71,6 @@ fn from_int_btc() { assert_eq!(Amount::from_sat(200_000_000), amt); } -#[test] -fn test_signed_amount_try_from_amount() { - let ua_positive = Amount::from_sat(123); - let sa_positive = SignedAmount::try_from(ua_positive).unwrap(); - assert_eq!(sa_positive, SignedAmount::from_sat(123)); -} - #[test] fn test_amount_try_from_signed_amount() { let sa_positive = SignedAmount::from_sat(123); @@ -473,12 +466,11 @@ fn test_unsigned_signed_conversion() { let ua = Amount::from_sat; let max_sats: u64 = Amount::MAX.to_sat(); - assert_eq!(ua(max_sats).to_signed(), Ok(sa(max_sats as i64))); - assert_eq!(ua(i64::MAX as u64 + 1).to_signed(), Err(OutOfRangeError::too_big(true))); + assert_eq!(ua(max_sats).to_signed(), sa(max_sats as i64)); assert_eq!(sa(max_sats as i64).to_unsigned(), Ok(ua(max_sats))); - assert_eq!(sa(max_sats as i64).to_unsigned().unwrap().to_signed(), Ok(sa(max_sats as i64))); + assert_eq!(sa(max_sats as i64).to_unsigned().unwrap().to_signed(), sa(max_sats as i64)); } #[test] diff --git a/units/src/amount/unsigned.rs b/units/src/amount/unsigned.rs index e7b214189..9ee8d8cc0 100644 --- a/units/src/amount/unsigned.rs +++ b/units/src/amount/unsigned.rs @@ -438,17 +438,9 @@ impl Amount { pub fn unchecked_sub(self, rhs: Amount) -> Amount { Self(self.0 - rhs.0) } /// Converts to a signed amount. - /// - /// # Errors - /// - /// If the amount is too big. #[rustfmt::skip] // Moves code comments to the wrong line. - pub fn to_signed(self) -> Result { - if self.to_sat() > SignedAmount::MAX.to_sat() as u64 { // Cast ok, signed max is positive and fits in u64. - Err(OutOfRangeError::too_big(true)) - } else { - Ok(SignedAmount::from_sat(self.to_sat() as i64)) // Cast ok, checked not too big above. - } + pub fn to_signed(self) -> SignedAmount { + SignedAmount::from_sat_unchecked(self.to_sat() as i64) // Cast ok, signed amount and amount share positive range. } /// Checks if the amount is below the maximum value. Returns `None` if it is above.