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();
// 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
let mut writer = BitStreamWriter::new(self.writer);

View File

@ -643,11 +643,11 @@ impl_vec!((u32, Address));
#[cfg(feature = "std")]
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],
mut w: W,
w: &mut W,
) -> 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)?;
Ok(vi_len + data.len())
}

View File

@ -68,7 +68,7 @@ impl PublicKey {
}
/// 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))
}

View File

@ -675,7 +675,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// [`io::Write`] trait.
pub fn taproot_encode_signing_data_to<Write: io::Write, T: Borrow<TxOut>>(
&mut self,
mut writer: Write,
writer: &mut Write,
input_index: usize,
prevouts: &Prevouts<T>,
annex: Option<Annex>,
@ -687,18 +687,18 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
// epoch
0u8.consensus_encode(&mut writer)?;
0u8.consensus_encode(writer)?;
// * Control:
// hash_type (1).
(sighash_type as u8).consensus_encode(&mut writer)?;
(sighash_type as u8).consensus_encode(writer)?;
// * Transaction Data:
// 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.
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:
// 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_sequences (32): the SHA256 of the serialization of all input nSequence.
if !anyone_can_pay {
self.common_cache().prevouts.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(&mut writer)?;
self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(&mut writer)?;
self.common_cache().sequences.consensus_encode(&mut writer)?;
self.common_cache().prevouts.consensus_encode(writer)?;
self.taproot_cache(prevouts.get_all()?).amounts.consensus_encode(writer)?;
self.taproot_cache(prevouts.get_all()?).script_pubkeys.consensus_encode(writer)?;
self.common_cache().sequences.consensus_encode(writer)?;
}
// 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.
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:
@ -728,7 +728,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
if leaf_hash_code_separator.is_some() {
spend_type |= 2u8;
}
spend_type.consensus_encode(&mut writer)?;
spend_type.consensus_encode(writer)?;
// If hash_type & 0x80 equals SIGHASH_ANYONECANPAY:
// 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(),
})?;
let previous_output = prevouts.get(input_index)?;
txin.previous_output.consensus_encode(&mut writer)?;
previous_output.value.consensus_encode(&mut writer)?;
previous_output.script_pubkey.consensus_encode(&mut writer)?;
txin.sequence.consensus_encode(&mut writer)?;
txin.previous_output.consensus_encode(writer)?;
previous_output.value.consensus_encode(writer)?;
previous_output.script_pubkey.consensus_encode(writer)?;
txin.sequence.consensus_encode(writer)?;
} 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):
@ -757,7 +757,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
let mut enc = sha256::Hash::engine();
annex.consensus_encode(&mut enc)?;
let hash = sha256::Hash::from_engine(enc);
hash.consensus_encode(&mut writer)?;
hash.consensus_encode(writer)?;
}
// * Data about this output:
@ -775,7 +775,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
})?
.consensus_encode(&mut enc)?;
let hash = sha256::Hash::from_engine(enc);
hash.consensus_encode(&mut writer)?;
hash.consensus_encode(writer)?;
}
// if (scriptpath):
@ -783,9 +783,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
// ss += bytes([0])
// ss += struct.pack("<i", codeseparator_pos)
if let Some((hash, code_separator_pos)) = leaf_hash_code_separator {
hash.as_byte_array().consensus_encode(&mut writer)?;
KEY_VERSION_0.consensus_encode(&mut writer)?;
code_separator_pos.consensus_encode(&mut writer)?;
hash.as_byte_array().consensus_encode(writer)?;
KEY_VERSION_0.consensus_encode(writer)?;
code_separator_pos.consensus_encode(writer)?;
}
Ok(())
@ -862,7 +862,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// [`Self::p2wpkh_signature_hash`] and [`SighashCache::p2wsh_signature_hash`].)
pub fn segwit_v0_encode_signing_data_to<Write: io::Write>(
&mut self,
mut writer: Write,
writer: &mut Write,
input_index: usize,
script_code: &Script,
value: Amount,
@ -872,21 +872,21 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
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 {
self.segwit_cache().prevouts.consensus_encode(&mut writer)?;
self.segwit_cache().prevouts.consensus_encode(writer)?;
} else {
zero_hash.consensus_encode(&mut writer)?;
zero_hash.consensus_encode(writer)?;
}
if !anyone_can_pay
&& sighash != EcdsaSighashType::Single
&& sighash != EcdsaSighashType::None
{
self.segwit_cache().sequences.consensus_encode(&mut writer)?;
self.segwit_cache().sequences.consensus_encode(writer)?;
} 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(),
})?;
txin.previous_output.consensus_encode(&mut writer)?;
script_code.consensus_encode(&mut writer)?;
value.consensus_encode(&mut writer)?;
txin.sequence.consensus_encode(&mut writer)?;
txin.previous_output.consensus_encode(writer)?;
script_code.consensus_encode(writer)?;
value.consensus_encode(writer)?;
txin.sequence.consensus_encode(writer)?;
}
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()
{
let mut single_enc = LegacySighash::engine();
@ -914,8 +914,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
writer.write_all(&zero_hash[..])?;
}
self.tx.borrow().lock_time.consensus_encode(&mut writer)?;
sighash_type.to_u32().consensus_encode(&mut writer)?;
self.tx.borrow().lock_time.consensus_encode(writer)?;
sighash_type.to_u32().consensus_encode(writer)?;
Ok(())
}
@ -986,7 +986,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// 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>>(
&self,
writer: Write,
writer: &mut Write,
input_index: usize,
script_pubkey: &Script,
sighash_type: U,
@ -1013,7 +1013,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
fn encode_signing_data_to_inner<Write: io::Write>(
self_: &Transaction,
mut writer: Write,
writer: &mut Write,
input_index: usize,
script_pubkey: &Script,
sighash_type: u32,
@ -1074,8 +1074,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
_ => unreachable!(),
};
// hash the result
tx.consensus_encode(&mut writer)?;
sighash_type.to_le_bytes().consensus_encode(&mut writer)?;
tx.consensus_encode(writer)?;
sighash_type.to_le_bytes().consensus_encode(writer)?;
Ok(())
}

View File

@ -1109,7 +1109,7 @@ impl TaprootMerkleBranch {
/// # Returns
///
/// 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() {
writer.write_all(hash.as_ref())?;
}
@ -1237,12 +1237,12 @@ impl ControlBlock {
/// # Returns
///
/// 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 =
i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus();
writer.write_all(&[first_byte])?;
writer.write_all(&self.internal_key.serialize())?;
self.merkle_branch.encode(&mut writer)?;
self.merkle_branch.encode(writer)?;
Ok(self.size())
}