From 10fedfb3b44edef1aa69c16452fd27bb8cf65309 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Wed, 16 Feb 2022 23:35:54 -0800 Subject: [PATCH] Change Prevouts::All(&[TxOut]) to Prevouts::All(&[Borrow]) This avoids some allocation of creating a vec of TxOut to create a slice incase the data is already available in psbt/other methods. Facilitates creation of Prevouts from &[TxOut] as well as &[&TxOut] --- src/util/sighash.rs | 49 +++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/util/sighash.rs b/src/util/sighash.rs index 54254738..ad248fd7 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -25,6 +25,7 @@ use blockdata::witness::Witness; use consensus::{encode, Encodable}; use core::fmt; use core::ops::{Deref, DerefMut}; +use core::borrow::Borrow; use hashes::{sha256, sha256d, Hash}; use io; use util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash}; @@ -80,14 +81,14 @@ struct TaprootCache { /// Contains outputs of previous transactions. /// In the case [`SchnorrSigHashType`] variant is `ANYONECANPAY`, [`Prevouts::One`] may be provided #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Prevouts<'u> { +pub enum Prevouts<'u, T> where T: 'u + Borrow { /// `One` variant allows to provide the single Prevout needed. It's useful for example /// when modifier `ANYONECANPAY` is provided, only prevout of the current input is needed. /// The first `usize` argument is the input index this [`TxOut`] is referring to. - One(usize, &'u TxOut), + One(usize, T), /// When `ANYONECANPAY` is not provided, or the caller is handy giving all prevouts so the same /// variable can be used for multiple inputs. - All(&'u [TxOut]), + All(&'u [T]), } const KEY_VERSION_0: u8 = 0u8; @@ -188,7 +189,7 @@ impl fmt::Display for Error { #[cfg(feature = "std")] impl ::std::error::Error for Error {} -impl<'u> Prevouts<'u> { +impl<'u, T> Prevouts<'u, T> where T: Borrow { fn check_all(&self, tx: &Transaction) -> Result<(), Error> { if let Prevouts::All(prevouts) = self { if prevouts.len() != tx.input.len() { @@ -198,9 +199,9 @@ impl<'u> Prevouts<'u> { Ok(()) } - fn get_all(&self) -> Result<&[TxOut], Error> { + fn get_all(&self) -> Result<&[T], Error> { match self { - Prevouts::All(prevouts) => Ok(prevouts), + Prevouts::All(prevouts) => Ok(*prevouts), _ => Err(Error::PrevoutKind), } } @@ -209,12 +210,15 @@ impl<'u> Prevouts<'u> { match self { Prevouts::One(index, prevout) => { if input_index == *index { - Ok(prevout) + Ok(prevout.borrow()) } else { Err(Error::PrevoutIndex) } } - Prevouts::All(prevouts) => prevouts.get(input_index).ok_or(Error::PrevoutIndex), + Prevouts::All(prevouts) => prevouts + .get(input_index) + .map(|x| x.borrow()) + .ok_or(Error::PrevoutIndex), } } } @@ -307,11 +311,11 @@ impl> SigHashCache { /// Encode the BIP341 signing data for any flag type into a given object implementing a /// io::Write trait. - pub fn taproot_encode_signing_data_to( + pub fn taproot_encode_signing_data_to>( &mut self, mut writer: Write, input_index: usize, - prevouts: &Prevouts, + prevouts: &Prevouts, annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, sighash_type: SchnorrSigHashType, @@ -437,10 +441,10 @@ impl> SigHashCache { } /// Compute the BIP341 sighash for any flag type. - pub fn taproot_signature_hash( + pub fn taproot_signature_hash>( &mut self, input_index: usize, - prevouts: &Prevouts, + prevouts: &Prevouts, annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, sighash_type: SchnorrSigHashType, @@ -458,10 +462,10 @@ impl> SigHashCache { } /// Compute the BIP341 sighash for a key spend - pub fn taproot_key_spend_signature_hash( + pub fn taproot_key_spend_signature_hash>( &mut self, input_index: usize, - prevouts: &Prevouts, + prevouts: &Prevouts, sighash_type: SchnorrSigHashType, ) -> Result { let mut enc = TapSighashHash::engine(); @@ -480,10 +484,10 @@ impl> SigHashCache { /// /// Assumes the default `OP_CODESEPARATOR` position of `0xFFFFFFFF`. Custom values can be /// provided through the more fine-grained API of [`SigHashCache::taproot_encode_signing_data_to`]. - pub fn taproot_script_spend_signature_hash>( + pub fn taproot_script_spend_signature_hash, T: Borrow>( &mut self, input_index: usize, - prevouts: &Prevouts, + prevouts: &Prevouts, leaf_hash: S, sighash_type: SchnorrSigHashType, ) -> Result { @@ -667,13 +671,15 @@ impl> SigHashCache { }) } - fn taproot_cache(&mut self, prevouts: &[TxOut]) -> &TaprootCache { + fn taproot_cache>(&mut self, prevouts: &[T]) -> &TaprootCache + { self.taproot_cache.get_or_insert_with(|| { let mut enc_amounts = sha256::Hash::engine(); let mut enc_script_pubkeys = sha256::Hash::engine(); for prevout in prevouts { - prevout.value.consensus_encode(&mut enc_amounts).unwrap(); + prevout.borrow().value.consensus_encode(&mut enc_amounts).unwrap(); prevout + .borrow() .script_pubkey .consensus_encode(&mut enc_script_pubkeys) .unwrap(); @@ -898,8 +904,11 @@ mod tests { }; let mut c = SigHashCache::new(&dumb_tx); + // 1.29 fixes + let empty_vec = vec![]; + let empty_prevouts : Prevouts = Prevouts::All(&empty_vec); assert_eq!( - c.taproot_signature_hash(0, &Prevouts::All(&vec![]), None, None, SchnorrSigHashType::All), + c.taproot_signature_hash(0, &empty_prevouts, None, None, SchnorrSigHashType::All), Err(Error::PrevoutsSize) ); let two = vec![TxOut::default(), TxOut::default()]; @@ -988,7 +997,7 @@ mod tests { let prevouts = if sighash_type.split_anyonecanpay_flag().1 && tx_bytes[0] % 2 == 0 { // for anyonecanpay the `Prevouts::All` variant is good anyway, but sometimes we want to // test other codepaths - Prevouts::One(input_index, &prevouts[input_index]) + Prevouts::One(input_index, prevouts[input_index].clone()) } else { Prevouts::All(&prevouts) };