2d6467f980 Add cargo fmt to pre-commit githook (Tobin C. Harding)
55312f2972 Update contributing docs re cargo fmt (Tobin C. Harding)
c1360067e9 Enable formatting in CI (Tobin C. Harding)
61c560baba Improve the DO_BENCH error message (Tobin C. Harding)
a11cf07501 Run the formatter (Tobin C. Harding)
21d716b313 Use new fn_params_layout option (Tobin C. Harding)

Pull request description:

  Run the formatter in CI so we stop continually introducing formatting problems in the code that is currently supposed to be formatted.

ACKs for top commit:
  apoelstra:
    ACK 2d6467f980
  sanket1729:
    ACK 2d6467f980

Tree-SHA512: 0dbe12bb853b0ec6102066118a9272462bf9ebf2dc53b1394c294185b9d4a824ba0cca478f500fcc44088e4bc54a61153402a6911f285435b68bc9a306f9f11f
This commit is contained in:
Andrew Poelstra 2023-03-07 12:52:01 +00:00
commit e074ee4316
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
31 changed files with 387 additions and 354 deletions

View File

@ -53,6 +53,7 @@ jobs:
uses: dtolnay/rust-toolchain@nightly uses: dtolnay/rust-toolchain@nightly
- name: Running test script - name: Running test script
env: env:
DO_FMT: true
DO_BENCH: true DO_BENCH: true
AS_DEPENDENCY: false AS_DEPENDENCY: false
DO_NO_STD: true DO_NO_STD: true

View File

@ -170,9 +170,9 @@ Library reflects Bitcoin Core approach whenever possible.
### Formatting ### Formatting
The repository currently does use `rustfmt`. The introduction of this is still The repository currently uses `rustfmt` (WIP, some directories are excluded). We use nightly
WIP (see 'ignore' in `rustfmt.toml`) but we are working towards full features so to run the formatter use `cargo +nightly fmt`. (Remember that your editor may be
formatting. configured to fmt with a stable toolchain, this will result in many unwanted changes.)
### Naming conventions ### Naming conventions

View File

@ -12,11 +12,16 @@ fi
cargo --version cargo --version
rustc --version rustc --version
# Work out if we are using a nightly toolchain. # Some tests require certain toolchain types.
NIGHTLY=false NIGHTLY=false
STABLE=true
if cargo --version | grep nightly; then if cargo --version | grep nightly; then
STABLE=false
NIGHTLY=true NIGHTLY=true
fi fi
if cargo --version | grep beta; then
STABLE=false
fi
# Pin dependencies as required if we are using MSRV toolchain. # Pin dependencies as required if we are using MSRV toolchain.
if cargo --version | grep "1\.41"; then if cargo --version | grep "1\.41"; then
@ -106,16 +111,24 @@ then
) )
fi fi
# Run formatter if told to.
if [ "$DO_FMT" = true ]; then
if [ "$NIGHTLY" = false ]; then
echo "DO_FMT requires a nightly toolchain (consider using RUSTUP_TOOLCHAIN)"
exit 1
fi
rustup component add rustfmt
cargo fmt --check
fi
# Bench if told to, only works with non-stable toolchain (nightly, beta). # Bench if told to, only works with non-stable toolchain (nightly, beta).
if [ "$DO_BENCH" = true ] if [ "$DO_BENCH" = true ]
then then
if [ "$NIGHTLY" = false ] if [ "$STABLE" = true ]; then
then if [ -n "$RUSTUP_TOOLCHAIN" ]; then
if [ -n "$RUSTUP_TOOLCHAIN" ] echo "RUSTUP_TOOLCHAIN is set to a stable toolchain but DO_BENCH requires a non-stable (beta, nightly) toolchain"
then
echo "RUSTUP_TOOLCHAIN is set to a non-nightly toolchain but DO_BENCH requires a nightly toolchain"
else else
echo "DO_BENCH requires a nightly toolchain" echo "DO_BENCH requires a non-stable (beta, nightly) toolchain"
fi fi
exit 1 exit 1
fi fi

View File

@ -176,8 +176,7 @@ impl WatchOnly {
/// Creates the PSBT, in BIP174 parlance this is the 'Creater'. /// Creates the PSBT, in BIP174 parlance this is the 'Creater'.
fn create_psbt<C: Verification>(&self, secp: &Secp256k1<C>) -> Result<Psbt> { fn create_psbt<C: Verification>(&self, secp: &Secp256k1<C>) -> Result<Psbt> {
let to_address = Address::from_str(RECEIVE_ADDRESS)? let to_address = Address::from_str(RECEIVE_ADDRESS)?.require_network(Network::Regtest)?;
.require_network(Network::Regtest)?;
let to_amount = Amount::from_str(OUTPUT_AMOUNT_BTC)?; let to_amount = Amount::from_str(OUTPUT_AMOUNT_BTC)?;
let (_, change_address, _) = self.change_address(secp)?; let (_, change_address, _) = self.change_address(secp)?;
@ -187,10 +186,7 @@ impl WatchOnly {
version: 2, version: 2,
lock_time: absolute::LockTime::ZERO, lock_time: absolute::LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { previous_output: OutPoint { txid: INPUT_UTXO_TXID.parse()?, vout: INPUT_UTXO_VOUT },
txid: INPUT_UTXO_TXID.parse()?,
vout: INPUT_UTXO_VOUT,
},
script_sig: ScriptBuf::new(), script_sig: ScriptBuf::new(),
sequence: Sequence::MAX, // Disable LockTime and RBF. sequence: Sequence::MAX, // Disable LockTime and RBF.
witness: Witness::default(), witness: Witness::default(),

View File

@ -88,7 +88,8 @@ use bitcoin::secp256k1::Secp256k1;
use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType}; use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo}; use bitcoin::taproot::{self, LeafVersion, TapLeafHash, TaprootBuilder, TaprootSpendInfo};
use bitcoin::{ use bitcoin::{
absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness, absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut,
Witness,
}; };
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
@ -233,10 +234,7 @@ fn generate_bip86_key_spend_tx(
version: 2, version: 2,
lock_time: absolute::LockTime::ZERO, lock_time: absolute::LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { previous_output: OutPoint { txid: input_utxo.txid.parse()?, vout: input_utxo.vout },
txid: input_utxo.txid.parse()?,
vout: input_utxo.vout,
},
script_sig: ScriptBuf::new(), script_sig: ScriptBuf::new(),
sequence: bitcoin::Sequence(0xFFFFFFFF), // Ignore nSequence. sequence: bitcoin::Sequence(0xFFFFFFFF), // Ignore nSequence.
witness: Witness::default(), witness: Witness::default(),
@ -363,7 +361,10 @@ impl BenefactorWallet {
}) })
} }
fn time_lock_script(locktime: absolute::LockTime, beneficiary_key: XOnlyPublicKey) -> ScriptBuf { fn time_lock_script(
locktime: absolute::LockTime,
beneficiary_key: XOnlyPublicKey,
) -> ScriptBuf {
script::Builder::new() script::Builder::new()
.push_int(locktime.to_consensus_u32() as i64) .push_int(locktime.to_consensus_u32() as i64)
.push_opcode(OP_CLTV) .push_opcode(OP_CLTV)

View File

@ -43,7 +43,9 @@ use crate::blockdata::constants::{
}; };
use crate::blockdata::opcodes; use crate::blockdata::opcodes;
use crate::blockdata::opcodes::all::*; use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::{self, Instruction, Script, ScriptBuf, PushBytes, PushBytesBuf, PushBytesErrorReport}; use crate::blockdata::script::{
self, Instruction, PushBytes, PushBytesBuf, PushBytesErrorReport, Script, ScriptBuf,
};
use crate::crypto::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey}; use crate::crypto::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
use crate::error::ParseIntError; use crate::error::ParseIntError;
use crate::hash_types::{PubkeyHash, ScriptHash}; use crate::hash_types::{PubkeyHash, ScriptHash};
@ -94,8 +96,8 @@ pub enum Error {
/// Network on which the address was found to be valid. /// Network on which the address was found to be valid.
found: Network, found: Network,
/// The address itself /// The address itself
address: Address<NetworkUnchecked> address: Address<NetworkUnchecked>,
} },
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -412,8 +414,13 @@ pub struct WitnessProgram {
impl WitnessProgram { impl WitnessProgram {
/// Creates a new witness program. /// Creates a new witness program.
pub fn new<P>(version: WitnessVersion, program: P) -> Result<Self, Error> where P: TryInto<PushBytesBuf>, <P as TryInto<PushBytesBuf>>::Error: PushBytesErrorReport { pub fn new<P>(version: WitnessVersion, program: P) -> Result<Self, Error>
let program = program.try_into() where
P: TryInto<PushBytesBuf>,
<P as TryInto<PushBytesBuf>>::Error: PushBytesErrorReport,
{
let program = program
.try_into()
.map_err(|error| Error::InvalidWitnessProgramLength(error.input_len()))?; .map_err(|error| Error::InvalidWitnessProgramLength(error.input_len()))?;
if program.len() < 2 || program.len() > 40 { if program.len() < 2 || program.len() > 40 {
return Err(Error::InvalidWitnessProgramLength(program.len())); return Err(Error::InvalidWitnessProgramLength(program.len()));
@ -427,14 +434,10 @@ impl WitnessProgram {
} }
/// Returns the witness program version. /// Returns the witness program version.
pub fn version(&self) -> WitnessVersion { pub fn version(&self) -> WitnessVersion { self.version }
self.version
}
/// Returns the witness program. /// Returns the witness program.
pub fn program(&self) -> &PushBytes { pub fn program(&self) -> &PushBytes { &self.program }
&self.program
}
} }
impl Payload { impl Payload {
@ -443,21 +446,16 @@ impl Payload {
Ok(if script.is_p2pkh() { Ok(if script.is_p2pkh() {
let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long"); let bytes = script.as_bytes()[3..23].try_into().expect("statically 20B long");
Payload::PubkeyHash(PubkeyHash::from_byte_array(bytes)) Payload::PubkeyHash(PubkeyHash::from_byte_array(bytes))
} else if script.is_p2sh() { } else if script.is_p2sh() {
let bytes = script.as_bytes()[2..22].try_into().expect("statically 20B long"); let bytes = script.as_bytes()[2..22].try_into().expect("statically 20B long");
Payload::ScriptHash(ScriptHash::from_byte_array(bytes)) Payload::ScriptHash(ScriptHash::from_byte_array(bytes))
} else if script.is_witness_program() { } else if script.is_witness_program() {
let opcode = script.first_opcode().expect("witness_version guarantees len() > 4"); let opcode = script.first_opcode().expect("witness_version guarantees len() > 4");
let witness_program = script let witness_program = script.as_bytes()[2..].to_vec();
.as_bytes()[2..]
.to_vec();
let witness_program = WitnessProgram::new( let witness_program =
WitnessVersion::try_from(opcode)?, WitnessProgram::new(WitnessVersion::try_from(opcode)?, witness_program)?;
witness_program,
)?;
Payload::WitnessProgram(witness_program) Payload::WitnessProgram(witness_program)
} else { } else {
return Err(Error::UnrecognizedScript); return Err(Error::UnrecognizedScript);
@ -469,8 +467,7 @@ impl Payload {
match *self { match *self {
Payload::PubkeyHash(ref hash) => ScriptBuf::new_p2pkh(hash), Payload::PubkeyHash(ref hash) => ScriptBuf::new_p2pkh(hash),
Payload::ScriptHash(ref hash) => ScriptBuf::new_p2sh(hash), Payload::ScriptHash(ref hash) => ScriptBuf::new_p2sh(hash),
Payload::WitnessProgram(ref prog) => Payload::WitnessProgram(ref prog) => ScriptBuf::new_witness_program(prog),
ScriptBuf::new_witness_program(prog)
} }
} }
@ -478,15 +475,12 @@ impl Payload {
/// This function doesn't make any allocations. /// This function doesn't make any allocations.
pub fn matches_script_pubkey(&self, script: &Script) -> bool { pub fn matches_script_pubkey(&self, script: &Script) -> bool {
match *self { match *self {
Payload::PubkeyHash(ref hash) if script.is_p2pkh() => { Payload::PubkeyHash(ref hash) if script.is_p2pkh() =>
&script.as_bytes()[3..23] == <PubkeyHash as AsRef<[u8; 20]>>::as_ref(hash) &script.as_bytes()[3..23] == <PubkeyHash as AsRef<[u8; 20]>>::as_ref(hash),
}, Payload::ScriptHash(ref hash) if script.is_p2sh() =>
Payload::ScriptHash(ref hash) if script.is_p2sh() => { &script.as_bytes()[2..22] == <ScriptHash as AsRef<[u8; 20]>>::as_ref(hash),
&script.as_bytes()[2..22] == <ScriptHash as AsRef<[u8; 20]>>::as_ref(hash) Payload::WitnessProgram(ref prog) if script.is_witness_program() =>
}, &script.as_bytes()[2..] == prog.program.as_bytes(),
Payload::WitnessProgram(ref prog) if script.is_witness_program() => {
&script.as_bytes()[2..] == prog.program.as_bytes()
},
Payload::PubkeyHash(_) | Payload::ScriptHash(_) | Payload::WitnessProgram(_) => false, Payload::PubkeyHash(_) | Payload::ScriptHash(_) | Payload::WitnessProgram(_) => false,
} }
} }
@ -508,7 +502,7 @@ impl Payload {
pub fn p2wpkh(pk: &PublicKey) -> Result<Payload, Error> { pub fn p2wpkh(pk: &PublicKey) -> Result<Payload, Error> {
let prog = WitnessProgram::new( let prog = WitnessProgram::new(
WitnessVersion::V0, WitnessVersion::V0,
pk.wpubkey_hash().ok_or(Error::UncompressedPubkey)? pk.wpubkey_hash().ok_or(Error::UncompressedPubkey)?,
)?; )?;
Ok(Payload::WitnessProgram(prog)) Ok(Payload::WitnessProgram(prog))
} }
@ -524,17 +518,14 @@ impl Payload {
/// Create a witness pay to script hash payload. /// Create a witness pay to script hash payload.
pub fn p2wsh(script: &Script) -> Payload { pub fn p2wsh(script: &Script) -> Payload {
let prog = WitnessProgram::new( let prog = WitnessProgram::new(WitnessVersion::V0, script.wscript_hash())
WitnessVersion::V0, .expect("wscript_hash has len 32 compatible with segwitv0");
script.wscript_hash()
).expect("wscript_hash has len 32 compatible with segwitv0");
Payload::WitnessProgram(prog) Payload::WitnessProgram(prog)
} }
/// Create a pay to script payload that embeds a witness pay to script hash address /// Create a pay to script payload that embeds a witness pay to script hash address
pub fn p2shwsh(script: &Script) -> Payload { pub fn p2shwsh(script: &Script) -> Payload {
let ws = let ws = script::Builder::new().push_int(0).push_slice(script.wscript_hash()).into_script();
script::Builder::new().push_int(0).push_slice(script.wscript_hash()).into_script();
Payload::ScriptHash(ws.script_hash()) Payload::ScriptHash(ws.script_hash())
} }
@ -546,10 +537,8 @@ impl Payload {
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
) -> Payload { ) -> Payload {
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root); let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
let prog = WitnessProgram::new( let prog = WitnessProgram::new(WitnessVersion::V1, output_key.to_inner().serialize())
WitnessVersion::V1, .expect("taproot output key has len 32 <= 40");
output_key.to_inner().serialize()
).expect("taproot output key has len 32 <= 40");
Payload::WitnessProgram(prog) Payload::WitnessProgram(prog)
} }
@ -557,10 +546,8 @@ impl Payload {
/// ///
/// This method is not recommended for use and [Payload::p2tr()] should be used where possible. /// This method is not recommended for use and [Payload::p2tr()] should be used where possible.
pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Payload { pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Payload {
let prog = WitnessProgram::new( let prog = WitnessProgram::new(WitnessVersion::V1, output_key.to_inner().serialize())
WitnessVersion::V1, .expect("taproot output key has len 32 <= 40");
output_key.to_inner().serialize()
).expect("taproot output key has len 32 <= 40");
Payload::WitnessProgram(prog) Payload::WitnessProgram(prog)
} }
@ -644,8 +631,12 @@ pub enum NetworkChecked {}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NetworkUnchecked {} pub enum NetworkUnchecked {}
impl NetworkValidation for NetworkChecked { const IS_CHECKED: bool = true; } impl NetworkValidation for NetworkChecked {
impl NetworkValidation for NetworkUnchecked { const IS_CHECKED: bool = false; } const IS_CHECKED: bool = true;
}
impl NetworkValidation for NetworkUnchecked {
const IS_CHECKED: bool = false;
}
/// A Bitcoin address. /// A Bitcoin address.
/// ///
@ -792,7 +783,9 @@ impl<V: NetworkValidation> Address<V> {
WitnessVersion::V0 => match prog.program().len() { WitnessVersion::V0 => match prog.program().len() {
20 => Some(AddressType::P2wpkh), 20 => Some(AddressType::P2wpkh),
32 => Some(AddressType::P2wsh), 32 => Some(AddressType::P2wsh),
_ => unreachable!("Address creation invariant violation: invalid program length") _ => unreachable!(
"Address creation invariant violation: invalid program length"
),
}, },
WitnessVersion::V1 if prog.program().len() == 32 => Some(AddressType::P2tr), WitnessVersion::V1 if prog.program().len() == 32 => Some(AddressType::P2tr),
_ => None, _ => None,
@ -905,9 +898,7 @@ impl Address {
/// # Returns /// # Returns
/// None if unknown, non-standard or related to the future witness version. /// None if unknown, non-standard or related to the future witness version.
#[inline] #[inline]
pub fn address_type(&self) -> Option<AddressType> { pub fn address_type(&self) -> Option<AddressType> { self.address_type_internal() }
self.address_type_internal()
}
/// Checks whether or not the address is following Bitcoin standardness rules when /// Checks whether or not the address is following Bitcoin standardness rules when
/// *spending* from this address. *NOT* to be called by senders. /// *spending* from this address. *NOT* to be called by senders.
@ -1042,15 +1033,11 @@ impl Address<NetworkUnchecked> {
/// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses) /// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses)
/// on [`Address`]. /// on [`Address`].
#[inline] #[inline]
pub fn assume_checked(self) -> Address { pub fn assume_checked(self) -> Address { Address::new(self.network, self.payload) }
Address::new(self.network, self.payload)
}
} }
impl From<Address> for script::ScriptBuf { impl From<Address> for script::ScriptBuf {
fn from(a: Address) -> Self { fn from(a: Address) -> Self { a.script_pubkey() }
a.script_pubkey()
}
} }
// Alternate formatting `{:#}` is used to return uppercase version of bech32 addresses which should // Alternate formatting `{:#}` is used to return uppercase version of bech32 addresses which should
@ -1168,11 +1155,11 @@ fn segwit_redeem_hash(pubkey_hash: &PubkeyHash) -> crate::hashes::hash160::Hash
mod tests { mod tests {
use core::str::FromStr; use core::str::FromStr;
use hex_lit::hex;
use secp256k1::XOnlyPublicKey; use secp256k1::XOnlyPublicKey;
use super::*; use super::*;
use crate::crypto::key::PublicKey; use crate::crypto::key::PublicKey;
use hex_lit::hex;
use crate::network::constants::Network::{Bitcoin, Testnet}; use crate::network::constants::Network::{Bitcoin, Testnet};
fn roundtrips(addr: &Address) { fn roundtrips(addr: &Address) {
@ -1192,14 +1179,18 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
{ {
let ser = serde_json::to_string(addr).expect("failed to serialize address"); let ser = serde_json::to_string(addr).expect("failed to serialize address");
let back: Address<NetworkUnchecked> = serde_json::from_str(&ser).expect("failed to deserialize address"); let back: Address<NetworkUnchecked> =
serde_json::from_str(&ser).expect("failed to deserialize address");
assert_eq!(back.assume_checked(), *addr, "serde round-trip failed for {}", addr) assert_eq!(back.assume_checked(), *addr, "serde round-trip failed for {}", addr)
} }
} }
#[test] #[test]
fn test_p2pkh_address_58() { fn test_p2pkh_address_58() {
let addr = Address::new(Bitcoin, Payload::PubkeyHash("162c5ea71c0b23f5b9022ef047c4a86470a5b070".parse().unwrap())); let addr = Address::new(
Bitcoin,
Payload::PubkeyHash("162c5ea71c0b23f5b9022ef047c4a86470a5b070".parse().unwrap()),
);
assert_eq!( assert_eq!(
addr.script_pubkey(), addr.script_pubkey(),
@ -1216,7 +1207,9 @@ mod tests {
let addr = Address::p2pkh(&key, Bitcoin); let addr = Address::p2pkh(&key, Bitcoin);
assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY"); assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY");
let key = "03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f".parse::<PublicKey>().unwrap(); let key = "03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f"
.parse::<PublicKey>()
.unwrap();
let addr = Address::p2pkh(&key, Testnet); let addr = Address::p2pkh(&key, Testnet);
assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC"); assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC");
assert_eq!(addr.address_type(), Some(AddressType::P2pkh)); assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
@ -1225,7 +1218,10 @@ mod tests {
#[test] #[test]
fn test_p2sh_address_58() { fn test_p2sh_address_58() {
let addr = Address::new(Bitcoin, Payload::ScriptHash("162c5ea71c0b23f5b9022ef047c4a86470a5b070".parse().unwrap())); let addr = Address::new(
Bitcoin,
Payload::ScriptHash("162c5ea71c0b23f5b9022ef047c4a86470a5b070".parse().unwrap()),
);
assert_eq!( assert_eq!(
addr.script_pubkey(), addr.script_pubkey(),
@ -1254,7 +1250,9 @@ mod tests {
#[test] #[test]
fn test_p2wpkh() { fn test_p2wpkh() {
// stolen from Bitcoin transaction: b3c8c2b6cfc335abbcb2c7823a8453f55d64b2b5125a9a61e8737230cdb8ce20 // stolen from Bitcoin transaction: b3c8c2b6cfc335abbcb2c7823a8453f55d64b2b5125a9a61e8737230cdb8ce20
let mut key = "033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc".parse::<PublicKey>().unwrap(); let mut key = "033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc"
.parse::<PublicKey>()
.unwrap();
let addr = Address::p2wpkh(&key, Bitcoin).unwrap(); let addr = Address::p2wpkh(&key, Bitcoin).unwrap();
assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw"); assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw");
assert_eq!(addr.address_type(), Some(AddressType::P2wpkh)); assert_eq!(addr.address_type(), Some(AddressType::P2wpkh));
@ -1281,7 +1279,9 @@ mod tests {
#[test] #[test]
fn test_p2shwpkh() { fn test_p2shwpkh() {
// stolen from Bitcoin transaction: ad3fd9c6b52e752ba21425435ff3dd361d6ac271531fc1d2144843a9f550ad01 // stolen from Bitcoin transaction: ad3fd9c6b52e752ba21425435ff3dd361d6ac271531fc1d2144843a9f550ad01
let mut key = "026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766".parse::<PublicKey>().unwrap(); let mut key = "026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766"
.parse::<PublicKey>()
.unwrap();
let addr = Address::p2shwpkh(&key, Bitcoin).unwrap(); let addr = Address::p2shwpkh(&key, Bitcoin).unwrap();
assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE"); assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE");
assert_eq!(addr.address_type(), Some(AddressType::P2sh)); assert_eq!(addr.address_type(), Some(AddressType::P2sh));
@ -1305,7 +1305,9 @@ mod tests {
#[test] #[test]
fn test_non_existent_segwit_version() { fn test_non_existent_segwit_version() {
// 40-byte program // 40-byte program
let program = hex!("654f6ea368e0acdfd92976b7c2103a1b26313f430654f6ea368e0acdfd92976b7c2103a1b26313f4"); let program = hex!(
"654f6ea368e0acdfd92976b7c2103a1b26313f430654f6ea368e0acdfd92976b7c2103a1b26313f4"
);
let witness_prog = WitnessProgram::new(WitnessVersion::V13, program.to_vec()).unwrap(); let witness_prog = WitnessProgram::new(WitnessVersion::V13, program.to_vec()).unwrap();
let addr = Address::new(Bitcoin, Payload::WitnessProgram(witness_prog)); let addr = Address::new(Bitcoin, Payload::WitnessProgram(witness_prog));
roundtrips(&addr); roundtrips(&addr);
@ -1315,19 +1317,24 @@ mod tests {
fn test_address_debug() { fn test_address_debug() {
// This is not really testing output of Debug but the ability and proper functioning // This is not really testing output of Debug but the ability and proper functioning
// of Debug derivation on structs generic in NetworkValidation. // of Debug derivation on structs generic in NetworkValidation.
#[derive(Debug)] #[allow(unused)] #[derive(Debug)]
struct Test<V: NetworkValidation> { address: Address<V> } #[allow(unused)]
struct Test<V: NetworkValidation> {
address: Address<V>,
}
let addr_str = "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k"; let addr_str = "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k";
let unchecked = Address::from_str(addr_str).unwrap(); let unchecked = Address::from_str(addr_str).unwrap();
assert_eq!( assert_eq!(
format!("{:?}", Test { address: unchecked.clone() }), format!("{:?}", Test { address: unchecked.clone() }),
format!("Test {{ address: Address<NetworkUnchecked>({}) }}", addr_str)); format!("Test {{ address: Address<NetworkUnchecked>({}) }}", addr_str)
);
assert_eq!( assert_eq!(
format!("{:?}", Test { address: unchecked.assume_checked() }), format!("{:?}", Test { address: unchecked.assume_checked() }),
format!("Test {{ address: {} }}", addr_str)); format!("Test {{ address: {} }}", addr_str)
);
} }
#[test] #[test]
@ -1442,7 +1449,8 @@ mod tests {
fn test_json_serialize() { fn test_json_serialize() {
use serde_json; use serde_json;
let addr = Address::from_str("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM").unwrap().assume_checked(); let addr =
Address::from_str("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM").unwrap().assume_checked();
let json = serde_json::to_value(&addr).unwrap(); let json = serde_json::to_value(&addr).unwrap();
assert_eq!( assert_eq!(
json, json,
@ -1455,7 +1463,8 @@ mod tests {
ScriptBuf::from_hex("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac").unwrap() ScriptBuf::from_hex("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac").unwrap()
); );
let addr = Address::from_str("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k").unwrap().assume_checked(); let addr =
Address::from_str("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k").unwrap().assume_checked();
let json = serde_json::to_value(&addr).unwrap(); let json = serde_json::to_value(&addr).unwrap();
assert_eq!( assert_eq!(
json, json,
@ -1481,7 +1490,8 @@ mod tests {
let addr = let addr =
Address::from_str("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7") Address::from_str("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7")
.unwrap().assume_checked(); .unwrap()
.assume_checked();
let json = serde_json::to_value(&addr).unwrap(); let json = serde_json::to_value(&addr).unwrap();
assert_eq!( assert_eq!(
json, json,
@ -1493,10 +1503,15 @@ mod tests {
assert_eq!(addr.to_string(), into.to_string()); assert_eq!(addr.to_string(), into.to_string());
assert_eq!( assert_eq!(
into.script_pubkey(), into.script_pubkey(),
ScriptBuf::from_hex("00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262").unwrap() ScriptBuf::from_hex(
"00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
)
.unwrap()
); );
let addr = Address::from_str("bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl").unwrap().assume_checked(); let addr = Address::from_str("bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl")
.unwrap()
.assume_checked();
let json = serde_json::to_value(&addr).unwrap(); let json = serde_json::to_value(&addr).unwrap();
assert_eq!( assert_eq!(
json, json,
@ -1515,7 +1530,8 @@ mod tests {
for el in for el in
["132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM", "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k"].iter() ["132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM", "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k"].iter()
{ {
let addr = Address::from_str(el).unwrap().require_network(Network::Bitcoin).expect("mainnet"); let addr =
Address::from_str(el).unwrap().require_network(Network::Bitcoin).expect("mainnet");
assert_eq!(addr.to_qr_uri(), format!("bitcoin:{}", el)); assert_eq!(addr.to_qr_uri(), format!("bitcoin:{}", el));
} }
@ -1537,10 +1553,15 @@ mod tests {
Payload::ScriptHash(ScriptHash::all_zeros()), Payload::ScriptHash(ScriptHash::all_zeros()),
]; ];
let segwit_payload = (0..=16) let segwit_payload = (0..=16)
.map(|version| Payload::WitnessProgram(WitnessProgram::new( .map(|version| {
Payload::WitnessProgram(
WitnessProgram::new(
WitnessVersion::try_from(version).unwrap(), WitnessVersion::try_from(version).unwrap(),
vec![0xab; 32], // Choose 32 to make test case valid for all witness versions(including v0) vec![0xab; 32], // Choose 32 to make test case valid for all witness versions(including v0)
).unwrap())) )
.unwrap(),
)
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
const LEGACY_EQUIVALENCE_CLASSES: &[&[Network]] = const LEGACY_EQUIVALENCE_CLASSES: &[&[Network]] =
@ -1726,9 +1747,12 @@ mod tests {
#[test] #[test]
fn test_fail_address_from_script() { fn test_fail_address_from_script() {
let bad_p2wpkh = ScriptBuf::from_hex("0014dbc5b0a8f9d4353b4b54c3db48846bb15abfec").unwrap(); let bad_p2wpkh = ScriptBuf::from_hex("0014dbc5b0a8f9d4353b4b54c3db48846bb15abfec").unwrap();
let bad_p2wsh = let bad_p2wsh = ScriptBuf::from_hex(
ScriptBuf::from_hex("00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623").unwrap(); "00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623",
let invalid_segwitv0_script = ScriptBuf::from_hex("001161458e330389cd0437ee9fe3641d70cc18").unwrap(); )
.unwrap();
let invalid_segwitv0_script =
ScriptBuf::from_hex("001161458e330389cd0437ee9fe3641d70cc18").unwrap();
let expected = Err(Error::UnrecognizedScript); let expected = Err(Error::UnrecognizedScript);
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected); assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected);
@ -1765,15 +1789,10 @@ mod tests {
"bc1pgllnmtxs0g058qz7c6qgaqq4qknwrqj9z7rqn9e2dzhmcfmhlu4sfadf5e", "bc1pgllnmtxs0g058qz7c6qgaqq4qknwrqj9z7rqn9e2dzhmcfmhlu4sfadf5e",
]; ];
for addr in &addresses { for addr in &addresses {
let addr = Address::from_str(addr) let addr = Address::from_str(addr).unwrap().require_network(Network::Bitcoin).unwrap();
.unwrap()
.require_network(Network::Bitcoin)
.unwrap();
for another in &addresses { for another in &addresses {
let another = Address::from_str(another) let another =
.unwrap() Address::from_str(another).unwrap().require_network(Network::Bitcoin).unwrap();
.require_network(Network::Bitcoin)
.unwrap();
assert_eq!(addr.matches_script_pubkey(&another.script_pubkey()), addr == another); assert_eq!(addr.matches_script_pubkey(&another.script_pubkey()), addr == another);
} }
} }

View File

@ -375,8 +375,8 @@ mod test {
use super::*; use super::*;
use crate::blockdata::locktime::absolute; use crate::blockdata::locktime::absolute;
use crate::consensus::encode::{deserialize, serialize}; use crate::consensus::encode::{deserialize, serialize};
use crate::hashes::hex::FromHex;
use crate::hash_types::TxMerkleNode; use crate::hash_types::TxMerkleNode;
use crate::hashes::hex::FromHex;
use crate::{ use crate::{
CompactTarget, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, CompactTarget, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness,
}; };

View File

@ -561,8 +561,8 @@ mod test {
use super::*; use super::*;
use crate::consensus::encode::deserialize; use crate::consensus::encode::deserialize;
use crate::hash_types::BlockHash; use crate::hash_types::BlockHash;
use crate::ScriptBuf;
use crate::internal_macros::hex; use crate::internal_macros::hex;
use crate::ScriptBuf;
#[test] #[test]
fn test_blockfilters() { fn test_blockfilters() {
@ -572,8 +572,7 @@ mod test {
let testdata = serde_json::from_str::<Value>(data).unwrap().as_array().unwrap().clone(); let testdata = serde_json::from_str::<Value>(data).unwrap().as_array().unwrap().clone();
for t in testdata.iter().skip(1) { for t in testdata.iter().skip(1) {
let block_hash = t.get(1).unwrap().as_str().unwrap().parse::<BlockHash>().unwrap(); let block_hash = t.get(1).unwrap().as_str().unwrap().parse::<BlockHash>().unwrap();
let block: Block = let block: Block = deserialize(&hex!(t.get(2).unwrap().as_str().unwrap())).unwrap();
deserialize(&hex!(t.get(2).unwrap().as_str().unwrap())).unwrap();
assert_eq!(block.block_hash(), block_hash); assert_eq!(block.block_hash(), block_hash);
let scripts = t.get(3).unwrap().as_array().unwrap(); let scripts = t.get(3).unwrap().as_array().unwrap();
let previous_filter_header = let previous_filter_header =

View File

@ -475,7 +475,8 @@ impl fmt::Display for Error {
write!(f, "encoded extended key data has wrong length {}", len), write!(f, "encoded extended key data has wrong length {}", len),
Error::Base58(ref e) => write_err!(f, "base58 encoding error"; e), Error::Base58(ref e) => write_err!(f, "base58 encoding error"; e),
Error::Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e), Error::Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e),
Error::InvalidPublicKeyHexLength(got) => write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got), Error::InvalidPublicKeyHexLength(got) =>
write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got),
} }
} }
} }
@ -622,9 +623,13 @@ impl ExtendedPrivKey {
Ok(ExtendedPrivKey { Ok(ExtendedPrivKey {
network, network,
depth: data[4], depth: data[4],
parent_fingerprint: data[5..9].try_into().expect("9 - 5 == 4, which is the Fingerprint length"), parent_fingerprint: data[5..9]
.try_into()
.expect("9 - 5 == 4, which is the Fingerprint length"),
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(), child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
chain_code: data[13..45].try_into().expect("45 - 13 == 32, which is the ChainCode length"), chain_code: data[13..45]
.try_into()
.expect("45 - 13 == 32, which is the ChainCode length"),
private_key: secp256k1::SecretKey::from_slice(&data[46..78])?, private_key: secp256k1::SecretKey::from_slice(&data[46..78])?,
}) })
} }
@ -754,9 +759,13 @@ impl ExtendedPubKey {
return Err(Error::UnknownVersion(ver)); return Err(Error::UnknownVersion(ver));
}, },
depth: data[4], depth: data[4],
parent_fingerprint: data[5..9].try_into().expect("9 - 5 == 4, which is the Fingerprint length"), parent_fingerprint: data[5..9]
.try_into()
.expect("9 - 5 == 4, which is the Fingerprint length"),
child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(), child_number: u32::from_be_bytes(data[9..13].try_into().expect("4 byte slice")).into(),
chain_code: data[13..45].try_into().expect("45 - 13 == 32, which is the ChainCode length"), chain_code: data[13..45]
.try_into()
.expect("45 - 13 == 32, which is the ChainCode length"),
public_key: secp256k1::PublicKey::from_slice(&data[45..78])?, public_key: secp256k1::PublicKey::from_slice(&data[45..78])?,
}) })
} }
@ -786,7 +795,9 @@ impl ExtendedPubKey {
} }
/// Returns the first four bytes of the identifier /// Returns the first four bytes of the identifier
pub fn fingerprint(&self) -> Fingerprint { self.identifier()[0..4].try_into().expect("4 is the fingerprint length") } pub fn fingerprint(&self) -> Fingerprint {
self.identifier()[0..4].try_into().expect("4 is the fingerprint length")
}
} }
impl fmt::Display for ExtendedPrivKey { impl fmt::Display for ExtendedPrivKey {

View File

@ -84,14 +84,14 @@ macro_rules! impl_bytes_newtype {
impl core::fmt::LowerHex for $t { impl core::fmt::LowerHex for $t {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use bitcoin_internals::hex::{Case, display}; use bitcoin_internals::hex::{display, Case};
display::fmt_hex_exact!(f, $len, &self.0, Case::Lower) display::fmt_hex_exact!(f, $len, &self.0, Case::Lower)
} }
} }
impl core::fmt::UpperHex for $t { impl core::fmt::UpperHex for $t {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use bitcoin_internals::hex::{Case, display}; use bitcoin_internals::hex::{display, Case};
display::fmt_hex_exact!(f, $len, &self.0, Case::Upper) display::fmt_hex_exact!(f, $len, &self.0, Case::Upper)
} }
} }

View File

@ -37,7 +37,6 @@
#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
// Coding conventions // Coding conventions
#![warn(missing_docs)] #![warn(missing_docs)]
// Instead of littering the codebase for non-fuzzing code just globally allow. // Instead of littering the codebase for non-fuzzing code just globally allow.
#![cfg_attr(fuzzing, allow(dead_code, unused_imports))] #![cfg_attr(fuzzing, allow(dead_code, unused_imports))]
@ -132,7 +131,9 @@ pub use crate::consensus::encode::VarInt;
pub use crate::crypto::key::{self, PrivateKey, PublicKey}; pub use crate::crypto::key::{self, PrivateKey, PublicKey};
pub use crate::crypto::{ecdsa, sighash}; pub use crate::crypto::{ecdsa, sighash};
pub use crate::error::Error; pub use crate::error::Error;
pub use crate::hash_types::{Txid, Wtxid, BlockHash, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; pub use crate::hash_types::{
BlockHash, PubkeyHash, ScriptHash, Txid, WPubkeyHash, WScriptHash, Wtxid,
};
pub use crate::merkle_tree::MerkleBlock; 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};

View File

@ -41,6 +41,7 @@
use core::fmt; use core::fmt;
use self::MerkleBlockError::*;
use crate::blockdata::block::{self, Block}; use crate::blockdata::block::{self, Block};
use crate::blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT}; use crate::blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT};
use crate::blockdata::transaction::Transaction; use crate::blockdata::transaction::Transaction;
@ -49,7 +50,6 @@ use crate::hash_types::{TxMerkleNode, Txid};
use crate::hashes::Hash; use crate::hashes::Hash;
use crate::io; use crate::io;
use crate::prelude::*; use crate::prelude::*;
use self::MerkleBlockError::*;
/// Data structure that represents a block header paired to a partial merkle tree. /// Data structure that represents a block header paired to a partial merkle tree.
/// ///
@ -509,8 +509,9 @@ impl std::error::Error for MerkleBlockError {
use self::MerkleBlockError::*; use self::MerkleBlockError::*;
match *self { match *self {
MerkleRootMismatch | NoTransactions | TooManyTransactions | TooManyHashes | NotEnoughBits | NotAllBitsConsumed | MerkleRootMismatch | NoTransactions | TooManyTransactions | TooManyHashes
NotAllHashesConsumed | BitsArrayOverflow | HashesArrayOverflow | IdenticalHashesFound => None, | NotEnoughBits | NotAllBitsConsumed | NotAllHashesConsumed | BitsArrayOverflow
| HashesArrayOverflow | IdenticalHashesFound => None,
} }
} }
} }
@ -564,6 +565,7 @@ mod tests {
#[cfg(feature = "rand-std")] #[cfg(feature = "rand-std")]
fn pmt_test(tx_count: usize) { fn pmt_test(tx_count: usize) {
use core::cmp::min; use core::cmp::min;
use crate::merkle_tree; use crate::merkle_tree;
let mut rng = thread_rng(); let mut rng = thread_rng();

View File

@ -454,8 +454,7 @@ mod test {
assert!(deserialize::<AddrV2>(&hex!("01fd010201020304")).is_err()); assert!(deserialize::<AddrV2>(&hex!("01fd010201020304")).is_err());
// Valid IPv6. // Valid IPv6.
let ip: AddrV2 = let ip: AddrV2 = deserialize(&hex!("02100102030405060708090a0b0c0d0e0f10")).unwrap();
deserialize(&hex!("02100102030405060708090a0b0c0d0e0f10")).unwrap();
assert_eq!( assert_eq!(
ip, ip,
AddrV2::Ipv6(Ipv6Addr::from_str("102:304:506:708:90a:b0c:d0e:f10").unwrap()) AddrV2::Ipv6(Ipv6Addr::from_str("102:304:506:708:90a:b0c:d0e:f10").unwrap())
@ -465,16 +464,10 @@ mod test {
assert!(deserialize::<AddrV2>(&hex!("020400")).is_err()); assert!(deserialize::<AddrV2>(&hex!("020400")).is_err());
// Invalid IPv6, contains embedded IPv4. // Invalid IPv6, contains embedded IPv4.
assert!(deserialize::<AddrV2>( assert!(deserialize::<AddrV2>(&hex!("021000000000000000000000ffff01020304")).is_err());
&hex!("021000000000000000000000ffff01020304")
)
.is_err());
// Invalid IPv6, contains embedded TORv2. // Invalid IPv6, contains embedded TORv2.
assert!(deserialize::<AddrV2>( assert!(deserialize::<AddrV2>(&hex!("0210fd87d87eeb430102030405060708090a")).is_err());
&hex!("0210fd87d87eeb430102030405060708090a")
)
.is_err());
// Valid TORv2. // Valid TORv2.
let ip: AddrV2 = deserialize(&hex!("030af1f2f3f4f5f6f7f8f9fa")).unwrap(); let ip: AddrV2 = deserialize(&hex!("030af1f2f3f4f5f6f7f8f9fa")).unwrap();
@ -484,10 +477,9 @@ mod test {
assert!(deserialize::<AddrV2>(&hex!("030700")).is_err()); assert!(deserialize::<AddrV2>(&hex!("030700")).is_err());
// Valid TORv3. // Valid TORv3.
let ip: AddrV2 = deserialize( let ip: AddrV2 = deserialize(&hex!(
&hex!("042079bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f") "042079bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f"
, ))
)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
ip, ip,
@ -503,10 +495,9 @@ mod test {
assert!(deserialize::<AddrV2>(&hex!("040000")).is_err()); assert!(deserialize::<AddrV2>(&hex!("040000")).is_err());
// Valid I2P. // Valid I2P.
let ip: AddrV2 = deserialize( let ip: AddrV2 = deserialize(&hex!(
&hex!("0520a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87") "0520a2894dabaec08c0051a481a6dac88b64f98232ae42d4b6fd2fa81952dfe36a87"
, ))
)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
ip, ip,
@ -522,23 +513,17 @@ mod test {
assert!(deserialize::<AddrV2>(&hex!("050300")).is_err()); assert!(deserialize::<AddrV2>(&hex!("050300")).is_err());
// Valid CJDNS. // Valid CJDNS.
let ip: AddrV2 = let ip: AddrV2 = deserialize(&hex!("0610fc000001000200030004000500060007")).unwrap();
deserialize(&hex!("0610fc000001000200030004000500060007")).unwrap();
assert_eq!(ip, AddrV2::Cjdns(Ipv6Addr::from_str("fc00:1:2:3:4:5:6:7").unwrap())); assert_eq!(ip, AddrV2::Cjdns(Ipv6Addr::from_str("fc00:1:2:3:4:5:6:7").unwrap()));
// Invalid CJDNS, incorrect marker // Invalid CJDNS, incorrect marker
assert!(deserialize::<AddrV2>( assert!(deserialize::<AddrV2>(&hex!("0610fd000001000200030004000500060007")).is_err());
&hex!("0610fd000001000200030004000500060007")
)
.is_err());
// Invalid CJDNS, with bogus length. // Invalid CJDNS, with bogus length.
assert!(deserialize::<AddrV2>(&hex!("060100")).is_err()); assert!(deserialize::<AddrV2>(&hex!("060100")).is_err());
// Unknown, with extreme length. // Unknown, with extreme length.
assert!( assert!(deserialize::<AddrV2>(&hex!("aafe0000000201020304050607")).is_err());
deserialize::<AddrV2>(&hex!("aafe0000000201020304050607")).is_err()
);
// Unknown, with reasonable length. // Unknown, with reasonable length.
let ip: AddrV2 = deserialize(&hex!("aa0401020304")).unwrap(); let ip: AddrV2 = deserialize(&hex!("aa0401020304")).unwrap();

View File

@ -28,9 +28,9 @@
use core::borrow::{Borrow, BorrowMut}; use core::borrow::{Borrow, BorrowMut};
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt::Display;
use core::str::FromStr; use core::str::FromStr;
use core::{fmt, ops}; use core::{fmt, ops};
use core::fmt::Display;
use bitcoin_internals::{debug_from_display, write_err}; use bitcoin_internals::{debug_from_display, write_err};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -155,9 +155,7 @@ impl Network {
/// let network = Network::Bitcoin; /// let network = Network::Bitcoin;
/// assert_eq!(network.chain_hash(), ChainHash::BITCOIN); /// assert_eq!(network.chain_hash(), ChainHash::BITCOIN);
/// ``` /// ```
pub fn chain_hash(self) -> ChainHash { pub fn chain_hash(self) -> ChainHash { ChainHash::using_genesis_block(self) }
ChainHash::using_genesis_block(self)
}
/// Creates a `Network` from the chain hash (genesis block hash). /// Creates a `Network` from the chain hash (genesis block hash).
/// ///
@ -170,7 +168,9 @@ impl Network {
/// ///
/// assert_eq!(Ok(Network::Bitcoin), Network::try_from(ChainHash::BITCOIN)); /// assert_eq!(Ok(Network::Bitcoin), Network::try_from(ChainHash::BITCOIN));
/// ``` /// ```
pub fn from_chain_hash(chain_hash: ChainHash) -> Option<Network> { Network::try_from(chain_hash).ok() } pub fn from_chain_hash(chain_hash: ChainHash) -> Option<Network> {
Network::try_from(chain_hash).ok()
}
} }
/// An error in parsing network string. /// An error in parsing network string.

View File

@ -540,10 +540,8 @@ mod test {
let tx: Transaction = deserialize(&hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000")).unwrap(); let tx: Transaction = deserialize(&hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000")).unwrap();
let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap(); let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap();
let header: block::Header = deserialize(&hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b")).unwrap(); let header: block::Header = deserialize(&hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b")).unwrap();
let script: ScriptBuf = deserialize( let script: ScriptBuf =
&hex!("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac"), deserialize(&hex!("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")).unwrap();
)
.unwrap();
let merkle_block: MerkleBlock = deserialize(&hex!("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101")).unwrap(); let merkle_block: MerkleBlock = deserialize(&hex!("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101")).unwrap();
let cmptblock = deserialize(&hex!("00000030d923ad36ff2d955abab07f8a0a6e813bc6e066b973e780c5e36674cad5d1cd1f6e265f2a17a0d35cbe701fe9d06e2c6324cfe135f6233e8b767bfa3fb4479b71115dc562ffff7f2006000000000000000000000000010002000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0302ee00ffffffff0100f9029500000000015100000000")).unwrap(); let cmptblock = deserialize(&hex!("00000030d923ad36ff2d955abab07f8a0a6e813bc6e066b973e780c5e36674cad5d1cd1f6e265f2a17a0d35cbe701fe9d06e2c6324cfe135f6233e8b767bfa3fb4479b71115dc562ffff7f2006000000000000000000000000010002000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0302ee00ffffffff0100f9029500000000015100000000")).unwrap();
let blocktxn = deserialize(&hex!("2e93c0cff39ff605020072d96bc3a8d20b8447e294d08092351c8583e08d9b5a01020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0402dc0000ffffffff0200f90295000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000")).unwrap(); let blocktxn = deserialize(&hex!("2e93c0cff39ff605020072d96bc3a8d20b8447e294d08092351c8583e08d9b5a01020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0402dc0000ffffffff0200f90295000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000")).unwrap();
@ -582,7 +580,9 @@ mod test {
flags: BloomFlags::All, flags: BloomFlags::All,
}), }),
NetworkMessage::FilterAdd(FilterAdd { data: script.as_bytes().to_vec() }), NetworkMessage::FilterAdd(FilterAdd { data: script.as_bytes().to_vec() }),
NetworkMessage::FilterAdd(FilterAdd { data: hash([29u8; 32]).as_byte_array().to_vec() }), NetworkMessage::FilterAdd(FilterAdd {
data: hash([29u8; 32]).as_byte_array().to_vec(),
}),
NetworkMessage::FilterClear, NetworkMessage::FilterClear,
NetworkMessage::GetCFilters(GetCFilters { NetworkMessage::GetCFilters(GetCFilters {
filter_type: 2, filter_type: 2,

View File

@ -135,8 +135,7 @@ mod tests {
#[test] #[test]
fn getblocks_message_test() { fn getblocks_message_test() {
let from_sat = hex!("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000"); let from_sat = hex!("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000");
let genhash = let genhash = hex!("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
hex!("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
let decode: Result<GetBlocksMessage, _> = deserialize(&from_sat); let decode: Result<GetBlocksMessage, _> = deserialize(&from_sat);
assert!(decode.is_ok()); assert!(decode.is_ok());
@ -152,8 +151,7 @@ mod tests {
#[test] #[test]
fn getheaders_message_test() { fn getheaders_message_test() {
let from_sat = hex!("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000"); let from_sat = hex!("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000");
let genhash = let genhash = hex!("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
hex!("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
let decode: Result<GetHeadersMessage, _> = deserialize(&from_sat); let decode: Result<GetHeadersMessage, _> = deserialize(&from_sat);
assert!(decode.is_ok()); assert!(decode.is_ok());

View File

@ -183,7 +183,8 @@ mod tests {
assert_eq!(RejectReason::Duplicate, conflict.ccode); assert_eq!(RejectReason::Duplicate, conflict.ccode);
assert_eq!("txn-mempool-conflict", conflict.reason); assert_eq!("txn-mempool-conflict", conflict.reason);
assert_eq!( assert_eq!(
"0470f4f2dc4191221b59884bcffaaf00932748ab46356a80413c0b86d354df05".parse::<sha256d::Hash>() "0470f4f2dc4191221b59884bcffaaf00932748ab46356a80413c0b86d354df05"
.parse::<sha256d::Hash>()
.unwrap(), .unwrap(),
conflict.hash conflict.hash
); );
@ -193,7 +194,8 @@ mod tests {
assert_eq!(RejectReason::NonStandard, nonfinal.ccode); assert_eq!(RejectReason::NonStandard, nonfinal.ccode);
assert_eq!("non-final", nonfinal.reason); assert_eq!("non-final", nonfinal.reason);
assert_eq!( assert_eq!(
"0b46a539138b5fde4e341b37f2d945c23d41193b30caa7fcbd8bdb836cbe9b25".parse::<sha256d::Hash>() "0b46a539138b5fde4e341b37f2d945c23d41193b30caa7fcbd8bdb836cbe9b25"
.parse::<sha256d::Hash>()
.unwrap(), .unwrap(),
nonfinal.hash nonfinal.hash
); );

View File

@ -402,7 +402,8 @@ impl U256 {
// mutagen false positive: binop_bit, replace `|` with `^` // mutagen false positive: binop_bit, replace `|` with `^`
fn mul_u64(self, rhs: u64) -> (U256, bool) { fn mul_u64(self, rhs: u64) -> (U256, bool) {
let mut carry: u128 = 0; let mut carry: u128 = 0;
let mut split_le = [self.1 as u64, (self.1 >> 64) as u64, self.0 as u64, (self.0 >> 64) as u64]; let mut split_le =
[self.1 as u64, (self.1 >> 64) as u64, self.0 as u64, (self.0 >> 64) as u64];
for word in &mut split_le { for word in &mut split_le {
// TODO: Use `carrying_mul` when stabilized: https://github.com/rust-lang/rust/issues/85532 // TODO: Use `carrying_mul` when stabilized: https://github.com/rust-lang/rust/issues/85532
@ -1336,7 +1337,10 @@ mod tests {
let (got, overflow) = x.overflowing_mul(y); let (got, overflow) = x.overflowing_mul(y);
let want = U256(0x0000_0000_0000_0008_0000_0000_0000_0008, 0x0000_0000_0000_0006_0000_0000_0000_0004); let want = U256(
0x0000_0000_0000_0008_0000_0000_0000_0008,
0x0000_0000_0000_0006_0000_0000_0000_0004,
);
assert!(!overflow); assert!(!overflow);
assert_eq!(got, want) assert_eq!(got, want)
} }
@ -1489,9 +1493,12 @@ mod tests {
#[test] #[test]
fn target_is_met_by_for_target_equals_hash() { fn target_is_met_by_for_target_equals_hash() {
use std::str::FromStr; use std::str::FromStr;
use crate::hashes::Hash; use crate::hashes::Hash;
let hash = BlockHash::from_str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c").expect("failed to parse block hash"); let hash =
BlockHash::from_str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")
.expect("failed to parse block hash");
let target = Target(U256::from_le_bytes(hash.to_byte_array())); let target = Target(U256::from_le_bytes(hash.to_byte_array()));
assert!(target.is_met_by(hash)); assert!(target.is_met_by(hash));
} }
@ -1598,9 +1605,7 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
fn u256_multiplication_by_max_panics() { fn u256_multiplication_by_max_panics() { let _ = U256::MAX * U256::MAX; }
let _ = U256::MAX * U256::MAX;
}
#[test] #[test]
#[should_panic] #[should_panic]

View File

@ -18,7 +18,6 @@ impl<'a> serde::Serialize for SerializeBytesAsHex<'a> {
} }
} }
pub mod btreemap_byte_values { pub mod btreemap_byte_values {
//! Module for serialization of BTreeMaps with hex byte values. //! Module for serialization of BTreeMaps with hex byte values.
#![allow(missing_docs)] #![allow(missing_docs)]
@ -358,9 +357,7 @@ macro_rules! serde_string_impl {
$crate::serde_utils::serde_string_serialize_impl!($name, $expecting); $crate::serde_utils::serde_string_serialize_impl!($name, $expecting);
}; };
} }
pub(crate) use serde_string_impl; pub(crate) use {serde_string_deserialize_impl, serde_string_impl, serde_string_serialize_impl};
pub(crate) use serde_string_serialize_impl;
pub(crate) use serde_string_deserialize_impl;
/// A combination macro where the human-readable serialization is done like /// A combination macro where the human-readable serialization is done like
/// serde_string_impl and the non-human-readable impl is done as a struct. /// serde_string_impl and the non-human-readable impl is done as a struct.

View File

@ -47,14 +47,14 @@ impl<E> From<E> for FromHexError<E> {
fn from(e: E) -> Self { FromHexError::ParseHex(e) } fn from(e: E) -> Self { FromHexError::ParseHex(e) }
} }
impl<E: fmt::Display> fmt::Display for FromHexError<E> impl<E: fmt::Display> fmt::Display for FromHexError<E> {
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::FromHexError::*; use self::FromHexError::*;
match *self { match *self {
ParseHex(ref e) => write_err!(f, "failed to parse hex string"; e), ParseHex(ref e) => write_err!(f, "failed to parse hex string"; e),
MissingPrefix(ref value) => write_err!(f, "the input value `{}` is missing the `0x` prefix", value; self), MissingPrefix(ref value) =>
write_err!(f, "the input value `{}` is missing the `0x` prefix", value; self),
} }
} }
} }

View File

@ -14,14 +14,13 @@ use bitcoin_internals::write_err;
use secp256k1::{self, Scalar, Secp256k1}; use secp256k1::{self, Scalar, Secp256k1};
use crate::consensus::Encodable; use crate::consensus::Encodable;
use crate::hashes::{sha256t_hash_newtype, Hash, HashEngine};
use crate::crypto::key::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey}; use crate::crypto::key::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
// Re-export these so downstream only has to use one `taproot` module.
pub use crate::crypto::taproot::{Error, Signature};
use crate::hashes::{sha256t_hash_newtype, Hash, HashEngine};
use crate::prelude::*; use crate::prelude::*;
use crate::{io, Script, ScriptBuf}; use crate::{io, Script, ScriptBuf};
// Re-export these so downstream only has to use one `taproot` module.
pub use crate::crypto::taproot::{Signature, Error};
/// The SHA-256 midstate value for the TapLeaf hash. /// The SHA-256 midstate value for the TapLeaf hash.
const MIDSTATE_TAPLEAF: [u8; 32] = [ const MIDSTATE_TAPLEAF: [u8; 32] = [
156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108, 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108,
@ -128,9 +127,7 @@ impl TapNodeHash {
/// Similar to [`TapLeafHash::from_byte_array`], but explicitly conveys that the /// Similar to [`TapLeafHash::from_byte_array`], but explicitly conveys that the
/// hash is constructed from a hidden node. This also has better ergonomics /// hash is constructed from a hidden node. This also has better ergonomics
/// because it does not require the caller to import the Hash trait. /// because it does not require the caller to import the Hash trait.
pub fn assume_hidden(hash: [u8; 32]) -> TapNodeHash { pub fn assume_hidden(hash: [u8; 32]) -> TapNodeHash { TapNodeHash::from_byte_array(hash) }
TapNodeHash::from_byte_array(hash)
}
/// Computes the [`TapNodeHash`] from a script and a leaf version. /// Computes the [`TapNodeHash`] from a script and a leaf version.
pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash { pub fn from_script(script: &Script, ver: LeafVersion) -> TapNodeHash {
@ -291,12 +288,12 @@ impl TaprootSpendInfo {
let mut set = BTreeSet::new(); let mut set = BTreeSet::new();
set.insert(value); set.insert(value);
info.script_map.insert(key, set); info.script_map.insert(key, set);
}, }
Some(set) => { Some(set) => {
set.insert(value); set.insert(value);
} }
} }
}, }
} }
} }
info info
@ -385,9 +382,7 @@ impl TaprootBuilder {
/// ///
/// The size here should be maximum depth of the tree. /// The size here should be maximum depth of the tree.
pub fn with_capacity(size: usize) -> Self { pub fn with_capacity(size: usize) -> Self {
TaprootBuilder { TaprootBuilder { branch: Vec::with_capacity(size) }
branch: Vec::with_capacity(size),
}
} }
/// Creates a new [`TaprootSpendInfo`] from a list of scripts (with default script version) and /// Creates a new [`TaprootSpendInfo`] from a list of scripts (with default script version) and
@ -486,7 +481,9 @@ impl TaprootBuilder {
if self.branch().len() != 1 { if self.branch().len() != 1 {
return Err(IncompleteBuilder::NotFinalized(self)); return Err(IncompleteBuilder::NotFinalized(self));
} }
Ok(self.branch.pop() Ok(self
.branch
.pop()
.expect("length checked above") .expect("length checked above")
.expect("invariant guarantees node info exists")) .expect("invariant guarantees node info exists"))
} }
@ -497,7 +494,9 @@ impl TaprootBuilder {
let node = self.try_into_node_info()?; let node = self.try_into_node_info()?;
if node.has_hidden_nodes { if node.has_hidden_nodes {
// Reconstruct the builder as it was if it has hidden nodes // Reconstruct the builder as it was if it has hidden nodes
return Err(IncompleteBuilder::HiddenParts(TaprootBuilder { branch: vec![Some(node)] })); return Err(IncompleteBuilder::HiddenParts(TaprootBuilder {
branch: vec![Some(node)],
}));
} }
Ok(TapTree(node)) Ok(TapTree(node))
} }
@ -684,20 +683,14 @@ impl From<TapTree> for NodeInfo {
impl TapTree { impl TapTree {
/// Gets the reference to inner [`NodeInfo`] of this tree root. /// Gets the reference to inner [`NodeInfo`] of this tree root.
pub fn node_info(&self) -> &NodeInfo { pub fn node_info(&self) -> &NodeInfo { &self.0 }
&self.0
}
/// Gets the inner [`NodeInfo`] of this tree root. /// Gets the inner [`NodeInfo`] of this tree root.
pub fn into_node_info(self) -> NodeInfo { pub fn into_node_info(self) -> NodeInfo { self.0 }
self.0
}
/// Returns [`TapTreeIter<'_>`] iterator for a taproot script tree, operating in DFS order over /// Returns [`TapTreeIter<'_>`] iterator for a taproot script tree, operating in DFS order over
/// tree [`ScriptLeaf`]s. /// tree [`ScriptLeaf`]s.
pub fn script_leaves(&self) -> ScriptLeaves { pub fn script_leaves(&self) -> ScriptLeaves { ScriptLeaves { leaf_iter: self.0.leaf_nodes() } }
ScriptLeaves { leaf_iter: self.0.leaf_nodes() }
}
} }
impl TryFrom<TaprootBuilder> for TapTree { impl TryFrom<TaprootBuilder> for TapTree {
@ -709,9 +702,7 @@ impl TryFrom<TaprootBuilder> for TapTree {
/// ///
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteBuilder`] /// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteBuilder`]
/// error with the content of incomplete `builder` instance. /// error with the content of incomplete `builder` instance.
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> { fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> { builder.try_into_taptree() }
builder.try_into_taptree()
}
} }
impl TryFrom<NodeInfo> for TapTree { impl TryFrom<NodeInfo> for TapTree {
@ -744,9 +735,7 @@ impl<'tree> Iterator for ScriptLeaves<'tree> {
type Item = ScriptLeaf<'tree>; type Item = ScriptLeaf<'tree>;
#[inline] #[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> { ScriptLeaf::from_leaf_node(self.leaf_iter.next()?) }
ScriptLeaf::from_leaf_node(self.leaf_iter.next()?)
}
fn size_hint(&self) -> (usize, Option<usize>) { self.leaf_iter.size_hint() } fn size_hint(&self) -> (usize, Option<usize>) { self.leaf_iter.size_hint() }
} }
@ -850,9 +839,7 @@ impl NodeInfo {
} }
/// Creates an iterator over all leaves (including hidden leaves) in the tree. /// Creates an iterator over all leaves (including hidden leaves) in the tree.
pub fn leaf_nodes(&self) -> LeafNodes { pub fn leaf_nodes(&self) -> LeafNodes { LeafNodes { leaf_iter: self.leaves.iter() } }
LeafNodes { leaf_iter: self.leaves.iter() }
}
} }
impl TryFrom<TaprootBuilder> for NodeInfo { impl TryFrom<TaprootBuilder> for NodeInfo {
@ -899,7 +886,8 @@ impl<'de> serde::Deserialize<'de> for NodeInfo {
where where
A: serde::de::SeqAccess<'de>, A: serde::de::SeqAccess<'de>,
{ {
let size = seq.size_hint() let size = seq
.size_hint()
.map(|x| core::mem::size_of::<usize>() * 8 - x.leading_zeros() as usize) .map(|x| core::mem::size_of::<usize>() * 8 - x.leading_zeros() as usize)
.map(|x| x / 2) // Each leaf is serialized as two elements. .map(|x| x / 2) // Each leaf is serialized as two elements.
.unwrap_or(0) .unwrap_or(0)
@ -911,15 +899,19 @@ impl<'de> serde::Deserialize<'de> for NodeInfo {
.ok_or_else(|| serde::de::Error::custom("Missing tap_leaf"))?; .ok_or_else(|| serde::de::Error::custom("Missing tap_leaf"))?;
match tap_leaf { match tap_leaf {
TapLeaf::Script(script, ver) => { TapLeaf::Script(script, ver) => {
builder = builder.add_leaf_with_ver(depth, script, ver).map_err(|e| { builder =
builder.add_leaf_with_ver(depth, script, ver).map_err(|e| {
serde::de::Error::custom(format!("Leaf insertion error: {}", e)) serde::de::Error::custom(format!("Leaf insertion error: {}", e))
})?; })?;
}, }
TapLeaf::Hidden(h) => { TapLeaf::Hidden(h) => {
builder = builder.add_hidden_node(depth, h).map_err(|e| { builder = builder.add_hidden_node(depth, h).map_err(|e| {
serde::de::Error::custom(format!("Hidden node insertion error: {}", e)) serde::de::Error::custom(format!(
"Hidden node insertion error: {}",
e
))
})?; })?;
}, }
} }
} }
NodeInfo::try_from(builder).map_err(|e| { NodeInfo::try_from(builder).map_err(|e| {
@ -1009,9 +1001,7 @@ impl LeafNode {
#[inline] #[inline]
pub fn node_hash(&self) -> TapNodeHash { pub fn node_hash(&self) -> TapNodeHash {
match self.leaf { match self.leaf {
TapLeaf::Script(ref script, ver) => { TapLeaf::Script(ref script, ver) => TapLeafHash::from_script(script, ver).into(),
TapLeafHash::from_script(script, ver).into()
}
TapLeaf::Hidden(ref hash) => *hash, TapLeaf::Hidden(ref hash) => *hash,
} }
} }
@ -1031,9 +1021,7 @@ impl LeafNode {
/// Returns a reference to the leaf of this [`ScriptLeaf`]. /// Returns a reference to the leaf of this [`ScriptLeaf`].
#[inline] #[inline]
pub fn leaf(&self) -> &TapLeaf { pub fn leaf(&self) -> &TapLeaf { &self.leaf }
&self.leaf
}
} }
/// Script leaf node in a taproot tree along with the merkle proof to get this node. /// Script leaf node in a taproot tree along with the merkle proof to get this node.
@ -1049,30 +1037,19 @@ pub struct ScriptLeaf<'leaf> {
} }
impl<'leaf> ScriptLeaf<'leaf> { impl<'leaf> ScriptLeaf<'leaf> {
/// Obtains the version of the script leaf. /// Obtains the version of the script leaf.
pub fn version(&self) -> LeafVersion { pub fn version(&self) -> LeafVersion { self.version }
self.version
}
/// Obtains a reference to the script inside the leaf. /// Obtains a reference to the script inside the leaf.
pub fn script(&self) -> &Script { pub fn script(&self) -> &Script { self.script }
self.script
}
/// Obtains a reference to the merkle proof of the leaf. /// Obtains a reference to the merkle proof of the leaf.
pub fn merkle_branch(&self) -> &TaprootMerkleBranch { pub fn merkle_branch(&self) -> &TaprootMerkleBranch { self.merkle_branch }
self.merkle_branch
}
/// Obtains a script leaf from the leaf node if the leaf is not hidden. /// Obtains a script leaf from the leaf node if the leaf is not hidden.
pub fn from_leaf_node(leaf_node: &'leaf LeafNode) -> Option<Self> { pub fn from_leaf_node(leaf_node: &'leaf LeafNode) -> Option<Self> {
let (script, ver) = leaf_node.leaf.as_script()?; let (script, ver) = leaf_node.leaf.as_script()?;
Some(Self { Some(Self { version: ver, script, merkle_branch: &leaf_node.merkle_branch })
version: ver,
script,
merkle_branch: &leaf_node.merkle_branch,
})
} }
} }
@ -1096,9 +1073,7 @@ impl TaprootMerkleBranch {
/// Decodes bytes from control block. /// Decodes bytes from control block.
#[deprecated(since = "0.30.0", note = "Use decode instead")] #[deprecated(since = "0.30.0", note = "Use decode instead")]
pub fn from_slice(sl: &[u8]) -> Result<Self, TaprootError> { pub fn from_slice(sl: &[u8]) -> Result<Self, TaprootError> { Self::decode(sl) }
Self::decode(sl)
}
/// Decodes bytes from control block. /// Decodes bytes from control block.
/// ///
@ -1206,7 +1181,14 @@ macro_rules! impl_try_from_array {
// //
// The reason zero is included is that `TaprootMerkleBranch` doesn't contain the hash of the node // The reason zero is included is that `TaprootMerkleBranch` doesn't contain the hash of the node
// that's being proven - it's not needed because the script is already right before control block. // that's being proven - it's not needed because the script is already right before control block.
impl_try_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128); impl_try_from_array!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128
);
impl From<TaprootMerkleBranch> for Vec<TapNodeHash> { impl From<TaprootMerkleBranch> for Vec<TapNodeHash> {
fn from(branch: TaprootMerkleBranch) -> Self { branch.0 } fn from(branch: TaprootMerkleBranch) -> Self { branch.0 }
@ -1230,9 +1212,7 @@ pub struct ControlBlock {
impl ControlBlock { impl ControlBlock {
/// Constructs a `ControlBlock` from slice. /// Constructs a `ControlBlock` from slice.
#[deprecated(since = "0.30.0", note = "Use decode instead")] #[deprecated(since = "0.30.0", note = "Use decode instead")]
pub fn from_slice(sl: &[u8]) -> Result<ControlBlock, TaprootError> { pub fn from_slice(sl: &[u8]) -> Result<ControlBlock, TaprootError> { Self::decode(sl) }
Self::decode(sl)
}
/// Decodes bytes representing a `ControlBlock`. /// Decodes bytes representing a `ControlBlock`.
/// ///
@ -1998,7 +1978,9 @@ mod test {
let expected_spk = let expected_spk =
ScriptBuf::from_hex(arr["expected"]["scriptPubKey"].as_str().unwrap()).unwrap(); ScriptBuf::from_hex(arr["expected"]["scriptPubKey"].as_str().unwrap()).unwrap();
let expected_addr = let expected_addr =
Address::from_str(arr["expected"]["bip350Address"].as_str().unwrap()).unwrap().assume_checked(); Address::from_str(arr["expected"]["bip350Address"].as_str().unwrap())
.unwrap()
.assume_checked();
let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root); let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root); let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);

View File

@ -1,9 +1,9 @@
//! Tests PSBT integration vectors from BIP 174 //! Tests PSBT integration vectors from BIP 174
//! defined at <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors> //! defined at <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors>
use core::convert::TryFrom;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::str::FromStr; use std::str::FromStr;
use core::convert::TryFrom;
use bitcoin::bip32::{ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivationPath, KeySource}; use bitcoin::bip32::{ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivationPath, KeySource};
use bitcoin::blockdata::opcodes::OP_0; use bitcoin::blockdata::opcodes::OP_0;
@ -11,12 +11,12 @@ use bitcoin::blockdata::script;
use bitcoin::consensus::encode::{deserialize, serialize_hex}; use bitcoin::consensus::encode::{deserialize, serialize_hex};
use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::hex::FromHex;
use bitcoin::psbt::{Psbt, PsbtSighashType}; use bitcoin::psbt::{Psbt, PsbtSighashType};
use bitcoin::script::PushBytes;
use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::secp256k1::{self, Secp256k1};
use bitcoin::{ use bitcoin::{
absolute, Amount, Denomination, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, absolute, Amount, Denomination, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence,
Transaction, TxIn, TxOut, Witness, Transaction, TxIn, TxOut, Witness,
}; };
use bitcoin::script::PushBytes;
const NETWORK: Network = Network::Testnet; const NETWORK: Network = Network::Testnet;
@ -426,7 +426,10 @@ fn finalize_psbt(mut psbt: Psbt) -> Psbt {
.push_opcode(OP_0) // OP_CHECKMULTISIG bug pops +1 value when evaluating so push OP_0. .push_opcode(OP_0) // OP_CHECKMULTISIG bug pops +1 value when evaluating so push OP_0.
.push_slice(sigs[0].serialize()) .push_slice(sigs[0].serialize())
.push_slice(sigs[1].serialize()) .push_slice(sigs[1].serialize())
.push_slice(<&PushBytes>::try_from(psbt.inputs[0].redeem_script.as_ref().unwrap().as_bytes()).unwrap()) .push_slice(
<&PushBytes>::try_from(psbt.inputs[0].redeem_script.as_ref().unwrap().as_bytes())
.unwrap(),
)
.into_script(); .into_script();
psbt.inputs[0].final_script_sig = Some(script_sig); psbt.inputs[0].final_script_sig = Some(script_sig);
@ -439,7 +442,10 @@ fn finalize_psbt(mut psbt: Psbt) -> Psbt {
// Input 1: SegWit UTXO // Input 1: SegWit UTXO
let script_sig = script::Builder::new() let script_sig = script::Builder::new()
.push_slice(<&PushBytes>::try_from(psbt.inputs[1].redeem_script.as_ref().unwrap().as_bytes()).unwrap()) .push_slice(
<&PushBytes>::try_from(psbt.inputs[1].redeem_script.as_ref().unwrap().as_bytes())
.unwrap(),
)
.into_script(); .into_script();
psbt.inputs[1].final_script_sig = Some(script_sig); psbt.inputs[1].final_script_sig = Some(script_sig);

View File

@ -36,7 +36,7 @@ use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TaprootBuilder, TapTree}; use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
use bitcoin::{ use bitcoin::{
ecdsa, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, ecdsa, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target,
Transaction, TxIn, TxOut, Txid, Work, Transaction, TxIn, TxOut, Txid, Work,
@ -225,10 +225,13 @@ fn serde_regression_psbt() {
lock_time: absolute::LockTime::ZERO, lock_time: absolute::LockTime::ZERO,
input: vec![TxIn { input: vec![TxIn {
previous_output: OutPoint { previous_output: OutPoint {
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse::<Txid>().unwrap(), txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389"
.parse::<Txid>()
.unwrap(),
vout: 1, vout: 1,
}, },
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(), script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
.unwrap(),
sequence: Sequence::from_consensus(4294967295), sequence: Sequence::from_consensus(4294967295),
witness: Witness::from_slice(&[Vec::from_hex( witness: Witness::from_slice(&[Vec::from_hex(
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105", "03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105",

View File

@ -47,3 +47,6 @@ git diff-index --check --cached $against -- || exit 1
# Check that code lints cleanly. # Check that code lints cleanly.
cargo clippy --all-features -- -D warnings || exit 1 cargo clippy --all-features -- -D warnings || exit 1
# Check that there are no formatting issues.
cargo +nightly fmt --check || exit 1

View File

@ -89,6 +89,16 @@ if [ "$DO_ASAN" = true ]; then
cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu
fi fi
# Run formatter if told to.
if [ "$DO_FMT" = true ]; then
if [ "$NIGHTLY" = false ]; then
echo "DO_FMT requires a nightly toolchain (consider using RUSTUP_TOOLCHAIN)"
exit 1
fi
rustup component add rustfmt
cargo fmt --check
fi
# Bench if told to, only works with non-stable toolchain (nightly, beta). # Bench if told to, only works with non-stable toolchain (nightly, beta).
if [ "$DO_BENCH" = true ] if [ "$DO_BENCH" = true ]
then then

View File

@ -52,3 +52,13 @@ fi
if [ "$DO_DOCS" = true ]; then if [ "$DO_DOCS" = true ]; then
RUSTDOCFLAGS="-D warnings" cargo +stable doc --all-features RUSTDOCFLAGS="-D warnings" cargo +stable doc --all-features
fi fi
# Run formatter if told to.
if [ "$DO_FMT" = true ]; then
if [ "$NIGHTLY" = false ]; then
echo "DO_FMT requires a nightly toolchain (consider using RUSTUP_TOOLCHAIN)"
exit 1
fi
rustup component add rustfmt
cargo fmt --check
fi

View File

@ -4,9 +4,10 @@
//! faster than the usual `write!(f, "{02x}", b)?` in a for loop because it reduces dynamic //! faster than the usual `write!(f, "{02x}", b)?` in a for loop because it reduces dynamic
//! dispatch and decreases the number of allocations if a `String` is being created. //! dispatch and decreases the number of allocations if a `String` is being created.
use core::borrow::Borrow;
pub use out_bytes::OutBytes; pub use out_bytes::OutBytes;
use core::borrow::Borrow;
use super::Case; use super::Case;
/// Trait for types that can be soundly converted to `OutBytes`. /// Trait for types that can be soundly converted to `OutBytes`.
@ -205,13 +206,21 @@ impl<T: AsOutBytes> BufEncoder<T> {
/// The method panics if the bytes wouldn't fit the buffer. /// The method panics if the bytes wouldn't fit the buffer.
#[inline] #[inline]
#[cfg_attr(rust_v_1_46, track_caller)] #[cfg_attr(rust_v_1_46, track_caller)]
pub fn put_bytes<I>(&mut self, bytes: I, case: Case) where I: IntoIterator, I::Item: Borrow<u8> { pub fn put_bytes<I>(&mut self, bytes: I, case: Case)
where
I: IntoIterator,
I::Item: Borrow<u8>,
{
self.put_bytes_inner(bytes.into_iter(), case) self.put_bytes_inner(bytes.into_iter(), case)
} }
#[inline] #[inline]
#[cfg_attr(rust_v_1_46, track_caller)] #[cfg_attr(rust_v_1_46, track_caller)]
fn put_bytes_inner<I>(&mut self, bytes: I, case: Case) where I: Iterator, I::Item: Borrow<u8> { fn put_bytes_inner<I>(&mut self, bytes: I, case: Case)
where
I: Iterator,
I::Item: Borrow<u8>,
{
// May give the compiler better optimization opportunity // May give the compiler better optimization opportunity
if let Some(max) = bytes.size_hint().1 { if let Some(max) = bytes.size_hint().1 {
assert!(max <= self.space_remaining()); assert!(max <= self.space_remaining());

View File

@ -8,9 +8,9 @@ use core::fmt;
use super::buf_encoder::{BufEncoder, OutBytes}; use super::buf_encoder::{BufEncoder, OutBytes};
use super::Case; use super::Case;
use crate::hex::buf_encoder::FixedLenBuf;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use crate::prelude::*; use crate::prelude::*;
use crate::hex::buf_encoder::FixedLenBuf;
/// Extension trait for types that can be displayed as hex. /// Extension trait for types that can be displayed as hex.
/// ///
@ -153,34 +153,30 @@ impl<'a> DisplayByteSlice<'a> {
} }
impl<'a> fmt::LowerHex for DisplayByteSlice<'a> { impl<'a> fmt::LowerHex for DisplayByteSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
self.display(f, Case::Lower)
}
} }
impl<'a> fmt::UpperHex for DisplayByteSlice<'a> { impl<'a> fmt::UpperHex for DisplayByteSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
self.display(f, Case::Upper)
}
} }
/// Displays byte array as hex. /// Displays byte array as hex.
/// ///
/// Created by [`<&[u8; LEN] as DisplayHex>::as_hex`](DisplayHex::as_hex). /// Created by [`<&[u8; LEN] as DisplayHex>::as_hex`](DisplayHex::as_hex).
pub struct DisplayArray<A: Clone + IntoIterator, B: FixedLenBuf> where A::Item: Borrow<u8> { pub struct DisplayArray<A: Clone + IntoIterator, B: FixedLenBuf>
where
A::Item: Borrow<u8>,
{
array: A, array: A,
_buffer_marker: core::marker::PhantomData<B>, _buffer_marker: core::marker::PhantomData<B>,
} }
impl<A: Clone + IntoIterator, B: FixedLenBuf> DisplayArray<A, B>
impl<A: Clone + IntoIterator, B: FixedLenBuf> DisplayArray<A, B> where A::Item: Borrow<u8> { where
A::Item: Borrow<u8>,
{
/// Creates the wrapper. /// Creates the wrapper.
pub fn new(array: A) -> Self { pub fn new(array: A) -> Self { DisplayArray { array, _buffer_marker: Default::default() } }
DisplayArray {
array,
_buffer_marker: Default::default(),
}
}
fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result { fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
let mut buf = B::uninit(); let mut buf = B::uninit();
@ -190,16 +186,18 @@ impl<A: Clone + IntoIterator, B: FixedLenBuf> DisplayArray<A, B> where A::Item:
} }
} }
impl<A: Clone + IntoIterator, B: FixedLenBuf> fmt::LowerHex for DisplayArray<A, B> where A::Item: Borrow<u8> { impl<A: Clone + IntoIterator, B: FixedLenBuf> fmt::LowerHex for DisplayArray<A, B>
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { where
self.display(f, Case::Lower) A::Item: Borrow<u8>,
} {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
} }
impl<A: Clone + IntoIterator, B: FixedLenBuf> fmt::UpperHex for DisplayArray<A, B> where A::Item: Borrow<u8> { impl<A: Clone + IntoIterator, B: FixedLenBuf> fmt::UpperHex for DisplayArray<A, B>
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { where
self.display(f, Case::Upper) A::Item: Borrow<u8>,
} {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
} }
/// Format known-length array as hex. /// Format known-length array as hex.
@ -243,7 +241,9 @@ pub fn fmt_hex_exact_fn<I>(
bytes: I, bytes: I,
case: Case, case: Case,
) -> fmt::Result ) -> fmt::Result
where I: IntoIterator, I::Item: Borrow<u8> where
I: IntoIterator,
I::Item: Borrow<u8>,
{ {
let mut encoder = BufEncoder::new(buf); let mut encoder = BufEncoder::new(buf);
encoder.put_bytes(bytes, case); encoder.put_bytes(bytes, case);

View File

@ -30,15 +30,11 @@ macro_rules! impl_array_newtype {
} }
impl<'a> core::convert::From<[$ty; $len]> for $thing { impl<'a> core::convert::From<[$ty; $len]> for $thing {
fn from(data: [$ty; $len]) -> Self { fn from(data: [$ty; $len]) -> Self { $thing(data) }
$thing(data)
}
} }
impl<'a> core::convert::From<&'a [$ty; $len]> for $thing { impl<'a> core::convert::From<&'a [$ty; $len]> for $thing {
fn from(data: &'a [$ty; $len]) -> Self { fn from(data: &'a [$ty; $len]) -> Self { $thing(*data) }
$thing(*data)
}
} }
impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing { impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing {
@ -52,52 +48,36 @@ macro_rules! impl_array_newtype {
} }
impl AsRef<[$ty; $len]> for $thing { impl AsRef<[$ty; $len]> for $thing {
fn as_ref(&self) -> &[$ty; $len] { fn as_ref(&self) -> &[$ty; $len] { &self.0 }
&self.0
}
} }
impl AsMut<[$ty; $len]> for $thing { impl AsMut<[$ty; $len]> for $thing {
fn as_mut(&mut self) -> &mut [$ty; $len] { fn as_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 }
&mut self.0
}
} }
impl AsRef<[$ty]> for $thing { impl AsRef<[$ty]> for $thing {
fn as_ref(&self) -> &[$ty] { fn as_ref(&self) -> &[$ty] { &self.0 }
&self.0
}
} }
impl AsMut<[$ty]> for $thing { impl AsMut<[$ty]> for $thing {
fn as_mut(&mut self) -> &mut [$ty] { fn as_mut(&mut self) -> &mut [$ty] { &mut self.0 }
&mut self.0
}
} }
impl core::borrow::Borrow<[$ty; $len]> for $thing { impl core::borrow::Borrow<[$ty; $len]> for $thing {
fn borrow(&self) -> &[$ty; $len] { fn borrow(&self) -> &[$ty; $len] { &self.0 }
&self.0
}
} }
impl core::borrow::BorrowMut<[$ty; $len]> for $thing { impl core::borrow::BorrowMut<[$ty; $len]> for $thing {
fn borrow_mut(&mut self) -> &mut [$ty; $len] { fn borrow_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 }
&mut self.0
}
} }
// The following two are valid because `[T; N]: Borrow<[T]>` // The following two are valid because `[T; N]: Borrow<[T]>`
impl core::borrow::Borrow<[$ty]> for $thing { impl core::borrow::Borrow<[$ty]> for $thing {
fn borrow(&self) -> &[$ty] { fn borrow(&self) -> &[$ty] { &self.0 }
&self.0
}
} }
impl core::borrow::BorrowMut<[$ty]> for $thing { impl core::borrow::BorrowMut<[$ty]> for $thing {
fn borrow_mut(&mut self) -> &mut [$ty] { fn borrow_mut(&mut self) -> &mut [$ty] { &mut self.0 }
&mut self.0
}
} }
impl<I> core::ops::Index<I> for $thing impl<I> core::ops::Index<I> for $thing

View File

@ -58,7 +58,7 @@ enum_discrim_align_threshold = 0
match_arm_blocks = false # Default true match_arm_blocks = false # Default true
match_arm_leading_pipes = "Never" match_arm_leading_pipes = "Never"
force_multiline_blocks = false force_multiline_blocks = false
fn_args_layout = "Tall" fn_params_layout = "Tall"
brace_style = "SameLineWhere" brace_style = "SameLineWhere"
control_brace_style = "AlwaysSameLine" control_brace_style = "AlwaysSameLine"
trailing_semicolon = true trailing_semicolon = true