Stop relying on `std::io::Write`'s `&mut Write` blanket impl

`std::io::Write` is implemented for all `&mut std::io::Write`. This
makes it easy to have APIs that mix and match owned `Write`s with
mutable references to `Write`s.

However, in the next commit we add our own `Write` trait which we
intend to implement for all `std::io::Write`. Sadly, this is
mutually exclusive with a blanket implementation on our own
`&mut Write`, as that would conflict with an `std::io::Write`
blanket impl.

Thus, in order to use the `Write for all &mut Write` blanket impl
in rust-bitcoin, we'd have to bound all `Write`s by
`std::io::Write`, as we're unable to provide a blanket
`Write for &mut Write` impl.

Here we stop relying on that blanket impl in order to introduce the
new trait in the next commit.
This commit is contained in:
Matt Corallo 2023-09-10 01:04:34 +00:00
parent 5e0209569c
commit 2348449d2a
5 changed files with 46 additions and 46 deletions

View File

@ -393,7 +393,7 @@ impl<'a, W: io::Write> GcsFilterWriter<'a, W> {
mapped.sort_unstable(); mapped.sort_unstable();
// write number of elements as varint // write number of elements as varint
let mut wrote = VarInt::from(mapped.len()).consensus_encode(&mut self.writer)?; let mut wrote = VarInt::from(mapped.len()).consensus_encode(self.writer)?;
// write out deltas of sorted values into a Golonb-Rice coded bit stream // write out deltas of sorted values into a Golonb-Rice coded bit stream
let mut writer = BitStreamWriter::new(self.writer); let mut writer = BitStreamWriter::new(self.writer);

View File

@ -643,11 +643,11 @@ impl_vec!((u32, Address));
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl_vec!(AddrV2Message); impl_vec!(AddrV2Message);
pub(crate) fn consensus_encode_with_size<W: io::Write>( pub(crate) fn consensus_encode_with_size<W: io::Write + ?Sized>(
data: &[u8], data: &[u8],
mut w: W, w: &mut W,
) -> Result<usize, io::Error> { ) -> Result<usize, io::Error> {
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut w)?; let vi_len = VarInt(data.len() as u64).consensus_encode(w)?;
w.emit_slice(data)?; w.emit_slice(data)?;
Ok(vi_len + data.len()) Ok(vi_len + data.len())
} }

View File

@ -68,7 +68,7 @@ impl PublicKey {
} }
/// Write the public key into a writer /// Write the public key into a writer
pub fn write_into<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> { pub fn write_into<W: io::Write>(&self, writer: &mut W) -> Result<(), io::Error> {
self.with_serialized(|bytes| writer.write_all(bytes)) self.with_serialized(|bytes| writer.write_all(bytes))
} }

View File

@ -675,7 +675,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// [`io::Write`] trait. /// [`io::Write`] trait.
pub fn taproot_encode_signing_data_to<Write: io::Write, T: Borrow<TxOut>>( pub fn taproot_encode_signing_data_to<Write: io::Write, T: Borrow<TxOut>>(
&mut self, &mut self,
mut writer: Write, writer: &mut Write,
input_index: usize, input_index: usize,
prevouts: &Prevouts<T>, prevouts: &Prevouts<T>,
annex: Option<Annex>, annex: Option<Annex>,
@ -687,18 +687,18 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag(); let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
// epoch // epoch
0u8.consensus_encode(&mut writer)?; 0u8.consensus_encode(writer)?;
// * Control: // * Control:
// hash_type (1). // hash_type (1).
(sighash_type as u8).consensus_encode(&mut writer)?; (sighash_type as u8).consensus_encode(writer)?;
// * Transaction Data: // * Transaction Data:
// nVersion (4): the nVersion of the transaction. // nVersion (4): the nVersion of the transaction.
self.tx.borrow().version.consensus_encode(&mut writer)?; self.tx.borrow().version.consensus_encode(writer)?;
// nLockTime (4): the nLockTime of the transaction. // nLockTime (4): the nLockTime of the transaction.
self.tx.borrow().lock_time.consensus_encode(&mut writer)?; self.tx.borrow().lock_time.consensus_encode(writer)?;
// If the hash_type & 0x80 does not equal SIGHASH_ANYONECANPAY: // If the hash_type & 0x80 does not equal SIGHASH_ANYONECANPAY:
// sha_prevouts (32): the SHA256 of the serialization of all input outpoints. // sha_prevouts (32): the SHA256 of the serialization of all input outpoints.
@ -706,16 +706,16 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
// sha_scriptpubkeys (32): the SHA256 of the serialization of all spent output scriptPubKeys. // sha_scriptpubkeys (32): the SHA256 of the serialization of all spent output scriptPubKeys.
// 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(writer)?;
self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(&mut writer)?; self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(writer)?;
self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(&mut writer)?; self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(writer)?;
self.common_cache().sequences.consensus_encode(&mut writer)?; self.common_cache().sequences.consensus_encode(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:
// sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format. // sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format.
if sighash != TapSighashType::None && sighash != TapSighashType::Single { if sighash != TapSighashType::None && sighash != TapSighashType::Single {
self.common_cache().outputs.consensus_encode(&mut writer)?; self.common_cache().outputs.consensus_encode(writer)?;
} }
// * Data about this input: // * Data about this input:
@ -728,7 +728,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
if leaf_hash_code_separator.is_some() { if leaf_hash_code_separator.is_some() {
spend_type |= 2u8; spend_type |= 2u8;
} }
spend_type.consensus_encode(&mut writer)?; spend_type.consensus_encode(writer)?;
// If hash_type & 0x80 equals SIGHASH_ANYONECANPAY: // If hash_type & 0x80 equals SIGHASH_ANYONECANPAY:
// outpoint (36): the COutPoint of this input (32-byte hash + 4-byte little-endian). // outpoint (36): the COutPoint of this input (32-byte hash + 4-byte little-endian).
@ -742,12 +742,12 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
inputs_size: self.tx.borrow().input.len(), inputs_size: self.tx.borrow().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(writer)?;
previous_output.value.consensus_encode(&mut writer)?; previous_output.value.consensus_encode(writer)?;
previous_output.script_pubkey.consensus_encode(&mut writer)?; previous_output.script_pubkey.consensus_encode(writer)?;
txin.sequence.consensus_encode(&mut writer)?; txin.sequence.consensus_encode(writer)?;
} else { } else {
(input_index as u32).consensus_encode(&mut writer)?; (input_index as u32).consensus_encode(writer)?;
} }
// If an annex is present (the lowest bit of spend_type is set): // If an annex is present (the lowest bit of spend_type is set):
@ -757,7 +757,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
let mut enc = sha256::Hash::engine(); let mut enc = sha256::Hash::engine();
annex.consensus_encode(&mut enc)?; annex.consensus_encode(&mut enc)?;
let hash = sha256::Hash::from_engine(enc); let hash = sha256::Hash::from_engine(enc);
hash.consensus_encode(&mut writer)?; hash.consensus_encode(writer)?;
} }
// * Data about this output: // * Data about this output:
@ -775,7 +775,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
})? })?
.consensus_encode(&mut enc)?; .consensus_encode(&mut enc)?;
let hash = sha256::Hash::from_engine(enc); let hash = sha256::Hash::from_engine(enc);
hash.consensus_encode(&mut writer)?; hash.consensus_encode(writer)?;
} }
// if (scriptpath): // if (scriptpath):
@ -783,9 +783,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
// ss += bytes([0]) // ss += bytes([0])
// ss += struct.pack("<i", codeseparator_pos) // ss += struct.pack("<i", codeseparator_pos)
if let Some((hash, code_separator_pos)) = leaf_hash_code_separator { if let Some((hash, code_separator_pos)) = leaf_hash_code_separator {
hash.as_byte_array().consensus_encode(&mut writer)?; hash.as_byte_array().consensus_encode(writer)?;
KEY_VERSION_0.consensus_encode(&mut writer)?; KEY_VERSION_0.consensus_encode(writer)?;
code_separator_pos.consensus_encode(&mut writer)?; code_separator_pos.consensus_encode(writer)?;
} }
Ok(()) Ok(())
@ -862,7 +862,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// [`Self::p2wpkh_signature_hash`] and [`SighashCache::p2wsh_signature_hash`].) /// [`Self::p2wpkh_signature_hash`] and [`SighashCache::p2wsh_signature_hash`].)
pub fn segwit_v0_encode_signing_data_to<Write: io::Write>( pub fn segwit_v0_encode_signing_data_to<Write: io::Write>(
&mut self, &mut self,
mut writer: Write, writer: &mut Write,
input_index: usize, input_index: usize,
script_code: &Script, script_code: &Script,
value: Amount, value: Amount,
@ -872,21 +872,21 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag(); let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
self.tx.borrow().version.consensus_encode(&mut writer)?; self.tx.borrow().version.consensus_encode(writer)?;
if !anyone_can_pay { if !anyone_can_pay {
self.segwit_cache().prevouts.consensus_encode(&mut writer)?; self.segwit_cache().prevouts.consensus_encode(writer)?;
} else { } else {
zero_hash.consensus_encode(&mut writer)?; zero_hash.consensus_encode(writer)?;
} }
if !anyone_can_pay if !anyone_can_pay
&& sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::Single
&& sighash != EcdsaSighashType::None && sighash != EcdsaSighashType::None
{ {
self.segwit_cache().sequences.consensus_encode(&mut writer)?; self.segwit_cache().sequences.consensus_encode(writer)?;
} else { } else {
zero_hash.consensus_encode(&mut writer)?; zero_hash.consensus_encode(writer)?;
} }
{ {
@ -896,14 +896,14 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
inputs_size: self.tx.borrow().input.len(), inputs_size: self.tx.borrow().input.len(),
})?; })?;
txin.previous_output.consensus_encode(&mut writer)?; txin.previous_output.consensus_encode(writer)?;
script_code.consensus_encode(&mut writer)?; script_code.consensus_encode(writer)?;
value.consensus_encode(&mut writer)?; value.consensus_encode(writer)?;
txin.sequence.consensus_encode(&mut writer)?; txin.sequence.consensus_encode(writer)?;
} }
if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None { if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None {
self.segwit_cache().outputs.consensus_encode(&mut writer)?; self.segwit_cache().outputs.consensus_encode(writer)?;
} else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len() } else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len()
{ {
let mut single_enc = LegacySighash::engine(); let mut single_enc = LegacySighash::engine();
@ -914,8 +914,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
writer.write_all(&zero_hash[..])?; writer.write_all(&zero_hash[..])?;
} }
self.tx.borrow().lock_time.consensus_encode(&mut writer)?; self.tx.borrow().lock_time.consensus_encode(writer)?;
sighash_type.to_u32().consensus_encode(&mut writer)?; sighash_type.to_u32().consensus_encode(writer)?;
Ok(()) Ok(())
} }
@ -986,7 +986,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]). /// that must be handled by the caller (see [`EncodeSigningDataResult::is_sighash_single_bug`]).
pub fn legacy_encode_signing_data_to<Write: io::Write, U: Into<u32>>( pub fn legacy_encode_signing_data_to<Write: io::Write, U: Into<u32>>(
&self, &self,
writer: Write, writer: &mut Write,
input_index: usize, input_index: usize,
script_pubkey: &Script, script_pubkey: &Script,
sighash_type: U, sighash_type: U,
@ -1013,7 +1013,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
fn encode_signing_data_to_inner<Write: io::Write>( fn encode_signing_data_to_inner<Write: io::Write>(
self_: &Transaction, self_: &Transaction,
mut writer: Write, writer: &mut Write,
input_index: usize, input_index: usize,
script_pubkey: &Script, script_pubkey: &Script,
sighash_type: u32, sighash_type: u32,
@ -1074,8 +1074,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
_ => unreachable!(), _ => unreachable!(),
}; };
// hash the result // hash the result
tx.consensus_encode(&mut writer)?; tx.consensus_encode(writer)?;
sighash_type.to_le_bytes().consensus_encode(&mut writer)?; sighash_type.to_le_bytes().consensus_encode(writer)?;
Ok(()) Ok(())
} }

View File

@ -1109,7 +1109,7 @@ impl TaprootMerkleBranch {
/// # Returns /// # Returns
/// ///
/// The number of bytes written to the writer. /// The number of bytes written to the writer.
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> { pub fn encode<Write: io::Write>(&self, writer: &mut Write) -> io::Result<usize> {
for hash in self.0.iter() { for hash in self.0.iter() {
writer.write_all(hash.as_ref())?; writer.write_all(hash.as_ref())?;
} }
@ -1237,12 +1237,12 @@ impl ControlBlock {
/// # Returns /// # Returns
/// ///
/// The number of bytes written to the writer. /// The number of bytes written to the writer.
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> { pub fn encode<Write: io::Write>(&self, writer: &mut Write) -> io::Result<usize> {
let first_byte: u8 = let first_byte: u8 =
i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus(); i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus();
writer.write_all(&[first_byte])?; writer.write_all(&[first_byte])?;
writer.write_all(&self.internal_key.serialize())?; writer.write_all(&self.internal_key.serialize())?;
self.merkle_branch.encode(&mut writer)?; self.merkle_branch.encode(writer)?;
Ok(self.size()) Ok(self.size())
} }