clementine_core/builder/transaction/
input.rs1use 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)]
18pub struct SpendableTxIn {
20 previous_outpoint: OutPoint,
22 prevout: TxOut, scripts: Vec<Arc<dyn SpendableScript>>,
25 spendinfo: Option<TaprootSpendInfo>,
27}
28
29pub use clementine_errors::SpendableTxInError;
30
31pub use clementine_primitives::{UtxoVout, NUMBER_OF_ASSERT_TXS};
32
33impl SpendableTxIn {
34 pub fn get_prevout(&self) -> &TxOut {
36 &self.prevout
37 }
38
39 pub fn get_prev_outpoint(&self) -> &OutPoint {
41 &self.previous_outpoint
42 }
43
44 pub fn new_partial(previous_output: OutPoint, prevout: TxOut) -> SpendableTxIn {
46 Self::new(previous_output, prevout, vec![], None)
47 }
48
49 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 #[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 pub fn get_scripts(&self) -> &Vec<Arc<dyn SpendableScript>> {
103 &self.scripts
104 }
105
106 pub fn get_spend_info(&self) -> &Option<TaprootSpendInfo> {
108 &self.spendinfo
109 }
110
111 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 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 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)]
170pub struct SpentTxIn {
172 spendable: SpendableTxIn,
173 sequence: Sequence,
178 witness: Option<Witness>,
183 spend_path: SpendPath,
185 input_id: SignatureId,
187}
188
189impl SpentTxIn {
190 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 pub fn get_spendable(&self) -> &SpendableTxIn {
209 &self.spendable
210 }
211
212 pub fn get_spend_path(&self) -> SpendPath {
214 self.spend_path
215 }
216
217 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 pub fn get_witness(&self) -> &Option<Witness> {
234 &self.witness
235 }
236
237 pub fn get_signature_id(&self) -> SignatureId {
239 self.input_id
240 }
241
242 pub fn set_witness(&mut self, witness: Witness) {
244 self.witness = Some(witness);
245 }
246
247 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}