clementine_core/builder/transaction/
input.rs

1//! # Transaction Input Types and Utilities
2//!
3//! This module defines types and utilities for representing and handling transaction inputs used in [`super::TxHandler`].
4//! It provides abstractions for spendable inputs, input errors, correctness checks, supporting Taproot and script path spends.
5//!
6
7use crate::builder::script::SpendableScript;
8use crate::builder::sighash::TapTweakData;
9use crate::builder::{address::create_taproot_address, script::SpendPath};
10use crate::rpc::clementine::tagged_signature::SignatureId;
11use bitcoin::{
12    taproot::{LeafVersion, TaprootSpendInfo},
13    Amount, OutPoint, ScriptBuf, Sequence, TxIn, TxOut, Witness, WitnessProgram, XOnlyPublicKey,
14};
15use std::sync::Arc;
16
17#[derive(Debug, Clone)]
18/// Represents a spendable transaction input, including previous output, scripts, and Taproot spend info.
19pub struct SpendableTxIn {
20    /// The reference to the previous output that is being used as an input.
21    previous_outpoint: OutPoint,
22    prevout: TxOut, // locking script (taproot => op_1 op_pushbytes_32 tweaked pk)
23    /// Scripts associated with this input (for script path spends).
24    scripts: Vec<Arc<dyn SpendableScript>>,
25    /// Optional Taproot spend info for this input.
26    spendinfo: Option<TaprootSpendInfo>,
27}
28
29pub use clementine_errors::SpendableTxInError;
30
31pub use clementine_primitives::{UtxoVout, NUMBER_OF_ASSERT_TXS};
32
33impl SpendableTxIn {
34    /// Returns a reference to the previous output (TxOut) for this input.
35    pub fn get_prevout(&self) -> &TxOut {
36        &self.prevout
37    }
38
39    /// Returns a reference to the previous outpoint (OutPoint) for this input.
40    pub fn get_prev_outpoint(&self) -> &OutPoint {
41        &self.previous_outpoint
42    }
43
44    /// Creates a new [`SpendableTxIn`] with only a previous output and TxOut (no scripts or spend info).
45    pub fn new_partial(previous_output: OutPoint, prevout: TxOut) -> SpendableTxIn {
46        Self::new(previous_output, prevout, vec![], None)
47    }
48
49    /// Constructs a [`SpendableTxIn`] from scripts, value, and the internal key. Giving None for the internal key will create the tx
50    /// with an unspendable internal key.
51    ///
52    /// # Arguments
53    /// * `previous_output` - The outpoint being spent.
54    /// * `value` - The value of the previous output.
55    /// * `scripts` - Scripts for script path spends.
56    /// * `key_path` - The internal key for key path spends.
57    /// * `network` - Bitcoin network.
58    ///
59    /// # Returns
60    ///
61    /// A new [`SpendableTxIn`] with the specified parameters.
62    pub fn from_scripts(
63        previous_output: OutPoint,
64        value: Amount,
65        scripts: Vec<Arc<dyn SpendableScript>>,
66        key_path: Option<XOnlyPublicKey>,
67        network: bitcoin::Network,
68    ) -> SpendableTxIn {
69        let script_bufs: Vec<ScriptBuf> = scripts
70            .iter()
71            .map(|script| script.clone().to_script_buf())
72            .collect();
73        let (addr, spend_info) = create_taproot_address(&script_bufs, key_path, network);
74        Self::new(
75            previous_output,
76            TxOut {
77                value,
78                script_pubkey: addr.script_pubkey(),
79            },
80            scripts,
81            Some(spend_info),
82        )
83    }
84
85    /// Creates a new [`SpendableTxIn`] from all fields.
86    #[inline(always)]
87    pub fn new(
88        previous_output: OutPoint,
89        prevout: TxOut,
90        scripts: Vec<Arc<dyn SpendableScript>>,
91        spendinfo: Option<TaprootSpendInfo>,
92    ) -> SpendableTxIn {
93        if cfg!(debug_assertions) {
94            return Self::from_checked(previous_output, prevout, scripts, spendinfo)
95                .expect("failed to construct a spendabletxin in debug mode");
96        }
97
98        Self::from_unchecked(previous_output, prevout, scripts, spendinfo)
99    }
100
101    /// Returns a reference to the scripts for this input.
102    pub fn get_scripts(&self) -> &Vec<Arc<dyn SpendableScript>> {
103        &self.scripts
104    }
105
106    /// Returns a reference to the Taproot spend info for this input, if any.
107    pub fn get_spend_info(&self) -> &Option<TaprootSpendInfo> {
108        &self.spendinfo
109    }
110
111    /// Checks the validity of the spendable input, ensuring script pubkey and merkle proof map are correct.
112    fn check(&self) -> Result<(), SpendableTxInError> {
113        use SpendableTxInError::*;
114        let Some(spendinfo) = self.spendinfo.as_ref() else {
115            return Ok(());
116        };
117
118        let (prevout, scripts) = (&self.prevout, &self.scripts);
119
120        if ScriptBuf::new_witness_program(&WitnessProgram::p2tr_tweaked(spendinfo.output_key()))
121            != prevout.script_pubkey
122        {
123            return Err(IncorrectScriptPubkey);
124        }
125        let script_bufs: Vec<ScriptBuf> = scripts
126            .iter()
127            .map(|script| script.to_script_buf())
128            .collect();
129        if script_bufs.into_iter().any(|script| {
130            spendinfo
131                .script_map()
132                .get(&(script, LeafVersion::TapScript))
133                .is_none()
134        }) {
135            return Err(IncompleteMerkleProofMap);
136        }
137        Ok(())
138    }
139
140    /// Creates a [`SpendableTxIn`] with validation if the given input is valid (used in debug mode for testing).
141    fn from_checked(
142        previous_output: OutPoint,
143        prevout: TxOut,
144        scripts: Vec<Arc<dyn SpendableScript>>,
145        spendinfo: Option<TaprootSpendInfo>,
146    ) -> Result<SpendableTxIn, SpendableTxInError> {
147        let this = Self::from_unchecked(previous_output, prevout, scripts, spendinfo);
148        this.check()?;
149        Ok(this)
150    }
151
152    /// Creates a [`SpendableTxIn`] without validation (used in release mode).
153    fn from_unchecked(
154        previous_outpoint: OutPoint,
155        prevout: TxOut,
156        scripts: Vec<Arc<dyn SpendableScript>>,
157        spendinfo: Option<TaprootSpendInfo>,
158    ) -> SpendableTxIn {
159        SpendableTxIn {
160            previous_outpoint,
161            prevout,
162            scripts,
163            spendinfo,
164        }
165    }
166}
167
168#[allow(dead_code)]
169#[derive(Debug, Clone)]
170/// Represents a fully specified transaction input, including sequence, witness, spend path, and signature ID.
171pub struct SpentTxIn {
172    spendable: SpendableTxIn,
173    /// The sequence number, which suggests to miners which of two
174    /// conflicting transactions should be preferred, or 0xFFFFFFFF
175    /// to ignore this feature. This is generally never used since
176    /// the miner behavior cannot be enforced.
177    sequence: Sequence,
178    /// Witness data used to spend this TxIn. Can be None if the
179    /// transaction that this TxIn is in has not been signed yet.
180    ///
181    /// Has to be Some(_) when the transaction is signed.
182    witness: Option<Witness>,
183    /// Spend path for this input (key or script path).
184    spend_path: SpendPath,
185    /// Signature ID for this input, which signature in the protocol this input needs.
186    input_id: SignatureId,
187}
188
189impl SpentTxIn {
190    /// Constructs a [`SpentTxIn`] from a spendable input and associated metadata.
191    pub fn from_spendable(
192        input_id: SignatureId,
193        spendable: SpendableTxIn,
194        spend_path: SpendPath,
195        sequence: Sequence,
196        witness: Option<Witness>,
197    ) -> SpentTxIn {
198        SpentTxIn {
199            spendable,
200            sequence,
201            witness,
202            spend_path,
203            input_id,
204        }
205    }
206
207    /// Returns a reference to the underlying [`SpendableTxIn`].
208    pub fn get_spendable(&self) -> &SpendableTxIn {
209        &self.spendable
210    }
211
212    /// Returns the spend path for this input.
213    pub fn get_spend_path(&self) -> SpendPath {
214        self.spend_path
215    }
216
217    /// Returns the Taproot tweak data for this input, based on the spend path and spend info.
218    pub fn get_tweak_data(&self) -> TapTweakData {
219        match self.spend_path {
220            SpendPath::ScriptSpend(_) => TapTweakData::ScriptPath,
221            SpendPath::KeySpend => {
222                let spendinfo = self.spendable.get_spend_info();
223                match spendinfo {
224                    Some(spendinfo) => TapTweakData::KeyPath(spendinfo.merkle_root()),
225                    None => TapTweakData::Unknown,
226                }
227            }
228            SpendPath::Unknown => TapTweakData::Unknown,
229        }
230    }
231
232    /// Returns a reference to the witness data for this input, if any.
233    pub fn get_witness(&self) -> &Option<Witness> {
234        &self.witness
235    }
236
237    /// Returns the signature ID for this input.
238    pub fn get_signature_id(&self) -> SignatureId {
239        self.input_id
240    }
241
242    /// Sets the witness data for this input.
243    pub fn set_witness(&mut self, witness: Witness) {
244        self.witness = Some(witness);
245    }
246
247    // pub fn get_sequence(&self) -> Sequence {
248    //     self.sequence
249    // }
250
251    // pub fn set_sequence(&mut self, sequence: Sequence) {
252    //     self.sequence = sequence;
253    // }
254
255    /// Converts this [`SpentTxIn`] into a Bitcoin [`TxIn`] for inclusion in a Bitcoin transaction.
256    pub fn to_txin(&self) -> TxIn {
257        TxIn {
258            previous_output: self.spendable.previous_outpoint,
259            sequence: self.sequence,
260            script_sig: ScriptBuf::default(),
261            witness: self.witness.clone().unwrap_or_default(),
262        }
263    }
264}
265
266impl clementine_tx_sender::SpendableInputInfo for SpendableTxIn {
267    fn get_prevout(&self) -> &TxOut {
268        &self.prevout
269    }
270
271    fn get_outpoint(&self) -> OutPoint {
272        self.previous_outpoint
273    }
274}