//! Contains code that interfaces with the zcash_primitives crate from //! librustzcash. use std::{ convert::{TryFrom, TryInto}, io, ops::Deref, }; use zcash_primitives::transaction as zp_tx; use crate::{ amount::{Amount, NonNegative}, parameters::{Network, NetworkUpgrade}, serialization::ZcashSerialize, transaction::{AuthDigest, HashType, SigHash, Transaction}, transparent::{self, Script}, }; // Used by boilerplate code below. #[derive(Clone, Debug)] struct TransparentAuth<'a> { all_prev_outputs: &'a [transparent::Output], } impl zp_tx::components::transparent::Authorization for TransparentAuth<'_> { type ScriptSig = zcash_primitives::legacy::Script; } // In this block we convert our Output to a librustzcash to TxOut. // (We could do the serialize/deserialize route but it's simple enough to convert manually) impl zp_tx::sighash::TransparentAuthorizingContext for TransparentAuth<'_> { fn input_amounts(&self) -> Vec { self.all_prev_outputs .iter() .map(|prevout| { zp_tx::components::amount::Amount::from_nonnegative_i64_le_bytes( prevout.value.to_bytes(), ) .expect("will not fail since it was previously validated") }) .collect() } fn input_scriptpubkeys(&self) -> Vec { self.all_prev_outputs .iter() .map(|prevout| { zcash_primitives::legacy::Script(prevout.lock_script.as_raw_bytes().into()) }) .collect() } } // Boilerplate mostly copied from `zcash/src/rust/src/transaction_ffi.rs` which is required // to compute sighash. // TODO: remove/change if they improve the API to not require this. struct MapTransparent<'a> { auth: TransparentAuth<'a>, } impl<'a> zp_tx::components::transparent::MapAuth< zp_tx::components::transparent::Authorized, TransparentAuth<'a>, > for MapTransparent<'a> { fn map_script_sig( &self, s: ::ScriptSig, ) -> ::ScriptSig { s } fn map_authorization( &self, _: zp_tx::components::transparent::Authorized, ) -> TransparentAuth<'a> { // TODO: This map should consume self, so we can move self.auth self.auth.clone() } } struct IdentityMap; impl zp_tx::components::sapling::MapAuth< zp_tx::components::sapling::Authorized, zp_tx::components::sapling::Authorized, > for IdentityMap { fn map_proof( &self, p: ::Proof, ) -> ::Proof { p } fn map_auth_sig( &self, s: ::AuthSig, ) -> ::AuthSig{ s } fn map_authorization( &self, a: zp_tx::components::sapling::Authorized, ) -> zp_tx::components::sapling::Authorized { a } } impl zp_tx::components::orchard::MapAuth for IdentityMap { fn map_spend_auth( &self, s: ::SpendAuth, ) -> ::SpendAuth { s } fn map_authorization(&self, a: orchard::bundle::Authorized) -> orchard::bundle::Authorized { a } } struct PrecomputedAuth<'a> { _phantom: std::marker::PhantomData<&'a ()>, } impl<'a> zp_tx::Authorization for PrecomputedAuth<'a> { type TransparentAuth = TransparentAuth<'a>; type SaplingAuth = zp_tx::components::sapling::Authorized; type OrchardAuth = orchard::bundle::Authorized; } // End of (mostly) copied code impl TryFrom<&Transaction> for zp_tx::Transaction { type Error = io::Error; /// Convert a Zebra transaction into a librustzcash one. /// /// # Panics /// /// If the transaction is not V5. (Currently there is no need for this /// conversion for other versions.) fn try_from(trans: &Transaction) -> Result { let network_upgrade = match trans { Transaction::V5 { network_upgrade, .. } => network_upgrade, Transaction::V1 { .. } | Transaction::V2 { .. } | Transaction::V3 { .. } | Transaction::V4 { .. } => panic!("Zebra only uses librustzcash for V5 transactions"), }; convert_tx_to_librustzcash(trans, *network_upgrade) } } pub(crate) fn convert_tx_to_librustzcash( trans: &Transaction, network_upgrade: NetworkUpgrade, ) -> Result { let serialized_tx = trans.zcash_serialize_to_vec()?; let branch_id: u32 = network_upgrade .branch_id() .expect("Network upgrade must have a Branch ID") .into(); // We've already parsed this transaction, so its network upgrade must be valid. let branch_id: zcash_primitives::consensus::BranchId = branch_id .try_into() .expect("zcash_primitives and Zebra have the same branch ids"); let alt_tx = zp_tx::Transaction::read(&serialized_tx[..], branch_id)?; Ok(alt_tx) } /// Convert a Zebra Amount into a librustzcash one. impl TryFrom> for zp_tx::components::Amount { type Error = (); fn try_from(amount: Amount) -> Result { zp_tx::components::Amount::from_u64(amount.into()) } } /// Convert a Zebra Script into a librustzcash one. impl From<&Script> for zcash_primitives::legacy::Script { fn from(script: &Script) -> Self { zcash_primitives::legacy::Script(script.as_raw_bytes().to_vec()) } } /// Convert a Zebra Script into a librustzcash one. impl From