Run cargo fmt

Run the command `cargo +nightly fmt` to fix formatting issues. No other
changes other than those introduced by `rustfmt`.
This commit is contained in:
Tobin C. Harding 2022-11-16 10:22:16 +11:00
parent 1ecf09359b
commit 408d7737fb
8 changed files with 413 additions and 413 deletions

View File

@ -4,10 +4,10 @@ use std::str::FromStr;
use std::{env, process}; use std::{env, process};
use bitcoin::address::Address; use bitcoin::address::Address;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::hex::FromHex;
use bitcoin::secp256k1::ffi::types::AlignedType; use bitcoin::secp256k1::ffi::types::AlignedType;
use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::Secp256k1;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
use bitcoin::PublicKey; use bitcoin::PublicKey;
fn main() { fn main() {

View File

@ -33,14 +33,14 @@ use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use bitcoin::consensus::encode;
use bitcoin::hashes::hex::FromHex;
use bitcoin::locktime::absolute;
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
use bitcoin::bip32::{ use bitcoin::bip32::{
ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivationPath, ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivationPath,
}; };
use bitcoin::consensus::encode;
use bitcoin::hashes::hex::FromHex;
use bitcoin::locktime::absolute;
use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType}; use bitcoin::psbt::{self, Input, Psbt, PsbtSighashType};
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
use bitcoin::{ use bitcoin::{
Address, Amount, Network, OutPoint, PublicKey, Script, Sequence, Transaction, TxIn, TxOut, Address, Amount, Network, OutPoint, PublicKey, Script, Sequence, Transaction, TxIn, TxOut,
Txid, Witness, Txid, Witness,

View File

@ -78,6 +78,7 @@ const UTXO_3: P2trUtxo = P2trUtxo {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::str::FromStr; use std::str::FromStr;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint};
use bitcoin::consensus::encode; use bitcoin::consensus::encode;
use bitcoin::constants::COIN_VALUE; use bitcoin::constants::COIN_VALUE;
use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::hex::FromHex;
@ -87,16 +88,13 @@ use bitcoin::psbt::serialize::Serialize;
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType}; use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
use bitcoin::schnorr::TapTweak; use bitcoin::schnorr::TapTweak;
use bitcoin::secp256k1::{Message, Secp256k1}; use bitcoin::secp256k1::{Message, Secp256k1};
use bitcoin::bip32::{ use bitcoin::sighash::{self, SchnorrSighashType, SighashCache};
ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint,
};
use bitcoin::sighash::{self, SighashCache, SchnorrSighashType};
use bitcoin::util::taproot::{ use bitcoin::util::taproot::{
LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo, LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo,
}; };
use bitcoin::{ use bitcoin::{
absolute, script, Address, Amount, OutPoint, SchnorrSig, Script, absolute, script, Address, Amount, OutPoint, SchnorrSig, Script, Transaction, TxIn, TxOut,
Transaction, TxIn, TxOut, Txid, Witness, XOnlyPublicKey, Txid, Witness, XOnlyPublicKey,
}; };
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {

View File

@ -34,9 +34,9 @@ use crate::blockdata::constants::{
MAX_SCRIPT_ELEMENT_SIZE, PUBKEY_ADDRESS_PREFIX_MAIN, PUBKEY_ADDRESS_PREFIX_TEST, MAX_SCRIPT_ELEMENT_SIZE, PUBKEY_ADDRESS_PREFIX_MAIN, PUBKEY_ADDRESS_PREFIX_TEST,
SCRIPT_ADDRESS_PREFIX_MAIN, SCRIPT_ADDRESS_PREFIX_TEST, SCRIPT_ADDRESS_PREFIX_MAIN, SCRIPT_ADDRESS_PREFIX_TEST,
}; };
use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::Instruction; use crate::blockdata::script::Instruction;
use crate::blockdata::{opcodes, script}; use crate::blockdata::{opcodes, script};
use crate::blockdata::opcodes::all::*;
use crate::error::ParseIntError; use crate::error::ParseIntError;
use crate::hash_types::{PubkeyHash, ScriptHash}; use crate::hash_types::{PubkeyHash, ScriptHash};
use crate::hashes::{sha256, Hash, HashEngine}; use crate::hashes::{sha256, Hash, HashEngine};
@ -324,9 +324,7 @@ impl TryFrom<opcodes::All> for WitnessVersion {
fn try_from(opcode: opcodes::All) -> Result<Self, Self::Error> { fn try_from(opcode: opcodes::All) -> Result<Self, Self::Error> {
match opcode.to_u8() { match opcode.to_u8() {
0 => Ok(WitnessVersion::V0), 0 => Ok(WitnessVersion::V0),
version version if version >= OP_PUSHNUM_1.to_u8() && version <= OP_PUSHNUM_16.to_u8() =>
if version >= OP_PUSHNUM_1.to_u8()
&& version <= OP_PUSHNUM_16.to_u8() =>
WitnessVersion::try_from(version - OP_PUSHNUM_1.to_u8() + 1), WitnessVersion::try_from(version - OP_PUSHNUM_1.to_u8() + 1),
_ => Err(Error::MalformedWitnessVersion), _ => Err(Error::MalformedWitnessVersion),
} }

View File

@ -6,10 +6,12 @@
//! We refer to the documentation on the types for more information. //! We refer to the documentation on the types for more information.
//! //!
use crate::prelude::*; use core::cmp::Ordering;
use core::{ops, default, str::FromStr, cmp::Ordering};
use core::fmt::{self, Write}; use core::fmt::{self, Write};
use core::str::FromStr;
use core::{default, ops};
use crate::prelude::*;
/// A set of denominations in which amounts can be expressed. /// A set of denominations in which amounts can be expressed.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@ -63,9 +65,7 @@ impl Denomination {
} }
impl fmt::Display for Denomination { impl fmt::Display for Denomination {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) }
f.write_str(self.as_str())
}
} }
impl FromStr for Denomination { impl FromStr for Denomination {
@ -79,18 +79,17 @@ impl FromStr for Denomination {
/// ///
/// Due to ambiguity between mega and milli, pico and peta we prohibit usage of leading capital 'M', 'P'. /// Due to ambiguity between mega and milli, pico and peta we prohibit usage of leading capital 'M', 'P'.
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::ParseAmountError::*;
use self::Denomination as D; use self::Denomination as D;
use self::ParseAmountError::*;
let starts_with_uppercase = || s.starts_with(char::is_uppercase); let starts_with_uppercase = || s.starts_with(char::is_uppercase);
match denomination_from_str(s) { match denomination_from_str(s) {
None => Err(UnknownDenomination(s.to_owned())), None => Err(UnknownDenomination(s.to_owned())),
Some(D::MilliBitcoin) | Some(D::PicoBitcoin) | Some(D::MilliSatoshi) if starts_with_uppercase() => { Some(D::MilliBitcoin) | Some(D::PicoBitcoin) | Some(D::MilliSatoshi)
Err(PossiblyConfusingDenomination(s.to_owned())) if starts_with_uppercase() =>
} Err(PossiblyConfusingDenomination(s.to_owned())),
Some(D::NanoBitcoin) | Some(D::MicroBitcoin) if starts_with_uppercase() => { Some(D::NanoBitcoin) | Some(D::MicroBitcoin) if starts_with_uppercase() =>
Err(UnknownDenomination(s.to_owned())) Err(UnknownDenomination(s.to_owned())),
}
Some(d) => Ok(d), Some(d) => Ok(d),
} }
} }
@ -157,7 +156,7 @@ pub enum ParseAmountError {
/// The denomination was unknown. /// The denomination was unknown.
UnknownDenomination(String), UnknownDenomination(String),
/// The denomination has multiple possible interpretations. /// The denomination has multiple possible interpretations.
PossiblyConfusingDenomination(String) PossiblyConfusingDenomination(String),
} }
impl fmt::Display for ParseAmountError { impl fmt::Display for ParseAmountError {
@ -169,7 +168,8 @@ impl fmt::Display for ParseAmountError {
ParseAmountError::InvalidFormat => f.write_str("invalid number format"), ParseAmountError::InvalidFormat => f.write_str("invalid number format"),
ParseAmountError::InputTooLarge => f.write_str("input string was too large"), ParseAmountError::InputTooLarge => f.write_str("input string was too large"),
ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c), ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
ParseAmountError::UnknownDenomination(ref d) => write!(f, "unknown denomination: {}", d), ParseAmountError::UnknownDenomination(ref d) =>
write!(f, "unknown denomination: {}", d),
ParseAmountError::PossiblyConfusingDenomination(ref d) => { ParseAmountError::PossiblyConfusingDenomination(ref d) => {
let (letter, upper, lower) = match d.chars().next() { let (letter, upper, lower) = match d.chars().next() {
Some('M') => ('M', "Mega", "milli"), Some('M') => ('M', "Mega", "milli"),
@ -197,7 +197,7 @@ impl std::error::Error for ParseAmountError {
| InputTooLarge | InputTooLarge
| InvalidCharacter(_) | InvalidCharacter(_)
| UnknownDenomination(_) | UnknownDenomination(_)
| PossiblyConfusingDenomination(_) => None | PossiblyConfusingDenomination(_) => None,
} }
} }
} }
@ -337,9 +337,7 @@ fn dec_width(mut num: u64) -> usize {
} }
// NIH due to MSRV, impl copied from `core::i8::unsigned_abs` (introduced in Rust 1.51.1). // NIH due to MSRV, impl copied from `core::i8::unsigned_abs` (introduced in Rust 1.51.1).
fn unsigned_abs(x: i8) -> u8 { fn unsigned_abs(x: i8) -> u8 { x.wrapping_abs() as u8 }
x.wrapping_abs() as u8
}
fn repeat_char(f: &mut dyn fmt::Write, c: char, count: usize) -> fmt::Result { fn repeat_char(f: &mut dyn fmt::Write, c: char, count: usize) -> fmt::Result {
for _ in 0..count { for _ in 0..count {
@ -372,7 +370,7 @@ fn fmt_satoshi_in(
exp = precision as usize; exp = precision as usize;
} }
trailing_decimal_zeros = options.precision.unwrap_or(0); trailing_decimal_zeros = options.precision.unwrap_or(0);
}, }
Ordering::Less => { Ordering::Less => {
let precision = unsigned_abs(precision); let precision = unsigned_abs(precision);
let divisor = 10u64.pow(precision.into()); let divisor = 10u64.pow(precision.into());
@ -391,7 +389,7 @@ fn fmt_satoshi_in(
// compute requested precision // compute requested precision
let opt_precision = options.precision.unwrap_or(0); let opt_precision = options.precision.unwrap_or(0);
trailing_decimal_zeros = opt_precision.saturating_sub(norm_nb_decimals); trailing_decimal_zeros = opt_precision.saturating_sub(norm_nb_decimals);
}, }
Ordering::Equal => trailing_decimal_zeros = options.precision.unwrap_or(0), Ordering::Equal => trailing_decimal_zeros = options.precision.unwrap_or(0),
} }
let total_decimals = norm_nb_decimals + trailing_decimal_zeros; let total_decimals = norm_nb_decimals + trailing_decimal_zeros;
@ -420,7 +418,8 @@ fn fmt_satoshi_in(
(true, true, _) | (true, false, fmt::Alignment::Right) => (width - num_width, 0), (true, true, _) | (true, false, fmt::Alignment::Right) => (width - num_width, 0),
(true, false, fmt::Alignment::Left) => (0, width - num_width), (true, false, fmt::Alignment::Left) => (0, width - num_width),
// If the required padding is odd it needs to be skewed to the left // If the required padding is odd it needs to be skewed to the left
(true, false, fmt::Alignment::Center) => ((width - num_width) / 2, (width - num_width + 1) / 2), (true, false, fmt::Alignment::Center) =>
((width - num_width) / 2, (width - num_width + 1) / 2),
}; };
if !options.sign_aware_zero_pad { if !options.sign_aware_zero_pad {
@ -488,24 +487,16 @@ impl Amount {
pub const MAX_MONEY: Amount = Amount(21_000_000 * 100_000_000); pub const MAX_MONEY: Amount = Amount(21_000_000 * 100_000_000);
/// Create an [Amount] with satoshi precision and the given number of satoshis. /// Create an [Amount] with satoshi precision and the given number of satoshis.
pub const fn from_sat(satoshi: u64) -> Amount { pub const fn from_sat(satoshi: u64) -> Amount { Amount(satoshi) }
Amount(satoshi)
}
/// Gets the number of satoshis in this [`Amount`]. /// Gets the number of satoshis in this [`Amount`].
pub fn to_sat(self) -> u64 { pub fn to_sat(self) -> u64 { self.0 }
self.0
}
/// The maximum value of an [Amount]. /// The maximum value of an [Amount].
pub fn max_value() -> Amount { pub fn max_value() -> Amount { Amount(u64::max_value()) }
Amount(u64::max_value())
}
/// The minimum value of an [Amount]. /// The minimum value of an [Amount].
pub fn min_value() -> Amount { pub fn min_value() -> Amount { Amount(u64::min_value()) }
Amount(u64::min_value())
}
/// Convert from a value expressing bitcoins to an [Amount]. /// Convert from a value expressing bitcoins to an [Amount].
pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> { pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> {
@ -559,9 +550,7 @@ impl Amount {
/// let amount = Amount::from_sat(100_000); /// let amount = Amount::from_sat(100_000);
/// assert_eq!(amount.to_btc(), amount.to_float_in(Denomination::Bitcoin)) /// assert_eq!(amount.to_btc(), amount.to_float_in(Denomination::Bitcoin))
/// ``` /// ```
pub fn to_btc(self) -> f64 { pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
self.to_float_in(Denomination::Bitcoin)
}
/// Convert this [Amount] in floating-point notation with a given /// Convert this [Amount] in floating-point notation with a given
/// denomination. /// denomination.
@ -582,7 +571,7 @@ impl Amount {
Display { Display {
sats_abs: self.to_sat(), sats_abs: self.to_sat(),
is_negative: false, is_negative: false,
style: DisplayStyle::FixedDenomination { denomination, show_denomination: false, }, style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
} }
} }
@ -640,23 +629,17 @@ impl Amount {
/// Checked multiplication. /// Checked multiplication.
/// Returns [None] if overflow occurred. /// Returns [None] if overflow occurred.
pub fn checked_mul(self, rhs: u64) -> Option<Amount> { pub fn checked_mul(self, rhs: u64) -> Option<Amount> { self.0.checked_mul(rhs).map(Amount) }
self.0.checked_mul(rhs).map(Amount)
}
/// Checked integer division. /// Checked integer division.
/// Be aware that integer division loses the remainder if no exact division /// Be aware that integer division loses the remainder if no exact division
/// can be made. /// can be made.
/// Returns [None] if overflow occurred. /// Returns [None] if overflow occurred.
pub fn checked_div(self, rhs: u64) -> Option<Amount> { pub fn checked_div(self, rhs: u64) -> Option<Amount> { self.0.checked_div(rhs).map(Amount) }
self.0.checked_div(rhs).map(Amount)
}
/// Checked remainder. /// Checked remainder.
/// Returns [None] if overflow occurred. /// Returns [None] if overflow occurred.
pub fn checked_rem(self, rhs: u64) -> Option<Amount> { pub fn checked_rem(self, rhs: u64) -> Option<Amount> { self.0.checked_rem(rhs).map(Amount) }
self.0.checked_rem(rhs).map(Amount)
}
/// Convert to a signed amount. /// Convert to a signed amount.
pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> { pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
@ -669,9 +652,7 @@ impl Amount {
} }
impl default::Default for Amount { impl default::Default for Amount {
fn default() -> Self { fn default() -> Self { Amount::ZERO }
Amount::ZERO
}
} }
impl fmt::Debug for Amount { impl fmt::Debug for Amount {
@ -698,9 +679,7 @@ impl ops::Add for Amount {
} }
impl ops::AddAssign for Amount { impl ops::AddAssign for Amount {
fn add_assign(&mut self, other: Amount) { fn add_assign(&mut self, other: Amount) { *self = *self + other }
*self = *self + other
}
} }
impl ops::Sub for Amount { impl ops::Sub for Amount {
@ -712,9 +691,7 @@ impl ops::Sub for Amount {
} }
impl ops::SubAssign for Amount { impl ops::SubAssign for Amount {
fn sub_assign(&mut self, other: Amount) { fn sub_assign(&mut self, other: Amount) { *self = *self - other }
*self = *self - other
}
} }
impl ops::Rem<u64> for Amount { impl ops::Rem<u64> for Amount {
@ -726,9 +703,7 @@ impl ops::Rem<u64> for Amount {
} }
impl ops::RemAssign<u64> for Amount { impl ops::RemAssign<u64> for Amount {
fn rem_assign(&mut self, modulus: u64) { fn rem_assign(&mut self, modulus: u64) { *self = *self % modulus }
*self = *self % modulus
}
} }
impl ops::Mul<u64> for Amount { impl ops::Mul<u64> for Amount {
@ -740,31 +715,23 @@ impl ops::Mul<u64> for Amount {
} }
impl ops::MulAssign<u64> for Amount { impl ops::MulAssign<u64> for Amount {
fn mul_assign(&mut self, rhs: u64) { fn mul_assign(&mut self, rhs: u64) { *self = *self * rhs }
*self = *self * rhs
}
} }
impl ops::Div<u64> for Amount { impl ops::Div<u64> for Amount {
type Output = Amount; type Output = Amount;
fn div(self, rhs: u64) -> Self::Output { fn div(self, rhs: u64) -> Self::Output { self.checked_div(rhs).expect("Amount division error") }
self.checked_div(rhs).expect("Amount division error")
}
} }
impl ops::DivAssign<u64> for Amount { impl ops::DivAssign<u64> for Amount {
fn div_assign(&mut self, rhs: u64) { fn div_assign(&mut self, rhs: u64) { *self = *self / rhs }
*self = *self / rhs
}
} }
impl FromStr for Amount { impl FromStr for Amount {
type Err = ParseAmountError; type Err = ParseAmountError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> { Amount::from_str_with_denomination(s) }
Amount::from_str_with_denomination(s)
}
} }
impl core::iter::Sum for Amount { impl core::iter::Sum for Amount {
@ -829,7 +796,7 @@ impl fmt::Display for Display {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum DisplayStyle { enum DisplayStyle {
FixedDenomination { denomination: Denomination, show_denomination: bool, }, FixedDenomination { denomination: Denomination, show_denomination: bool },
DynamicDenomination, DynamicDenomination,
} }
@ -861,24 +828,16 @@ impl SignedAmount {
pub const MAX_MONEY: SignedAmount = SignedAmount(21_000_000 * 100_000_000); pub const MAX_MONEY: SignedAmount = SignedAmount(21_000_000 * 100_000_000);
/// Create an [SignedAmount] with satoshi precision and the given number of satoshis. /// Create an [SignedAmount] with satoshi precision and the given number of satoshis.
pub const fn from_sat(satoshi: i64) -> SignedAmount { pub const fn from_sat(satoshi: i64) -> SignedAmount { SignedAmount(satoshi) }
SignedAmount(satoshi)
}
/// Gets the number of satoshis in this [`SignedAmount`]. /// Gets the number of satoshis in this [`SignedAmount`].
pub fn to_sat(self) -> i64 { pub fn to_sat(self) -> i64 { self.0 }
self.0
}
/// The maximum value of an [SignedAmount]. /// The maximum value of an [SignedAmount].
pub fn max_value() -> SignedAmount { pub fn max_value() -> SignedAmount { SignedAmount(i64::max_value()) }
SignedAmount(i64::max_value())
}
/// The minimum value of an [SignedAmount]. /// The minimum value of an [SignedAmount].
pub fn min_value() -> SignedAmount { pub fn min_value() -> SignedAmount { SignedAmount(i64::min_value()) }
SignedAmount(i64::min_value())
}
/// Convert from a value expressing bitcoins to an [SignedAmount]. /// Convert from a value expressing bitcoins to an [SignedAmount].
pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> { pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
@ -927,9 +886,7 @@ impl SignedAmount {
/// Equivalent to `to_float_in(Denomination::Bitcoin)`. /// Equivalent to `to_float_in(Denomination::Bitcoin)`.
/// ///
/// Please be aware of the risk of using floating-point numbers. /// Please be aware of the risk of using floating-point numbers.
pub fn to_btc(self) -> f64 { pub fn to_btc(self) -> f64 { self.to_float_in(Denomination::Bitcoin) }
self.to_float_in(Denomination::Bitcoin)
}
/// Convert this [SignedAmount] in floating-point notation with a given /// Convert this [SignedAmount] in floating-point notation with a given
/// denomination. /// denomination.
@ -948,16 +905,14 @@ impl SignedAmount {
/// Returns the absolute value as satoshis. /// Returns the absolute value as satoshis.
/// ///
/// This is the implementation of `unsigned_abs()` copied from `core` to support older MSRV. /// This is the implementation of `unsigned_abs()` copied from `core` to support older MSRV.
fn to_sat_abs(self) -> u64 { fn to_sat_abs(self) -> u64 { self.to_sat().wrapping_abs() as u64 }
self.to_sat().wrapping_abs() as u64
}
/// Create an object that implements [`fmt::Display`] using specified denomination. /// Create an object that implements [`fmt::Display`] using specified denomination.
pub fn display_in(self, denomination: Denomination) -> Display { pub fn display_in(self, denomination: Denomination) -> Display {
Display { Display {
sats_abs: self.to_sat_abs(), sats_abs: self.to_sat_abs(),
is_negative: self.is_negative(), is_negative: self.is_negative(),
style: DisplayStyle::FixedDenomination { denomination, show_denomination: false, }, style: DisplayStyle::FixedDenomination { denomination, show_denomination: false },
} }
} }
@ -1002,37 +957,26 @@ impl SignedAmount {
// Some arithmetic that doesn't fit in `core::ops` traits. // Some arithmetic that doesn't fit in `core::ops` traits.
/// Get the absolute value of this [SignedAmount]. /// Get the absolute value of this [SignedAmount].
pub fn abs(self) -> SignedAmount { pub fn abs(self) -> SignedAmount { SignedAmount(self.0.abs()) }
SignedAmount(self.0.abs())
}
/// Returns a number representing sign of this [SignedAmount]. /// Returns a number representing sign of this [SignedAmount].
/// ///
/// - `0` if the amount is zero /// - `0` if the amount is zero
/// - `1` if the amount is positive /// - `1` if the amount is positive
/// - `-1` if the amount is negative /// - `-1` if the amount is negative
pub fn signum(self) -> i64 { pub fn signum(self) -> i64 { self.0.signum() }
self.0.signum()
}
/// Returns `true` if this [SignedAmount] is positive and `false` if /// Returns `true` if this [SignedAmount] is positive and `false` if
/// this [SignedAmount] is zero or negative. /// this [SignedAmount] is zero or negative.
pub fn is_positive(self) -> bool { pub fn is_positive(self) -> bool { self.0.is_positive() }
self.0.is_positive()
}
/// Returns `true` if this [SignedAmount] is negative and `false` if /// Returns `true` if this [SignedAmount] is negative and `false` if
/// this [SignedAmount] is zero or positive. /// this [SignedAmount] is zero or positive.
pub fn is_negative(self) -> bool { pub fn is_negative(self) -> bool { self.0.is_negative() }
self.0.is_negative()
}
/// Get the absolute value of this [SignedAmount]. /// Get the absolute value of this [SignedAmount].
/// Returns [None] if overflow occurred. (`self == min_value()`) /// Returns [None] if overflow occurred. (`self == min_value()`)
pub fn checked_abs(self) -> Option<SignedAmount> { pub fn checked_abs(self) -> Option<SignedAmount> { self.0.checked_abs().map(SignedAmount) }
self.0.checked_abs().map(SignedAmount)
}
/// Checked addition. /// Checked addition.
/// Returns [None] if overflow occurred. /// Returns [None] if overflow occurred.
@ -1087,9 +1031,7 @@ impl SignedAmount {
} }
impl default::Default for SignedAmount { impl default::Default for SignedAmount {
fn default() -> Self { fn default() -> Self { SignedAmount::ZERO }
SignedAmount::ZERO
}
} }
impl fmt::Debug for SignedAmount { impl fmt::Debug for SignedAmount {
@ -1116,9 +1058,7 @@ impl ops::Add for SignedAmount {
} }
impl ops::AddAssign for SignedAmount { impl ops::AddAssign for SignedAmount {
fn add_assign(&mut self, other: SignedAmount) { fn add_assign(&mut self, other: SignedAmount) { *self = *self + other }
*self = *self + other
}
} }
impl ops::Sub for SignedAmount { impl ops::Sub for SignedAmount {
@ -1130,9 +1070,7 @@ impl ops::Sub for SignedAmount {
} }
impl ops::SubAssign for SignedAmount { impl ops::SubAssign for SignedAmount {
fn sub_assign(&mut self, other: SignedAmount) { fn sub_assign(&mut self, other: SignedAmount) { *self = *self - other }
*self = *self - other
}
} }
impl ops::Rem<i64> for SignedAmount { impl ops::Rem<i64> for SignedAmount {
@ -1144,9 +1082,7 @@ impl ops::Rem<i64> for SignedAmount {
} }
impl ops::RemAssign<i64> for SignedAmount { impl ops::RemAssign<i64> for SignedAmount {
fn rem_assign(&mut self, modulus: i64) { fn rem_assign(&mut self, modulus: i64) { *self = *self % modulus }
*self = *self % modulus
}
} }
impl ops::Mul<i64> for SignedAmount { impl ops::Mul<i64> for SignedAmount {
@ -1158,9 +1094,7 @@ impl ops::Mul<i64> for SignedAmount {
} }
impl ops::MulAssign<i64> for SignedAmount { impl ops::MulAssign<i64> for SignedAmount {
fn mul_assign(&mut self, rhs: i64) { fn mul_assign(&mut self, rhs: i64) { *self = *self * rhs }
*self = *self * rhs
}
} }
impl ops::Div<i64> for SignedAmount { impl ops::Div<i64> for SignedAmount {
@ -1172,17 +1106,13 @@ impl ops::Div<i64> for SignedAmount {
} }
impl ops::DivAssign<i64> for SignedAmount { impl ops::DivAssign<i64> for SignedAmount {
fn div_assign(&mut self, rhs: i64) { fn div_assign(&mut self, rhs: i64) { *self = *self / rhs }
*self = *self / rhs
}
} }
impl FromStr for SignedAmount { impl FromStr for SignedAmount {
type Err = ParseAmountError; type Err = ParseAmountError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> { SignedAmount::from_str_with_denomination(s) }
SignedAmount::from_str_with_denomination(s)
}
} }
impl core::iter::Sum for SignedAmount { impl core::iter::Sum for SignedAmount {
@ -1199,18 +1129,21 @@ pub trait CheckedSum<R>: private::SumSeal<R> {
fn checked_sum(self) -> Option<R>; fn checked_sum(self) -> Option<R>;
} }
impl<T> CheckedSum<Amount> for T where T: Iterator<Item=Amount> { impl<T> CheckedSum<Amount> for T
where
T: Iterator<Item = Amount>,
{
fn checked_sum(mut self) -> Option<Amount> { fn checked_sum(mut self) -> Option<Amount> {
let first = Some(self.next().unwrap_or_default()); let first = Some(self.next().unwrap_or_default());
self.fold( self.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
first,
|acc, item| acc.and_then(|acc| acc.checked_add(item))
)
} }
} }
impl<T> CheckedSum<SignedAmount> for T where T: Iterator<Item=SignedAmount> { impl<T> CheckedSum<SignedAmount> for T
where
T: Iterator<Item = SignedAmount>,
{
fn checked_sum(mut self) -> Option<SignedAmount> { fn checked_sum(mut self) -> Option<SignedAmount> {
let first = Some(self.next().unwrap_or_default()); let first = Some(self.next().unwrap_or_default());
@ -1252,6 +1185,7 @@ pub mod serde {
//! ``` //! ```
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::amount::{Amount, Denomination, SignedAmount}; use crate::amount::{Amount, Denomination, SignedAmount};
/// This trait is used only to avoid code duplication and naming collisions /// This trait is used only to avoid code duplication and naming collisions
@ -1295,9 +1229,7 @@ pub mod serde {
} }
impl SerdeAmountForOpt for Amount { impl SerdeAmountForOpt for Amount {
fn type_prefix() -> &'static str { fn type_prefix() -> &'static str { "u" }
"u"
}
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> { fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_some(&self.to_sat()) s.serialize_some(&self.to_sat())
} }
@ -1323,9 +1255,7 @@ pub mod serde {
} }
impl SerdeAmountForOpt for SignedAmount { impl SerdeAmountForOpt for SignedAmount {
fn type_prefix() -> &'static str { fn type_prefix() -> &'static str { "i" }
"i"
}
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> { fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_some(&self.to_sat()) s.serialize_some(&self.to_sat())
} }
@ -1339,6 +1269,7 @@ pub mod serde {
//! Use with `#[serde(with = "amount::serde::as_sat")]`. //! Use with `#[serde(with = "amount::serde::as_sat")]`.
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
use crate::amount::serde::SerdeAmount; use crate::amount::serde::SerdeAmount;
pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> { pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
@ -1353,11 +1284,13 @@ pub mod serde {
//! Serialize and deserialize [`Option<Amount>`](crate::Amount) as real numbers denominated in satoshi. //! Serialize and deserialize [`Option<Amount>`](crate::Amount) as real numbers denominated in satoshi.
//! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`. //! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`.
use serde::{Deserializer, Serializer, de};
use crate::amount::serde::SerdeAmountForOpt;
use core::fmt; use core::fmt;
use core::marker::PhantomData; use core::marker::PhantomData;
use serde::{de, Deserializer, Serializer};
use crate::amount::serde::SerdeAmountForOpt;
pub fn serialize<A: SerdeAmountForOpt, S: Serializer>( pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
a: &Option<A>, a: &Option<A>,
s: S, s: S,
@ -1403,6 +1336,7 @@ pub mod serde {
//! Use with `#[serde(with = "amount::serde::as_btc")]`. //! Use with `#[serde(with = "amount::serde::as_btc")]`.
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
use crate::amount::serde::SerdeAmount; use crate::amount::serde::SerdeAmount;
pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> { pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
@ -1417,11 +1351,13 @@ pub mod serde {
//! Serialize and deserialize [Option<Amount>] as JSON numbers denominated in BTC. //! Serialize and deserialize [Option<Amount>] as JSON numbers denominated in BTC.
//! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`. //! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`.
use serde::{Deserializer, Serializer, de};
use crate::amount::serde::SerdeAmountForOpt;
use core::fmt; use core::fmt;
use core::marker::PhantomData; use core::marker::PhantomData;
use serde::{de, Deserializer, Serializer};
use crate::amount::serde::SerdeAmountForOpt;
pub fn serialize<A: SerdeAmountForOpt, S: Serializer>( pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
a: &Option<A>, a: &Option<A>,
s: S, s: S,
@ -1465,14 +1401,15 @@ pub mod serde {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use core::str::FromStr;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::panic; use std::panic;
use core::str::FromStr;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde_test; use serde_test;
use super::*;
#[test] #[test]
fn add_sub_mul_div() { fn add_sub_mul_div() {
let sat = Amount::from_sat; let sat = Amount::from_sat;
@ -1613,13 +1550,22 @@ mod tests {
// make sure satoshi > i64::max_value() is checked. // make sure satoshi > i64::max_value() is checked.
let amount = Amount::from_sat(i64::max_value() as u64); let amount = Amount::from_sat(i64::max_value() as u64);
assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount)); assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
assert_eq!(Amount::from_str_in(&(amount+Amount(1)).to_string_in(sat), sat), Err(E::TooBig)); assert_eq!(
Amount::from_str_in(&(amount + Amount(1)).to_string_in(sat), sat),
Err(E::TooBig)
);
assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise)); assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise));
// exactly 50 chars. // exactly 50 chars.
assert_eq!(p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin), Err(E::TooBig)); assert_eq!(
p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin),
Err(E::TooBig)
);
// more than 50 chars. // more than 50 chars.
assert_eq!(p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin), Err(E::InputTooLarge)); assert_eq!(
p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin),
Err(E::InputTooLarge)
);
} }
#[test] #[test]
@ -1845,7 +1791,10 @@ mod tests {
assert_eq!(sa(0).to_unsigned().unwrap().to_signed(), Ok(sa(0))); assert_eq!(sa(0).to_unsigned().unwrap().to_signed(), Ok(sa(0)));
assert_eq!(sa(1).to_unsigned().unwrap().to_signed(), Ok(sa(1))); assert_eq!(sa(1).to_unsigned().unwrap().to_signed(), Ok(sa(1)));
assert_eq!(sa(i64::max_value()).to_unsigned().unwrap().to_signed(), Ok(sa(i64::max_value()))); assert_eq!(
sa(i64::max_value()).to_unsigned().unwrap().to_signed(),
Ok(sa(i64::max_value()))
);
} }
#[test] #[test]
@ -1907,34 +1856,73 @@ mod tests {
assert_eq!("2535830000", Amount::from_sat(253583).to_string_in(D::PicoBitcoin)); assert_eq!("2535830000", Amount::from_sat(253583).to_string_in(D::PicoBitcoin));
assert_eq!("-100000000", SignedAmount::from_sat(-10_000).to_string_in(D::PicoBitcoin)); assert_eq!("-100000000", SignedAmount::from_sat(-10_000).to_string_in(D::PicoBitcoin));
assert_eq!("0.50", format!("{:.2}", Amount::from_sat(50).display_in(D::Bit))); assert_eq!("0.50", format!("{:.2}", Amount::from_sat(50).display_in(D::Bit)));
assert_eq!("-0.50", format!("{:.2}", SignedAmount::from_sat(-50).display_in(D::Bit))); assert_eq!("-0.50", format!("{:.2}", SignedAmount::from_sat(-50).display_in(D::Bit)));
assert_eq!("0.10000000", format!("{:.8}", Amount::from_sat(100_000_00).display_in(D::Bitcoin))); assert_eq!(
"0.10000000",
format!("{:.8}", Amount::from_sat(100_000_00).display_in(D::Bitcoin))
);
assert_eq!("-100.00", format!("{:.2}", SignedAmount::from_sat(-10_000).display_in(D::Bit))); assert_eq!("-100.00", format!("{:.2}", SignedAmount::from_sat(-10_000).display_in(D::Bit)));
assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0))); assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0)));
assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500))); assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500)));
assert_eq!(ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit), Ok(ua_sat(21_000_000))); assert_eq!(
assert_eq!(ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(ua_sat(1))); ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit),
assert_eq!(ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Ok(ua_sat(1_000_000_000_000))); Ok(ua_sat(21_000_000))
assert_eq!(ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Err(ParseAmountError::TooBig)); );
assert_eq!(
ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
Ok(ua_sat(1))
);
assert_eq!(
ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
Ok(ua_sat(1_000_000_000_000))
);
assert_eq!(
ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin),
Err(ParseAmountError::TooBig)
);
assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(sa_sat(-1))); assert_eq!(
sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin),
Ok(sa_sat(-1))
);
assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig)); assert_eq!(
sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin),
Err(ParseAmountError::TooBig)
);
// Test an overflow bug in `abs()` // Test an overflow bug in `abs()`
assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig)); assert_eq!(
sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin),
assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::NanoBitcoin), D::NanoBitcoin), Ok(sa_sat(-1))); Err(ParseAmountError::TooBig)
assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::NanoBitcoin), Err(ParseAmountError::TooPrecise)); );
assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::NanoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::PicoBitcoin), D::PicoBitcoin), Ok(sa_sat(-1)));
assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::PicoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::PicoBitcoin), Err(ParseAmountError::TooPrecise));
assert_eq!(
sa_str(&sa_sat(-1).to_string_in(D::NanoBitcoin), D::NanoBitcoin),
Ok(sa_sat(-1))
);
assert_eq!(
sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::NanoBitcoin),
Err(ParseAmountError::TooPrecise)
);
assert_eq!(
sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::NanoBitcoin),
Err(ParseAmountError::TooPrecise)
);
assert_eq!(
sa_str(&sa_sat(-1).to_string_in(D::PicoBitcoin), D::PicoBitcoin),
Ok(sa_sat(-1))
);
assert_eq!(
sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::PicoBitcoin),
Err(ParseAmountError::TooPrecise)
);
assert_eq!(
sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::PicoBitcoin),
Err(ParseAmountError::TooPrecise)
);
} }
#[test] #[test]
@ -1958,7 +1946,6 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[test] #[test]
fn serde_as_sat() { fn serde_as_sat() {
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(crate = "actual_serde")] #[serde(crate = "actual_serde")]
struct T { struct T {
@ -1969,10 +1956,7 @@ mod tests {
} }
serde_test::assert_tokens( serde_test::assert_tokens(
&T { &T { amt: Amount::from_sat(123456789), samt: SignedAmount::from_sat(-123456789) },
amt: Amount::from_sat(123456789),
samt: SignedAmount::from_sat(-123456789),
},
&[ &[
serde_test::Token::Struct { name: "T", len: 2 }, serde_test::Token::Struct { name: "T", len: 2 },
serde_test::Token::Str("amt"), serde_test::Token::Str("amt"),
@ -2039,10 +2023,7 @@ mod tests {
amt: Some(Amount::from_sat(2_500_000_00)), amt: Some(Amount::from_sat(2_500_000_00)),
samt: Some(SignedAmount::from_sat(-2_500_000_00)), samt: Some(SignedAmount::from_sat(-2_500_000_00)),
}; };
let without = T { let without = T { amt: None, samt: None };
amt: None,
samt: None,
};
// Test Roundtripping // Test Roundtripping
for s in [&with, &without].iter() { for s in [&with, &without].iter() {
@ -2084,10 +2065,7 @@ mod tests {
amt: Some(Amount::from_sat(2_500_000_00)), amt: Some(Amount::from_sat(2_500_000_00)),
samt: Some(SignedAmount::from_sat(-2_500_000_00)), samt: Some(SignedAmount::from_sat(-2_500_000_00)),
}; };
let without = T { let without = T { amt: None, samt: None };
amt: None,
samt: None,
};
// Test Roundtripping // Test Roundtripping
for s in [&with, &without].iter() { for s in [&with, &without].iter() {
@ -2115,18 +2093,14 @@ mod tests {
assert_eq!(Amount::from_sat(0), vec![].into_iter().sum::<Amount>()); assert_eq!(Amount::from_sat(0), vec![].into_iter().sum::<Amount>());
assert_eq!(SignedAmount::from_sat(0), vec![].into_iter().sum::<SignedAmount>()); assert_eq!(SignedAmount::from_sat(0), vec![].into_iter().sum::<SignedAmount>());
let amounts = vec![ let amounts = vec![Amount::from_sat(42), Amount::from_sat(1337), Amount::from_sat(21)];
Amount::from_sat(42),
Amount::from_sat(1337),
Amount::from_sat(21)
];
let sum = amounts.into_iter().sum::<Amount>(); let sum = amounts.into_iter().sum::<Amount>();
assert_eq!(Amount::from_sat(1400), sum); assert_eq!(Amount::from_sat(1400), sum);
let amounts = vec![ let amounts = vec![
SignedAmount::from_sat(-42), SignedAmount::from_sat(-42),
SignedAmount::from_sat(1337), SignedAmount::from_sat(1337),
SignedAmount::from_sat(21) SignedAmount::from_sat(21),
]; ];
let sum = amounts.into_iter().sum::<SignedAmount>(); let sum = amounts.into_iter().sum::<SignedAmount>();
assert_eq!(SignedAmount::from_sat(1316), sum); assert_eq!(SignedAmount::from_sat(1316), sum);
@ -2137,26 +2111,19 @@ mod tests {
assert_eq!(Some(Amount::from_sat(0)), vec![].into_iter().checked_sum()); assert_eq!(Some(Amount::from_sat(0)), vec![].into_iter().checked_sum());
assert_eq!(Some(SignedAmount::from_sat(0)), vec![].into_iter().checked_sum()); assert_eq!(Some(SignedAmount::from_sat(0)), vec![].into_iter().checked_sum());
let amounts = vec![ let amounts = vec![Amount::from_sat(42), Amount::from_sat(1337), Amount::from_sat(21)];
Amount::from_sat(42),
Amount::from_sat(1337),
Amount::from_sat(21)
];
let sum = amounts.into_iter().checked_sum(); let sum = amounts.into_iter().checked_sum();
assert_eq!(Some(Amount::from_sat(1400)), sum); assert_eq!(Some(Amount::from_sat(1400)), sum);
let amounts = vec![ let amounts =
Amount::from_sat(u64::max_value()), vec![Amount::from_sat(u64::max_value()), Amount::from_sat(1337), Amount::from_sat(21)];
Amount::from_sat(1337),
Amount::from_sat(21)
];
let sum = amounts.into_iter().checked_sum(); let sum = amounts.into_iter().checked_sum();
assert_eq!(None, sum); assert_eq!(None, sum);
let amounts = vec![ let amounts = vec![
SignedAmount::from_sat(i64::min_value()), SignedAmount::from_sat(i64::min_value()),
SignedAmount::from_sat(-1), SignedAmount::from_sat(-1),
SignedAmount::from_sat(21) SignedAmount::from_sat(21),
]; ];
let sum = amounts.into_iter().checked_sum(); let sum = amounts.into_iter().checked_sum();
assert_eq!(None, sum); assert_eq!(None, sum);
@ -2164,7 +2131,7 @@ mod tests {
let amounts = vec![ let amounts = vec![
SignedAmount::from_sat(i64::max_value()), SignedAmount::from_sat(i64::max_value()),
SignedAmount::from_sat(1), SignedAmount::from_sat(1),
SignedAmount::from_sat(21) SignedAmount::from_sat(21),
]; ];
let sum = amounts.into_iter().checked_sum(); let sum = amounts.into_iter().checked_sum();
assert_eq!(None, sum); assert_eq!(None, sum);
@ -2172,7 +2139,7 @@ mod tests {
let amounts = vec![ let amounts = vec![
SignedAmount::from_sat(42), SignedAmount::from_sat(42),
SignedAmount::from_sat(3301), SignedAmount::from_sat(3301),
SignedAmount::from_sat(21) SignedAmount::from_sat(21),
]; ];
let sum = amounts.into_iter().checked_sum(); let sum = amounts.into_iter().checked_sum();
assert_eq!(Some(SignedAmount::from_sat(3364)), sum); assert_eq!(Some(SignedAmount::from_sat(3364)), sum);
@ -2181,7 +2148,10 @@ mod tests {
#[test] #[test]
fn denomination_string_acceptable_forms() { fn denomination_string_acceptable_forms() {
// Non-exhaustive list of valid forms. // Non-exhaustive list of valid forms.
let valid = vec!["BTC", "btc", "mBTC", "mbtc", "uBTC", "ubtc", "SATOSHI","Satoshi", "Satoshis", "satoshis", "SAT", "Sat", "sats", "bit", "bits", "nBTC", "pBTC"]; let valid = vec![
"BTC", "btc", "mBTC", "mbtc", "uBTC", "ubtc", "SATOSHI", "Satoshi", "Satoshis",
"satoshis", "SAT", "Sat", "sats", "bit", "bits", "nBTC", "pBTC",
];
for denom in valid.iter() { for denom in valid.iter() {
assert!(Denomination::from_str(denom).is_ok()); assert!(Denomination::from_str(denom).is_ok());
} }
@ -2190,11 +2160,12 @@ mod tests {
#[test] #[test]
fn disallow_confusing_forms() { fn disallow_confusing_forms() {
// Non-exhaustive list of confusing forms. // Non-exhaustive list of confusing forms.
let confusing = vec!["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"]; let confusing =
vec!["Msat", "Msats", "MSAT", "MSATS", "MSat", "MSats", "MBTC", "Mbtc", "PBTC"];
for denom in confusing.iter() { for denom in confusing.iter() {
match Denomination::from_str(denom) { match Denomination::from_str(denom) {
Ok(_) => panic!("from_str should error for {}", denom), Ok(_) => panic!("from_str should error for {}", denom),
Err(ParseAmountError::PossiblyConfusingDenomination(_)) => {}, Err(ParseAmountError::PossiblyConfusingDenomination(_)) => {}
Err(e) => panic!("unexpected error: {}", e), Err(e) => panic!("unexpected error: {}", e),
} }
} }
@ -2207,7 +2178,7 @@ mod tests {
for denom in unknown.iter() { for denom in unknown.iter() {
match Denomination::from_str(denom) { match Denomination::from_str(denom) {
Ok(_) => panic!("from_str should error for {}", denom), Ok(_) => panic!("from_str should error for {}", denom),
Err(ParseAmountError::UnknownDenomination(_)) => {}, Err(ParseAmountError::UnknownDenomination(_)) => {}
Err(e) => panic!("unexpected error: {}", e), Err(e) => panic!("unexpected error: {}", e),
} }
} }

View File

@ -16,7 +16,7 @@ use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
use crate::hashes::{sha256, siphash24, Hash}; use crate::hashes::{sha256, siphash24, Hash};
use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding}; use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
use crate::prelude::*; use crate::prelude::*;
use crate::{io, block, Block, BlockHash, Transaction}; use crate::{block, io, Block, BlockHash, Transaction};
/// A BIP-152 error /// A BIP-152 error
#[derive(Clone, PartialEq, Eq, Debug, Copy, PartialOrd, Ord, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Copy, PartialOrd, Ord, Hash)]
@ -111,7 +111,10 @@ impl ShortId {
// 2. Running SipHash-2-4 with the input being the transaction ID and the keys (k0/k1) // 2. Running SipHash-2-4 with the input being the transaction ID and the keys (k0/k1)
// set to the first two little-endian 64-bit integers from the above hash, respectively. // set to the first two little-endian 64-bit integers from the above hash, respectively.
(u64::from_le_bytes(h[0..8].try_into().expect("8 byte slice")), u64::from_le_bytes(h[8..16].try_into().expect("8 byte slice"))) (
u64::from_le_bytes(h[0..8].try_into().expect("8 byte slice")),
u64::from_le_bytes(h[8..16].try_into().expect("8 byte slice")),
)
} }
/// Calculate the short ID with the given (w)txid and using the provided SipHash keys. /// Calculate the short ID with the given (w)txid and using the provided SipHash keys.
@ -374,8 +377,8 @@ mod test {
use crate::consensus::encode::{deserialize, serialize}; use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex; use crate::hashes::hex::FromHex;
use crate::{ use crate::{
CompactTarget, OutPoint, Script, Sequence, CompactTarget, OutPoint, Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid,
Transaction, TxIn, TxMerkleNode, TxOut, Txid, Witness, Witness,
}; };
fn dummy_tx(nonce: &[u8]) -> Transaction { fn dummy_tx(nonce: &[u8]) -> Transaction {

View File

@ -114,6 +114,7 @@ use std::io;
use core2::io; use core2::io;
pub use crate::address::{Address, AddressType}; pub use crate::address::{Address, AddressType};
pub use crate::amount::{Amount, Denomination, SignedAmount};
pub use crate::blockdata::block::{self, Block}; pub use crate::blockdata::block::{self, Block};
pub use crate::blockdata::locktime::{self, absolute, relative}; pub use crate::blockdata::locktime::{self, absolute, relative};
pub use crate::blockdata::script::{self, Script}; pub use crate::blockdata::script::{self, Script};
@ -123,12 +124,11 @@ pub use crate::blockdata::{constants, opcodes};
pub use crate::consensus::encode::VarInt; pub use crate::consensus::encode::VarInt;
pub use crate::error::Error; pub use crate::error::Error;
pub use crate::hash_types::*; pub use crate::hash_types::*;
pub use crate::merkle_tree::MerkleBlock;
pub use crate::network::constants::Network; pub use crate::network::constants::Network;
pub use crate::pow::{CompactTarget, Target, Work}; pub use crate::pow::{CompactTarget, Target, Work};
pub use crate::amount::{Amount, Denomination, SignedAmount};
pub use crate::util::ecdsa::{self, EcdsaSig, EcdsaSigError}; pub use crate::util::ecdsa::{self, EcdsaSig, EcdsaSigError};
pub use crate::util::key::{KeyPair, PrivateKey, PublicKey, XOnlyPublicKey}; pub use crate::util::key::{KeyPair, PrivateKey, PublicKey, XOnlyPublicKey};
pub use crate::merkle_tree::MerkleBlock;
pub use crate::util::schnorr::{self, SchnorrSig, SchnorrSigError}; pub use crate::util::schnorr::{self, SchnorrSig, SchnorrSigError};
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]

View File

@ -8,18 +8,18 @@
//! and legacy (before Bip143). //! and legacy (before Bip143).
//! //!
use core::{str, fmt};
use core::borrow::Borrow; use core::borrow::Borrow;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use core::{fmt, str};
use crate::{io, Script, Transaction, TxIn, TxOut, Sequence, Sighash};
use crate::blockdata::transaction::EncodeSigningDataResult; use crate::blockdata::transaction::EncodeSigningDataResult;
use crate::blockdata::witness::Witness; use crate::blockdata::witness::Witness;
use crate::consensus::{encode, Encodable}; use crate::consensus::{encode, Encodable};
use crate::error::impl_std_error; use crate::error::impl_std_error;
use crate::hashes::{sha256, sha256d, Hash}; use crate::hashes::{sha256, sha256d, Hash};
use crate::prelude::*; use crate::prelude::*;
use crate::util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash, LeafVersion}; use crate::util::taproot::{LeafVersion, TapLeafHash, TapSighashHash, TAPROOT_ANNEX_PREFIX};
use crate::{io, Script, Sequence, Sighash, Transaction, TxIn, TxOut};
/// Used for signature hash for invalid use of SIGHASH_SINGLE. /// Used for signature hash for invalid use of SIGHASH_SINGLE.
#[rustfmt::skip] #[rustfmt::skip]
@ -77,7 +77,10 @@ struct TaprootCache {
/// Contains outputs of previous transactions. In the case [`SchnorrSighashType`] variant is /// Contains outputs of previous transactions. In the case [`SchnorrSighashType`] variant is
/// `SIGHASH_ANYONECANPAY`, [`Prevouts::One`] may be used. /// `SIGHASH_ANYONECANPAY`, [`Prevouts::One`] may be used.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Prevouts<'u, T> where T: 'u + Borrow<TxOut> { pub enum Prevouts<'u, T>
where
T: 'u + Borrow<TxOut>,
{
/// `One` variant allows provision of the single prevout needed. It's useful, for example, when /// `One` variant allows provision of the single prevout needed. It's useful, for example, when
/// modifier `SIGHASH_ANYONECANPAY` is provided, only prevout of the current input is needed. /// modifier `SIGHASH_ANYONECANPAY` is provided, only prevout of the current input is needed.
/// The first `usize` argument is the input index this [`TxOut`] is referring to. /// The first `usize` argument is the input index this [`TxOut`] is referring to.
@ -233,7 +236,10 @@ impl std::error::Error for Error {
} }
} }
impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> { impl<'u, T> Prevouts<'u, T>
where
T: Borrow<TxOut>,
{
fn check_all(&self, tx: &Transaction) -> Result<(), Error> { fn check_all(&self, tx: &Transaction) -> Result<(), Error> {
if let Prevouts::All(prevouts) = self { if let Prevouts::All(prevouts) = self {
if prevouts.len() != tx.input.len() { if prevouts.len() != tx.input.len() {
@ -252,17 +258,14 @@ impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
fn get(&self, input_index: usize) -> Result<&TxOut, Error> { fn get(&self, input_index: usize) -> Result<&TxOut, Error> {
match self { match self {
Prevouts::One(index, prevout) => { Prevouts::One(index, prevout) =>
if input_index == *index { if input_index == *index {
Ok(prevout.borrow()) Ok(prevout.borrow())
} else { } else {
Err(Error::PrevoutIndex) Err(Error::PrevoutIndex)
} },
} Prevouts::All(prevouts) =>
Prevouts::All(prevouts) => prevouts prevouts.get(input_index).map(|x| x.borrow()).ok_or(Error::PrevoutIndex),
.get(input_index)
.map(|x| x.borrow())
.ok_or(Error::PrevoutIndex),
} }
} }
} }
@ -270,20 +273,18 @@ impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
impl<'s> ScriptPath<'s> { impl<'s> ScriptPath<'s> {
/// Creates a new `ScriptPath` structure. /// Creates a new `ScriptPath` structure.
pub fn new(script: &'s Script, leaf_version: LeafVersion) -> Self { pub fn new(script: &'s Script, leaf_version: LeafVersion) -> Self {
ScriptPath { ScriptPath { script, leaf_version }
script,
leaf_version,
}
} }
/// Creates a new `ScriptPath` structure using default leaf version value. /// Creates a new `ScriptPath` structure using default leaf version value.
pub fn with_defaults(script: &'s Script) -> Self { pub fn with_defaults(script: &'s Script) -> Self { Self::new(script, LeafVersion::TapScript) }
Self::new(script, LeafVersion::TapScript)
}
/// Computes the leaf hash for this `ScriptPath`. /// Computes the leaf hash for this `ScriptPath`.
pub fn leaf_hash(&self) -> TapLeafHash { pub fn leaf_hash(&self) -> TapLeafHash {
let mut enc = TapLeafHash::engine(); let mut enc = TapLeafHash::engine();
self.leaf_version.to_consensus().consensus_encode(&mut enc).expect("Writing to hash enging should never fail"); 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"); self.script.consensus_encode(&mut enc).expect("Writing to hash enging should never fail");
TapLeafHash::from_engine(enc) TapLeafHash::from_engine(enc)
@ -291,9 +292,7 @@ impl<'s> ScriptPath<'s> {
} }
impl<'s> From<ScriptPath<'s>> for TapLeafHash { impl<'s> From<ScriptPath<'s>> for TapLeafHash {
fn from(script_path: ScriptPath<'s>) -> TapLeafHash { fn from(script_path: ScriptPath<'s>) -> TapLeafHash { script_path.leaf_hash() }
script_path.leaf_hash()
}
} }
/// Hashtype of an input's signature, encoded in the last byte of the signature. /// Hashtype of an input's signature, encoded in the last byte of the signature.
@ -316,7 +315,7 @@ pub enum EcdsaSighashType {
/// 0x82: Sign no outputs and only this input. /// 0x82: Sign no outputs and only this input.
NonePlusAnyoneCanPay = 0x82, NonePlusAnyoneCanPay = 0x82,
/// 0x83: Sign one output and only this input (see `Single` for what "one output" means). /// 0x83: Sign one output and only this input (see `Single` for what "one output" means).
SinglePlusAnyoneCanPay = 0x83 SinglePlusAnyoneCanPay = 0x83,
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
crate::serde_utils::serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data"); crate::serde_utils::serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data");
@ -360,7 +359,7 @@ impl EcdsaSighashType {
EcdsaSighashType::Single => (EcdsaSighashType::Single, false), EcdsaSighashType::Single => (EcdsaSighashType::Single, false),
EcdsaSighashType::AllPlusAnyoneCanPay => (EcdsaSighashType::All, true), EcdsaSighashType::AllPlusAnyoneCanPay => (EcdsaSighashType::All, true),
EcdsaSighashType::NonePlusAnyoneCanPay => (EcdsaSighashType::None, true), EcdsaSighashType::NonePlusAnyoneCanPay => (EcdsaSighashType::None, true),
EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true) EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true),
} }
} }
@ -389,7 +388,7 @@ impl EcdsaSighashType {
0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay, 0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay,
// catchalls // catchalls
x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay, x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay,
_ => EcdsaSighashType::All _ => EcdsaSighashType::All,
} }
} }
@ -407,7 +406,7 @@ impl EcdsaSighashType {
0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), 0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay),
0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), 0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay),
0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), 0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay),
non_standard => Err(NonStandardSighashType(non_standard)) non_standard => Err(NonStandardSighashType(non_standard)),
} }
} }
@ -498,12 +497,7 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
/// sighashes to be valid, no fields in the transaction may change except for script_sig and /// sighashes to be valid, no fields in the transaction may change except for script_sig and
/// witness. /// witness.
pub fn new(tx: R) -> Self { pub fn new(tx: R) -> Self {
SighashCache { SighashCache { tx, common_cache: None, taproot_cache: None, segwit_cache: None }
tx,
common_cache: None,
taproot_cache: None,
segwit_cache: None,
}
} }
/// Encodes the BIP341 signing data for any flag type into a given object implementing a /// Encodes the BIP341 signing data for any flag type into a given object implementing a
@ -542,15 +536,9 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
// sha_sequences (32): the SHA256 of the serialization of all input nSequence. // sha_sequences (32): the SHA256 of the serialization of all input nSequence.
if !anyone_can_pay { if !anyone_can_pay {
self.common_cache().prevouts.consensus_encode(&mut writer)?; self.common_cache().prevouts.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?) self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(&mut writer)?;
.amounts self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(&mut writer)?;
.consensus_encode(&mut writer)?; self.common_cache().sequences.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?)
.script_pubkeys
.consensus_encode(&mut writer)?;
self.common_cache()
.sequences
.consensus_encode(&mut writer)?;
} }
// If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE: // If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE:
@ -577,21 +565,14 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
// scriptPubKey (35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes. // scriptPubKey (35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
// nSequence (4): nSequence of this input. // nSequence (4): nSequence of this input.
if anyone_can_pay { if anyone_can_pay {
let txin = let txin = &self.tx.input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
&self
.tx
.input
.get(input_index)
.ok_or(Error::IndexOutOfInputsBounds {
index: input_index, index: input_index,
inputs_size: self.tx.input.len(), inputs_size: self.tx.input.len(),
})?; })?;
let previous_output = prevouts.get(input_index)?; let previous_output = prevouts.get(input_index)?;
txin.previous_output.consensus_encode(&mut writer)?; txin.previous_output.consensus_encode(&mut writer)?;
previous_output.value.consensus_encode(&mut writer)?; previous_output.value.consensus_encode(&mut writer)?;
previous_output previous_output.script_pubkey.consensus_encode(&mut writer)?;
.script_pubkey
.consensus_encode(&mut writer)?;
txin.sequence.consensus_encode(&mut writer)?; txin.sequence.consensus_encode(&mut writer)?;
} else { } else {
(input_index as u32).consensus_encode(&mut writer)?; (input_index as u32).consensus_encode(&mut writer)?;
@ -726,20 +707,13 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
&& sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::Single
&& sighash != EcdsaSighashType::None && sighash != EcdsaSighashType::None
{ {
self.segwit_cache() self.segwit_cache().sequences.consensus_encode(&mut writer)?;
.sequences
.consensus_encode(&mut writer)?;
} else { } else {
zero_hash.consensus_encode(&mut writer)?; zero_hash.consensus_encode(&mut writer)?;
} }
{ {
let txin = let txin = &self.tx.input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
&self
.tx
.input
.get(input_index)
.ok_or(Error::IndexOutOfInputsBounds {
index: input_index, index: input_index,
inputs_size: self.tx.input.len(), inputs_size: self.tx.input.len(),
})?; })?;
@ -836,7 +810,8 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
script_pubkey: &Script, script_pubkey: &Script,
sighash_type: u32, sighash_type: u32,
) -> Result<(), io::Error> { ) -> Result<(), io::Error> {
let (sighash, anyone_can_pay) = EcdsaSighashType::from_consensus(sighash_type).split_anyonecanpay_flag(); let (sighash, anyone_can_pay) =
EcdsaSighashType::from_consensus(sighash_type).split_anyonecanpay_flag();
// Build tx to sign // Build tx to sign
let mut tx = Transaction { let mut tx = Transaction {
@ -858,8 +833,19 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
for (n, input) in self_.input.iter().enumerate() { for (n, input) in self_.input.iter().enumerate() {
tx.input.push(TxIn { tx.input.push(TxIn {
previous_output: input.previous_output, previous_output: input.previous_output,
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() }, script_sig: if n == input_index {
sequence: if n != input_index && (sighash == EcdsaSighashType::Single || sighash == EcdsaSighashType::None) { Sequence::ZERO } else { input.sequence }, script_pubkey.clone()
} else {
Script::new()
},
sequence: if n != input_index
&& (sighash == EcdsaSighashType::Single
|| sighash == EcdsaSighashType::None)
{
Sequence::ZERO
} else {
input.sequence
},
witness: Witness::default(), witness: Witness::default(),
}); });
} }
@ -868,14 +854,24 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
tx.output = match sighash { tx.output = match sighash {
EcdsaSighashType::All => self_.output.clone(), EcdsaSighashType::All => self_.output.clone(),
EcdsaSighashType::Single => { EcdsaSighashType::Single => {
let output_iter = self_.output.iter() let output_iter = self_
.output
.iter()
.take(input_index + 1) // sign all outputs up to and including this one, but erase .take(input_index + 1) // sign all outputs up to and including this one, but erase
.enumerate() // all of them except for this one .enumerate() // all of them except for this one
.map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() }); .map(
|(n, out)| {
if n == input_index {
out.clone()
} else {
TxOut::default()
}
},
);
output_iter.collect() output_iter.collect()
} }
EcdsaSighashType::None => vec![], EcdsaSighashType::None => vec![],
_ => unreachable!() _ => unreachable!(),
}; };
// hash the result // hash the result
tx.consensus_encode(&mut writer)?; tx.consensus_encode(&mut writer)?;
@ -889,8 +885,9 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
writer, writer,
input_index, input_index,
script_pubkey, script_pubkey,
sighash_type sighash_type,
).map_err(|e| Error::Io(e.kind())) )
.map_err(|e| Error::Io(e.kind())),
) )
} }
@ -920,8 +917,10 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
sighash_type: u32, sighash_type: u32,
) -> Result<Sighash, Error> { ) -> Result<Sighash, Error> {
let mut enc = Sighash::engine(); let mut enc = Sighash::engine();
if self.legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type) if self
.is_sighash_single_bug()? { .legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type)
.is_sighash_single_bug()?
{
Ok(Sighash::from_inner(UINT256_ONE)) Ok(Sighash::from_inner(UINT256_ONE))
} else { } else {
Ok(Sighash::from_engine(enc)) Ok(Sighash::from_engine(enc))
@ -941,9 +940,7 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
let mut enc_prevouts = sha256::Hash::engine(); let mut enc_prevouts = sha256::Hash::engine();
let mut enc_sequences = sha256::Hash::engine(); let mut enc_sequences = sha256::Hash::engine();
for txin in tx.input.iter() { for txin in tx.input.iter() {
txin.previous_output txin.previous_output.consensus_encode(&mut enc_prevouts).unwrap();
.consensus_encode(&mut enc_prevouts)
.unwrap();
txin.sequence.consensus_encode(&mut enc_sequences).unwrap(); txin.sequence.consensus_encode(&mut enc_sequences).unwrap();
} }
CommonCache { CommonCache {
@ -979,18 +976,13 @@ impl<R: Deref<Target = Transaction>> SighashCache<R> {
}) })
} }
fn taproot_cache<T: Borrow<TxOut>>(&mut self, prevouts: &[T]) -> &TaprootCache fn taproot_cache<T: Borrow<TxOut>>(&mut self, prevouts: &[T]) -> &TaprootCache {
{
self.taproot_cache.get_or_insert_with(|| { self.taproot_cache.get_or_insert_with(|| {
let mut enc_amounts = sha256::Hash::engine(); let mut enc_amounts = sha256::Hash::engine();
let mut enc_script_pubkeys = sha256::Hash::engine(); let mut enc_script_pubkeys = sha256::Hash::engine();
for prevout in prevouts { for prevout in prevouts {
prevout.borrow().value.consensus_encode(&mut enc_amounts).unwrap(); prevout.borrow().value.consensus_encode(&mut enc_amounts).unwrap();
prevout prevout.borrow().script_pubkey.consensus_encode(&mut enc_script_pubkeys).unwrap();
.borrow()
.script_pubkey
.consensus_encode(&mut enc_script_pubkeys)
.unwrap();
} }
TaprootCache { TaprootCache {
amounts: sha256::Hash::from_engine(enc_amounts), amounts: sha256::Hash::from_engine(enc_amounts),
@ -1026,9 +1018,7 @@ impl<R: DerefMut<Target=Transaction>> SighashCache<R> {
} }
impl From<io::Error> for Error { impl From<io::Error> for Error {
fn from(e: io::Error) -> Self { fn from(e: io::Error) -> Self { Error::Io(e.kind()) }
Error::Io(e.kind())
}
} }
/// The `Annex` struct is a slice wrapper enforcing first byte is `0x50`. /// The `Annex` struct is a slice wrapper enforcing first byte is `0x50`.
@ -1046,9 +1036,7 @@ impl<'a> Annex<'a> {
} }
/// Returns the Annex bytes data (including first byte `0x50`). /// Returns the Annex bytes data (including first byte `0x50`).
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] { self.0 }
self.0
}
} }
impl<'a> Encodable for Annex<'a> { impl<'a> Encodable for Annex<'a> {
@ -1064,23 +1052,22 @@ fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, output_len
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use std::str::FromStr; use std::str::FromStr;
use secp256k1::{self, SecretKey, XOnlyPublicKey}; use secp256k1::{self, SecretKey, XOnlyPublicKey};
use crate::{Script, Transaction, TxIn, TxOut, Address}; use super::*;
use crate::blockdata::locktime::absolute; use crate::blockdata::locktime::absolute;
use crate::consensus::deserialize; use crate::consensus::deserialize;
use crate::hash_types::Sighash;
use crate::hashes::hex::{FromHex, ToHex}; use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::{Hash, HashEngine}; use crate::hashes::{Hash, HashEngine};
use crate::hash_types::Sighash; use crate::internal_macros::{hex_decode, hex_from_slice, hex_into, hex_script};
use crate::internal_macros::{hex_into, hex_script, hex_decode, hex_from_slice};
use crate::network::constants::Network; use crate::network::constants::Network;
use crate::util::key::PublicKey;
use crate::sighash::{Annex, Error, Prevouts, ScriptPath, SighashCache}; use crate::sighash::{Annex, Error, Prevouts, ScriptPath, SighashCache};
use crate::util::taproot::{TapTweakHash, TapSighashHash, TapBranchHash, TapLeafHash}; use crate::util::key::PublicKey;
use crate::util::taproot::{TapBranchHash, TapLeafHash, TapSighashHash, TapTweakHash};
use crate::{Address, Script, Transaction, TxIn, TxOut};
extern crate serde_json; extern crate serde_json;
@ -1108,9 +1095,16 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn legacy_sighash() { fn legacy_sighash() {
use serde_json::Value; use serde_json::Value;
use crate::sighash::SighashCache; use crate::sighash::SighashCache;
fn run_test_sighash(tx: &str, script: &str, input_index: usize, hash_type: i64, expected_result: &str) { fn run_test_sighash(
tx: &str,
script: &str,
input_index: usize,
hash_type: i64,
expected_result: &str,
) {
let tx: Transaction = deserialize(&Vec::from_hex(tx).unwrap()[..]).unwrap(); let tx: Transaction = deserialize(&Vec::from_hex(tx).unwrap()[..]).unwrap();
let script = Script::from(Vec::from_hex(script).unwrap()); let script = Script::from(Vec::from_hex(script).unwrap());
let mut raw_expected = Vec::from_hex(expected_result).unwrap(); let mut raw_expected = Vec::from_hex(expected_result).unwrap();
@ -1362,9 +1356,7 @@ mod tests {
let script_inner = Script::from_hex(script_hex).unwrap(); let script_inner = Script::from_hex(script_hex).unwrap();
Some(ScriptPath::with_defaults(&script_inner).leaf_hash()) Some(ScriptPath::with_defaults(&script_inner).leaf_hash())
} }
(_, Some(script_leaf_hash)) => { (_, Some(script_leaf_hash)) => Some(TapLeafHash::from_hex(script_leaf_hash).unwrap()),
Some(TapLeafHash::from_hex(script_leaf_hash).unwrap())
}
_ => None, _ => None,
}; };
// All our tests use the default `0xFFFFFFFF` codeseparator value // All our tests use the default `0xFFFFFFFF` codeseparator value
@ -1389,13 +1381,13 @@ mod tests {
#[test] #[test]
fn bip_341_sighash_tests() { fn bip_341_sighash_tests() {
let data = bip_341_read_json(); let data = bip_341_read_json();
assert!(data["version"].as_u64().unwrap() == 1u64); assert!(data["version"].as_u64().unwrap() == 1u64);
let secp = &secp256k1::Secp256k1::new(); let secp = &secp256k1::Secp256k1::new();
let key_path = &data["keyPathSpending"].as_array().unwrap()[0]; let key_path = &data["keyPathSpending"].as_array().unwrap()[0];
let raw_unsigned_tx = hex_decode!(Transaction, key_path["given"]["rawUnsignedTx"].as_str().unwrap()); let raw_unsigned_tx =
hex_decode!(Transaction, key_path["given"]["rawUnsignedTx"].as_str().unwrap());
let mut utxos = vec![]; let mut utxos = vec![];
for utxo in key_path["given"]["utxosSpent"].as_array().unwrap() { for utxo in key_path["given"]["utxosSpent"].as_array().unwrap() {
let spk = hex_script!(utxo["scriptPubKey"].as_str().unwrap()); let spk = hex_script!(utxo["scriptPubKey"].as_str().unwrap());
@ -1420,24 +1412,41 @@ mod tests {
for inp in key_path["inputSpending"].as_array().unwrap() { for inp in key_path["inputSpending"].as_array().unwrap() {
let tx_ind = inp["given"]["txinIndex"].as_u64().unwrap() as usize; let tx_ind = inp["given"]["txinIndex"].as_u64().unwrap() as usize;
let internal_priv_key = hex_from_slice!(SecretKey, inp["given"]["internalPrivkey"].as_str().unwrap()); let internal_priv_key =
hex_from_slice!(SecretKey, inp["given"]["internalPrivkey"].as_str().unwrap());
let merkle_root = if inp["given"]["merkleRoot"].is_null() { let merkle_root = if inp["given"]["merkleRoot"].is_null() {
None None
} else { } else {
Some(hex_into!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap())) Some(hex_into!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap()))
}; };
let hash_ty = SchnorrSighashType::from_consensus_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap(); let hash_ty = SchnorrSighashType::from_consensus_u8(
inp["given"]["hashType"].as_u64().unwrap() as u8,
)
.unwrap();
let expected_internal_pk = hex_from_slice!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap()); let expected_internal_pk = hex_from_slice!(
let expected_tweak = hex_into!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap()); XOnlyPublicKey,
let expected_tweaked_priv_key = hex_from_slice!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap()); inp["intermediary"]["internalPubkey"].as_str().unwrap()
let expected_sig_msg = Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap(); );
let expected_sighash = hex_into!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap()); let expected_tweak =
hex_into!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap());
let expected_tweaked_priv_key =
hex_from_slice!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap());
let expected_sig_msg =
Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap();
let expected_sighash =
hex_into!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap());
let sig_str = inp["expected"]["witness"][0].as_str().unwrap(); let sig_str = inp["expected"]["witness"][0].as_str().unwrap();
let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 { let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 {
(secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default) (
secp256k1::schnorr::Signature::from_str(sig_str).unwrap(),
SchnorrSighashType::Default,
)
} else { } else {
let hash_ty = SchnorrSighashType::from_consensus_u8(Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0]).unwrap(); let hash_ty = SchnorrSighashType::from_consensus_u8(
Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0],
)
.unwrap();
(secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty) (secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty)
}; };
@ -1447,21 +1456,19 @@ mod tests {
let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root); let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
let tweaked_keypair = keypair.add_xonly_tweak(secp, &tweak.to_scalar()).unwrap(); let tweaked_keypair = keypair.add_xonly_tweak(secp, &tweak.to_scalar()).unwrap();
let mut sig_msg = Vec::new(); let mut sig_msg = Vec::new();
cache.taproot_encode_signing_data_to( cache
.taproot_encode_signing_data_to(
&mut sig_msg, &mut sig_msg,
tx_ind, tx_ind,
&Prevouts::All(&utxos), &Prevouts::All(&utxos),
None, None,
None, None,
hash_ty hash_ty,
).unwrap(); )
let sighash = cache.taproot_signature_hash( .unwrap();
tx_ind, let sighash = cache
&Prevouts::All(&utxos), .taproot_signature_hash(tx_ind, &Prevouts::All(&utxos), None, None, hash_ty)
None, .unwrap();
None,
hash_ty
).unwrap();
let msg = secp256k1::Message::from(sighash); let msg = secp256k1::Message::from(sighash);
let key_spend_sig = secp.sign_schnorr_with_aux_rand(&msg, &tweaked_keypair, &[0u8; 32]); let key_spend_sig = secp.sign_schnorr_with_aux_rand(&msg, &tweaked_keypair, &[0u8; 32]);
@ -1513,7 +1520,10 @@ mod tests {
"SigHash_NONE", "SigHash_NONE",
]; ];
for s in sht_mistakes { for s in sht_mistakes {
assert_eq!(SchnorrSighashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s)); assert_eq!(
SchnorrSighashType::from_str(s).unwrap_err().to_string(),
format!("Unrecognized SIGHASH string '{}'", s)
);
} }
} }
@ -1533,25 +1543,32 @@ mod tests {
).unwrap()[..], ).unwrap()[..],
).unwrap(); ).unwrap();
let witness_script = p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"); let witness_script =
p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357");
let value = 600_000_000; let value = 600_000_000;
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(), cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_from_slice!(Sighash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") hex_from_slice!(
Sighash,
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670"
)
); );
let cache = cache.segwit_cache(); let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_from_slice!( assert_eq!(
"96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37" cache.prevouts,
)); hex_from_slice!("96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37")
assert_eq!(cache.sequences, hex_from_slice!( );
"52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b" assert_eq!(
)); cache.sequences,
assert_eq!(cache.outputs, hex_from_slice!( hex_from_slice!("52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b")
"863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5" );
)); assert_eq!(
cache.outputs,
hex_from_slice!("863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5")
);
} }
#[test] #[test]
@ -1564,25 +1581,32 @@ mod tests {
).unwrap()[..], ).unwrap()[..],
).unwrap(); ).unwrap();
let witness_script = p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873"); let witness_script =
p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873");
let value = 1_000_000_000; let value = 1_000_000_000;
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(), cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_from_slice!(Sighash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") hex_from_slice!(
Sighash,
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6"
)
); );
let cache = cache.segwit_cache(); let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_from_slice!( assert_eq!(
"b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a" cache.prevouts,
)); hex_from_slice!("b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a")
assert_eq!(cache.sequences, hex_from_slice!( );
"18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198" assert_eq!(
)); cache.sequences,
assert_eq!(cache.outputs, hex_from_slice!( hex_from_slice!("18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198")
"de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83" );
)); assert_eq!(
cache.outputs,
hex_from_slice!("de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83")
);
} }
#[test] #[test]
@ -1607,18 +1631,24 @@ mod tests {
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(), cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_from_slice!(Sighash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c") hex_from_slice!(
Sighash,
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c"
)
); );
let cache = cache.segwit_cache(); let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_from_slice!( assert_eq!(
"74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0" cache.prevouts,
)); hex_from_slice!("74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0")
assert_eq!(cache.sequences, hex_from_slice!( );
"3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044" assert_eq!(
)); cache.sequences,
assert_eq!(cache.outputs, hex_from_slice!( hex_from_slice!("3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044")
"bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc" );
)); assert_eq!(
cache.outputs,
hex_from_slice!("bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc")
);
} }
} }