// SPDX-License-Identifier: CC0-1.0 //! Bitcoin transactions. //! //! A transaction describes a transfer of money. It consumes previously-unspent //! transaction outputs and produces new ones, satisfying the condition to spend //! the old outputs (typically a digital signature with a specific key must be //! provided) and defining the condition to spend the new ones. The use of digital //! signatures ensures that coins cannot be spent by unauthorized parties. //! //! This module provides the structures and functions needed to support transactions. use core::fmt; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; use hashes::sha256d; #[cfg(feature = "alloc")] use internals::write_err; #[cfg(feature = "alloc")] use units::{parse, Amount}; #[cfg(feature = "alloc")] use crate::script::ScriptBuf; #[cfg(feature = "alloc")] use crate::sequence::Sequence; #[cfg(feature = "alloc")] use crate::witness::Witness; /// Bitcoin transaction input. /// /// It contains the location of the previous transaction's output, /// that it spends and set of scripts that satisfy its spending /// conditions. /// /// ### Bitcoin Core References /// /// * [CTxIn definition](https://github.com/bitcoin/bitcoin/blob/345457b542b6a980ccfbc868af0970a6f91d1b82/src/primitives/transaction.h#L65) #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg(feature = "alloc")] pub struct TxIn { /// The reference to the previous output that is being used as an input. pub previous_output: OutPoint, /// The script which pushes values on the stack which will cause /// the referenced output's script to be accepted. pub script_sig: ScriptBuf, /// The sequence number, which suggests to miners which of two /// conflicting transactions should be preferred, or 0xFFFFFFFF /// to ignore this feature. This is generally never used since /// the miner behavior cannot be enforced. pub sequence: Sequence, /// Witness data: an array of byte-arrays. /// Note that this field is *not* (de)serialized with the rest of the TxIn in /// Encodable/Decodable, as it is (de)serialized at the end of the full /// Transaction. It *is* (de)serialized with the rest of the TxIn in other /// (de)serialization routines. pub witness: Witness, } #[cfg(feature = "alloc")] impl TxIn { /// An empty transaction input with the previous output as for a coinbase transaction. pub const EMPTY_COINBASE: TxIn = TxIn { previous_output: OutPoint::COINBASE_PREVOUT, script_sig: ScriptBuf::new(), sequence: Sequence::MAX, witness: Witness::new(), }; } /// Bitcoin transaction output. /// /// Defines new coins to be created as a result of the transaction, /// along with spending conditions ("script", aka "output script"), /// which an input spending it must satisfy. /// /// An output that is not yet spent by an input is called Unspent Transaction Output ("UTXO"). /// /// ### Bitcoin Core References /// /// * [CTxOut definition](https://github.com/bitcoin/bitcoin/blob/345457b542b6a980ccfbc868af0970a6f91d1b82/src/primitives/transaction.h#L148) #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg(feature = "alloc")] pub struct TxOut { /// The value of the output, in satoshis. pub value: Amount, /// The script which must be satisfied for the output to be spent. pub script_pubkey: ScriptBuf, } #[cfg(feature = "alloc")] impl TxOut { /// This is used as a "null txout" in consensus signing code. pub const NULL: Self = TxOut { value: Amount::from_sat(0xffffffffffffffff), script_pubkey: ScriptBuf::new() }; } /// A reference to a transaction output. /// /// ### Bitcoin Core References /// /// * [COutPoint definition](https://github.com/bitcoin/bitcoin/blob/345457b542b6a980ccfbc868af0970a6f91d1b82/src/primitives/transaction.h#L26) #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct OutPoint { /// The referenced transaction's txid. pub txid: Txid, /// The index of the referenced output in its transaction's vout. pub vout: u32, } #[cfg(feature = "serde")] internals::serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout); impl OutPoint { /// The number of bytes that an outpoint contributes to the size of a transaction. pub const SIZE: usize = 32 + 4; // The serialized lengths of txid and vout. /// The `OutPoint` used in a coinbase prevout. /// /// This is used as the dummy input for coinbase transactions because they don't have any /// previous outputs. In other words, does not point to a real transaction. pub const COINBASE_PREVOUT: Self = Self { txid: Txid::COINBASE_PREVOUT, vout: u32::MAX }; } impl fmt::Display for OutPoint { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}", self.txid, self.vout) } } #[cfg(feature = "alloc")] impl core::str::FromStr for OutPoint { type Err = ParseOutPointError; fn from_str(s: &str) -> Result { if s.len() > 75 { // 64 + 1 + 10 return Err(ParseOutPointError::TooLong); } let find = s.find(':'); if find.is_none() || find != s.rfind(':') { return Err(ParseOutPointError::Format); } let colon = find.unwrap(); if colon == 0 || colon == s.len() - 1 { return Err(ParseOutPointError::Format); } Ok(OutPoint { txid: s[..colon].parse().map_err(ParseOutPointError::Txid)?, vout: parse_vout(&s[colon + 1..])?, }) } } /// Parses a string-encoded transaction index (vout). /// /// Does not permit leading zeroes or non-digit characters. #[cfg(feature = "alloc")] fn parse_vout(s: &str) -> Result { if s.len() > 1 { let first = s.chars().next().unwrap(); if first == '0' || first == '+' { return Err(ParseOutPointError::VoutNotCanonical); } } parse::int(s).map_err(ParseOutPointError::Vout) } /// An error in parsing an [`OutPoint`]. #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] #[cfg(feature = "alloc")] pub enum ParseOutPointError { /// Error in TXID part. Txid(hex::HexToArrayError), /// Error in vout part. Vout(parse::ParseIntError), /// Error in general format. Format, /// Size exceeds max. TooLong, /// Vout part is not strictly numeric without leading zeroes. VoutNotCanonical, } #[cfg(feature = "alloc")] internals::impl_from_infallible!(ParseOutPointError); #[cfg(feature = "alloc")] impl fmt::Display for ParseOutPointError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use ParseOutPointError::*; match *self { Txid(ref e) => write_err!(f, "error parsing TXID"; e), Vout(ref e) => write_err!(f, "error parsing vout"; e), Format => write!(f, "OutPoint not in : format"), TooLong => write!(f, "vout should be at most 10 digits"), VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"), } } } #[cfg(feature = "std")] impl std::error::Error for ParseOutPointError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use ParseOutPointError::*; match self { Txid(e) => Some(e), Vout(e) => Some(e), Format | TooLong | VoutNotCanonical => None, } } } hashes::hash_newtype! { /// A bitcoin transaction hash/transaction ID. /// /// For compatibility with the existing Bitcoin infrastructure and historical and current /// versions of the Bitcoin Core software itself, this and other [`sha256d::Hash`] types, are /// serialized in reverse byte order when converted to a hex string via [`std::fmt::Display`] /// trait operations. /// /// See [`hashes::Hash::DISPLAY_BACKWARD`] for more details. pub struct Txid(sha256d::Hash); /// A bitcoin witness transaction ID. pub struct Wtxid(sha256d::Hash); } impl Txid { /// The `Txid` used in a coinbase prevout. /// /// This is used as the "txid" of the dummy input of a coinbase transaction. This is not a real /// TXID and should not be used in any other contexts. See [`OutPoint::COINBASE_PREVOUT`]. pub const COINBASE_PREVOUT: Self = Self::from_byte_array([0; 32]); } impl Wtxid { /// The `Wtxid` of a coinbase transaction. /// /// This is used as the wTXID for the coinbase transaction when constructing blocks (in the /// witness commitment tree) since the coinbase transaction contains a commitment to all /// transactions' wTXIDs but naturally cannot commit to its own. pub const COINBASE: Self = Self::from_byte_array([0; 32]); } /// The transaction version. /// /// Currently, as specified by [BIP-68] and [BIP-431], version 1, 2, and 3 are considered standard. /// /// Standardness of the inner `i32` is not an invariant because you are free to create transactions /// of any version, transactions with non-standard version numbers will not be relayed by the /// Bitcoin network. /// /// [BIP-68]: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki /// [BIP-431]: https://github.com/bitcoin/bips/blob/master/bip-0431.mediawiki #[derive(Copy, PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Version(pub i32); impl Version { /// The original Bitcoin transaction version (pre-BIP-68). pub const ONE: Self = Self(1); /// The second Bitcoin transaction version (post-BIP-68). pub const TWO: Self = Self(2); /// The third Bitcoin transaction version (post-BIP-431). pub const THREE: Self = Self(3); } impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } #[cfg(feature = "arbitrary")] #[cfg(feature = "alloc")] impl<'a> Arbitrary<'a> for TxIn { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { Ok(TxIn { previous_output: OutPoint::arbitrary(u)?, script_sig: ScriptBuf::arbitrary(u)?, sequence: Sequence::arbitrary(u)?, witness: Witness::arbitrary(u)?, }) } } #[cfg(feature = "arbitrary")] #[cfg(feature = "alloc")] impl<'a> Arbitrary<'a> for TxOut { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { Ok(TxOut { value: Amount::arbitrary(u)?, script_pubkey: ScriptBuf::arbitrary(u)? }) } } #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for OutPoint { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { Ok(OutPoint { txid: Txid::arbitrary(u)?, vout: u32::arbitrary(u)? }) } } #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Version { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { // Equally weight the case of normal version numbers let choice = u.int_in_range(0..=3)?; match choice { 0 => Ok(Version::ONE), 1 => Ok(Version::TWO), 2 => Ok(Version::THREE), _ => Ok(Version(u.arbitrary()?)), } } } #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Txid { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { let arbitrary_bytes = u.arbitrary()?; let t = sha256d::Hash::from_byte_array(arbitrary_bytes); Ok(Txid(t)) } }