//! Transparent-related (Bitcoin-inherited) functionality. #![allow(clippy::unit_arg)] mod address; mod keys; mod script; mod serialize; mod utxo; pub use address::Address; pub use script::Script; pub use utxo::{ new_ordered_outputs, new_outputs, utxos_from_ordered_utxos, CoinbaseSpendRestriction, OrderedUtxo, Utxo, }; #[cfg(any(test, feature = "proptest-impl"))] pub(crate) use utxo::new_transaction_ordered_outputs; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; #[cfg(any(test, feature = "proptest-impl"))] mod arbitrary; #[cfg(test)] mod prop; use crate::{ amount::{Amount, NegativeAllowed, NonNegative}, block, transaction, }; use std::collections::HashMap; /// Arbitrary data inserted by miners into a coinbase transaction. #[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct CoinbaseData( /// Invariant: this vec, together with the coinbase height, must be less than /// 100 bytes. We enforce this by only constructing CoinbaseData fields by /// parsing blocks with 100-byte data fields. When we implement block /// creation, we should provide a constructor for the coinbase data field /// that restricts it to 95 = 100 -1 -4 bytes (safe for any block height up /// to 500_000_000). pub(super) Vec, ); #[cfg(any(test, feature = "proptest-impl"))] impl CoinbaseData { /// Create a new `CoinbaseData` containing `data`. /// /// Only for use in tests. pub fn new(data: Vec) -> CoinbaseData { CoinbaseData(data) } } impl AsRef<[u8]> for CoinbaseData { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl std::fmt::Debug for CoinbaseData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let escaped = String::from_utf8( self.0 .iter() .cloned() .flat_map(std::ascii::escape_default) .collect(), ) .expect("ascii::escape_default produces utf8"); f.debug_tuple("CoinbaseData").field(&escaped).finish() } } /// OutPoint /// /// A particular transaction output reference. #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub struct OutPoint { /// References the transaction that contains the UTXO being spent. pub hash: transaction::Hash, /// Identifies which UTXO from that transaction is referenced; the /// first output is 0, etc. pub index: u32, } /// A transparent input to a transaction. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Input { /// A reference to an output of a previous transaction. PrevOut { /// The previous output transaction reference. outpoint: OutPoint, /// The script that authorizes spending `outpoint`. unlock_script: Script, /// The sequence number for the output. sequence: u32, }, /// New coins created by the block reward. Coinbase { /// The height of this block. height: block::Height, /// Free data inserted by miners after the block height. data: CoinbaseData, /// The sequence number for the output. sequence: u32, }, } impl Input { /// If this is a `PrevOut` input, returns this input's outpoint. /// Otherwise, returns `None`. pub fn outpoint(&self) -> Option { if let Input::PrevOut { outpoint, .. } = self { Some(*outpoint) } else { None } } /// Set this input's outpoint. /// /// Should only be called on `PrevOut` inputs. /// /// # Panics /// /// If `self` is a coinbase input. #[cfg(any(test, feature = "proptest-impl"))] pub fn set_outpoint(&mut self, new_outpoint: OutPoint) { if let Input::PrevOut { ref mut outpoint, .. } = self { *outpoint = new_outpoint; } else { unreachable!("unexpected variant: Coinbase Inputs do not have OutPoints"); } } /// Get the value spent by this input. /// This amount is added to the transaction value pool by this input. /// /// # Panics /// /// If the provided Utxos don't have the transaction outpoint. pub fn value(&self, utxos: &HashMap) -> Amount { match self { Input::PrevOut { outpoint, .. } => utxos .get(outpoint) .expect("Provided Utxos don't have transaction Outpoint") .output .value .constrain() .expect("conversion from NonNegative to NegativeAllowed is always valid"), Input::Coinbase { .. } => Amount::zero(), } } } /// A transparent output from a transaction. /// /// The most fundamental building block of a transaction is a /// transaction output -- the ZEC you own in your "wallet" is in /// fact a subset of unspent transaction outputs (or "UTXO"s) of the /// global UTXO set. /// /// UTXOs are indivisible, discrete units of value which can only be /// consumed in their entirety. Thus, if I want to send you 1 ZEC and /// I only own one UTXO worth 2 ZEC, I would construct a transaction /// that spends my UTXO and sends 1 ZEC to you and 1 ZEC back to me /// (just like receiving change). #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub struct Output { /// Transaction value. // At https://en.bitcoin.it/wiki/Protocol_documentation#tx, this is an i64. pub value: Amount, /// The lock script defines the conditions under which this output can be spent. pub lock_script: Script, } impl Output { /// Get the value contained in this output. /// This amount is subtracted from the transaction value pool by this output. pub fn value(&self) -> Amount { self.value .constrain() .expect("conversion from NonNegative to NegativeAllowed is always valid") } }