Change Prevouts::All(&[TxOut]) to Prevouts::All(&[Borrow<T>])

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]
This commit is contained in:
sanket1729 2022-02-16 23:35:54 -08:00
parent 0c5b695194
commit 10fedfb3b4
1 changed files with 29 additions and 20 deletions

View File

@ -25,6 +25,7 @@ use blockdata::witness::Witness;
use consensus::{encode, Encodable}; use consensus::{encode, Encodable};
use core::fmt; use core::fmt;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use core::borrow::Borrow;
use hashes::{sha256, sha256d, Hash}; use hashes::{sha256, sha256d, Hash};
use io; use io;
use util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash}; use util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash};
@ -80,14 +81,14 @@ struct TaprootCache {
/// Contains outputs of previous transactions. /// Contains outputs of previous transactions.
/// In the case [`SchnorrSigHashType`] variant is `ANYONECANPAY`, [`Prevouts::One`] may be provided /// In the case [`SchnorrSigHashType`] variant is `ANYONECANPAY`, [`Prevouts::One`] may be provided
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Prevouts<'u> { pub enum Prevouts<'u, T> where T: 'u + Borrow<TxOut> {
/// `One` variant allows to provide the single Prevout needed. It's useful for example /// `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. /// 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. /// 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 /// When `ANYONECANPAY` is not provided, or the caller is handy giving all prevouts so the same
/// variable can be used for multiple inputs. /// variable can be used for multiple inputs.
All(&'u [TxOut]), All(&'u [T]),
} }
const KEY_VERSION_0: u8 = 0u8; const KEY_VERSION_0: u8 = 0u8;
@ -188,7 +189,7 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl ::std::error::Error for Error {} impl ::std::error::Error for Error {}
impl<'u> Prevouts<'u> { impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
fn check_all(&self, tx: &Transaction) -> Result<(), Error> { fn check_all(&self, tx: &Transaction) -> Result<(), Error> {
if let Prevouts::All(prevouts) = self { if let Prevouts::All(prevouts) = self {
if prevouts.len() != tx.input.len() { if prevouts.len() != tx.input.len() {
@ -198,9 +199,9 @@ impl<'u> Prevouts<'u> {
Ok(()) Ok(())
} }
fn get_all(&self) -> Result<&[TxOut], Error> { fn get_all(&self) -> Result<&[T], Error> {
match self { match self {
Prevouts::All(prevouts) => Ok(prevouts), Prevouts::All(prevouts) => Ok(*prevouts),
_ => Err(Error::PrevoutKind), _ => Err(Error::PrevoutKind),
} }
} }
@ -209,12 +210,15 @@ impl<'u> Prevouts<'u> {
match self { match self {
Prevouts::One(index, prevout) => { Prevouts::One(index, prevout) => {
if input_index == *index { if input_index == *index {
Ok(prevout) Ok(prevout.borrow())
} else { } else {
Err(Error::PrevoutIndex) 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<R: Deref<Target = Transaction>> SigHashCache<R> {
/// Encode the BIP341 signing data for any flag type into a given object implementing a /// Encode the BIP341 signing data for any flag type into a given object implementing a
/// io::Write trait. /// io::Write trait.
pub fn taproot_encode_signing_data_to<Write: io::Write>( pub fn taproot_encode_signing_data_to<Write: io::Write, T: Borrow<TxOut>>(
&mut self, &mut self,
mut writer: Write, mut writer: Write,
input_index: usize, input_index: usize,
prevouts: &Prevouts, prevouts: &Prevouts<T>,
annex: Option<Annex>, annex: Option<Annex>,
leaf_hash_code_separator: Option<(TapLeafHash, u32)>, leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
sighash_type: SchnorrSigHashType, sighash_type: SchnorrSigHashType,
@ -437,10 +441,10 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
} }
/// Compute the BIP341 sighash for any flag type. /// Compute the BIP341 sighash for any flag type.
pub fn taproot_signature_hash( pub fn taproot_signature_hash<T: Borrow<TxOut>>(
&mut self, &mut self,
input_index: usize, input_index: usize,
prevouts: &Prevouts, prevouts: &Prevouts<T>,
annex: Option<Annex>, annex: Option<Annex>,
leaf_hash_code_separator: Option<(TapLeafHash, u32)>, leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
sighash_type: SchnorrSigHashType, sighash_type: SchnorrSigHashType,
@ -458,10 +462,10 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
} }
/// Compute the BIP341 sighash for a key spend /// Compute the BIP341 sighash for a key spend
pub fn taproot_key_spend_signature_hash( pub fn taproot_key_spend_signature_hash<T: Borrow<TxOut>>(
&mut self, &mut self,
input_index: usize, input_index: usize,
prevouts: &Prevouts, prevouts: &Prevouts<T>,
sighash_type: SchnorrSigHashType, sighash_type: SchnorrSigHashType,
) -> Result<TapSighashHash, Error> { ) -> Result<TapSighashHash, Error> {
let mut enc = TapSighashHash::engine(); let mut enc = TapSighashHash::engine();
@ -480,10 +484,10 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
/// ///
/// Assumes the default `OP_CODESEPARATOR` position of `0xFFFFFFFF`. Custom values can be /// 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`]. /// provided through the more fine-grained API of [`SigHashCache::taproot_encode_signing_data_to`].
pub fn taproot_script_spend_signature_hash<S: Into<TapLeafHash>>( pub fn taproot_script_spend_signature_hash<S: Into<TapLeafHash>, T: Borrow<TxOut>>(
&mut self, &mut self,
input_index: usize, input_index: usize,
prevouts: &Prevouts, prevouts: &Prevouts<T>,
leaf_hash: S, leaf_hash: S,
sighash_type: SchnorrSigHashType, sighash_type: SchnorrSigHashType,
) -> Result<TapSighashHash, Error> { ) -> Result<TapSighashHash, Error> {
@ -667,13 +671,15 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
}) })
} }
fn taproot_cache(&mut self, prevouts: &[TxOut]) -> &TaprootCache { fn taproot_cache<T: Borrow<TxOut>>(&mut self, prevouts: &[T]) -> &TaprootCache
{
self.taproot_cache.get_or_insert_with(|| { self.taproot_cache.get_or_insert_with(|| {
let mut enc_amounts = sha256::Hash::engine(); let mut enc_amounts = sha256::Hash::engine();
let mut enc_script_pubkeys = sha256::Hash::engine(); let mut enc_script_pubkeys = sha256::Hash::engine();
for prevout in prevouts { for prevout in prevouts {
prevout.value.consensus_encode(&mut enc_amounts).unwrap(); prevout.borrow().value.consensus_encode(&mut enc_amounts).unwrap();
prevout prevout
.borrow()
.script_pubkey .script_pubkey
.consensus_encode(&mut enc_script_pubkeys) .consensus_encode(&mut enc_script_pubkeys)
.unwrap(); .unwrap();
@ -898,8 +904,11 @@ mod tests {
}; };
let mut c = SigHashCache::new(&dumb_tx); let mut c = SigHashCache::new(&dumb_tx);
// 1.29 fixes
let empty_vec = vec![];
let empty_prevouts : Prevouts<TxOut> = Prevouts::All(&empty_vec);
assert_eq!( 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) Err(Error::PrevoutsSize)
); );
let two = vec![TxOut::default(), TxOut::default()]; 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 { 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 // for anyonecanpay the `Prevouts::All` variant is good anyway, but sometimes we want to
// test other codepaths // test other codepaths
Prevouts::One(input_index, &prevouts[input_index]) Prevouts::One(input_index, prevouts[input_index].clone())
} else { } else {
Prevouts::All(&prevouts) Prevouts::All(&prevouts)
}; };