kaspa_consensus_client/
input.rs

1//!
2//! Implementation of the client-side [`TransactionInput`] struct used by the client-side [`Transaction`] struct.
3//!
4
5#![allow(non_snake_case)]
6
7use crate::imports::*;
8use crate::result::Result;
9use crate::TransactionOutpoint;
10use crate::UtxoEntryReference;
11use kaspa_utils::hex::*;
12
13#[wasm_bindgen(typescript_custom_section)]
14const TS_TRANSACTION: &'static str = r#"
15/**
16 * Interface defines the structure of a transaction input.
17 * 
18 * @category Consensus
19 */
20export interface ITransactionInput {
21    previousOutpoint: ITransactionOutpoint;
22    signatureScript?: HexString;
23    sequence: bigint;
24    sigOpCount: number;
25    utxo?: UtxoEntryReference;
26
27    /** Optional verbose data provided by RPC */
28    verboseData?: ITransactionInputVerboseData;
29}
30
31/**
32 * Option transaction input verbose data.
33 * 
34 * @category Node RPC
35 */
36export interface ITransactionInputVerboseData { }
37
38"#;
39
40#[wasm_bindgen]
41extern "C" {
42    /// WASM (TypeScript) type representing `ITransactionInput | TransactionInput`
43    /// @category Consensus
44    #[wasm_bindgen(typescript_type = "ITransactionInput | TransactionInput")]
45    pub type TransactionInputT;
46    /// WASM (TypeScript) type representing `ITransactionInput[] | TransactionInput[]`
47    /// @category Consensus
48    #[wasm_bindgen(typescript_type = "(ITransactionInput | TransactionInput)[]")]
49    pub type TransactionInputArrayAsArgT;
50    /// WASM (TypeScript) type representing `TransactionInput[]`
51    /// @category Consensus
52    #[wasm_bindgen(typescript_type = "TransactionInput[]")]
53    pub type TransactionInputArrayAsResultT;
54}
55
56/// Inner type used by [`TransactionInput`]
57#[derive(Debug, Clone, Serialize, Deserialize)]
58#[serde(rename_all = "camelCase")]
59pub struct TransactionInputInner {
60    pub previous_outpoint: TransactionOutpoint,
61    pub signature_script: Option<Vec<u8>>,
62    pub sequence: u64,
63    pub sig_op_count: u8,
64    pub utxo: Option<UtxoEntryReference>,
65}
66
67impl TransactionInputInner {
68    pub fn new(
69        previous_outpoint: TransactionOutpoint,
70        signature_script: Option<Vec<u8>>,
71        sequence: u64,
72        sig_op_count: u8,
73        utxo: Option<UtxoEntryReference>,
74    ) -> Self {
75        Self { previous_outpoint, signature_script, sequence, sig_op_count, utxo }
76    }
77}
78
79/// Represents a Kaspa transaction input
80/// @category Consensus
81#[derive(Clone, Debug, Serialize, Deserialize, CastFromJs)]
82#[wasm_bindgen(inspectable)]
83pub struct TransactionInput {
84    inner: Arc<Mutex<TransactionInputInner>>,
85}
86
87impl TransactionInput {
88    pub fn new(
89        previous_outpoint: TransactionOutpoint,
90        signature_script: Option<Vec<u8>>,
91        sequence: u64,
92        sig_op_count: u8,
93        utxo: Option<UtxoEntryReference>,
94    ) -> Self {
95        let inner = TransactionInputInner::new(previous_outpoint, signature_script, sequence, sig_op_count, utxo);
96        Self { inner: Arc::new(Mutex::new(inner)) }
97    }
98
99    pub fn new_with_inner(inner: TransactionInputInner) -> Self {
100        Self { inner: Arc::new(Mutex::new(inner)) }
101    }
102
103    pub fn inner(&self) -> MutexGuard<'_, TransactionInputInner> {
104        self.inner.lock().unwrap()
105    }
106
107    pub fn sig_op_count(&self) -> u8 {
108        self.inner().sig_op_count
109    }
110
111    pub fn signature_script_length(&self) -> usize {
112        self.inner().signature_script.as_ref().map(|signature_script| signature_script.len()).unwrap_or_default()
113    }
114
115    pub fn utxo(&self) -> Option<UtxoEntryReference> {
116        self.inner().utxo.clone()
117    }
118}
119
120#[wasm_bindgen]
121impl TransactionInput {
122    #[wasm_bindgen(constructor)]
123    pub fn constructor(value: &TransactionInputT) -> Result<TransactionInput> {
124        Self::try_owned_from(value)
125    }
126
127    #[wasm_bindgen(getter = previousOutpoint)]
128    pub fn get_previous_outpoint(&self) -> TransactionOutpoint {
129        self.inner().previous_outpoint.clone()
130    }
131
132    #[wasm_bindgen(setter = previousOutpoint)]
133    pub fn set_previous_outpoint(&mut self, js_value: &JsValue) -> Result<()> {
134        match js_value.try_into() {
135            Ok(outpoint) => {
136                self.inner().previous_outpoint = outpoint;
137                Ok(())
138            }
139            Err(_) => Err(Error::custom("invalid outpoint script".to_string())),
140        }
141    }
142
143    #[wasm_bindgen(getter = signatureScript)]
144    pub fn get_signature_script_as_hex(&self) -> Option<String> {
145        self.inner().signature_script.as_ref().map(|script| script.to_hex())
146    }
147
148    #[wasm_bindgen(setter = signatureScript)]
149    pub fn set_signature_script_from_js_value(&mut self, js_value: JsValue) -> Result<()> {
150        match js_value.try_as_vec_u8() {
151            Ok(signature) => {
152                self.set_signature_script(signature);
153                Ok(())
154            }
155            Err(_) => Err(Error::custom("invalid signature script".to_string())),
156        }
157    }
158
159    #[wasm_bindgen(getter = sequence)]
160    pub fn get_sequence(&self) -> u64 {
161        self.inner().sequence
162    }
163
164    #[wasm_bindgen(setter = sequence)]
165    pub fn set_sequence(&mut self, sequence: u64) {
166        self.inner().sequence = sequence;
167    }
168
169    #[wasm_bindgen(getter = sigOpCount)]
170    pub fn get_sig_op_count(&self) -> u8 {
171        self.inner().sig_op_count
172    }
173
174    #[wasm_bindgen(setter = sigOpCount)]
175    pub fn set_sig_op_count(&mut self, sig_op_count: u8) {
176        self.inner().sig_op_count = sig_op_count;
177    }
178
179    #[wasm_bindgen(getter = utxo)]
180    pub fn get_utxo(&self) -> Option<UtxoEntryReference> {
181        self.inner().utxo.clone()
182    }
183}
184
185impl TransactionInput {
186    pub fn set_signature_script(&self, signature_script: Vec<u8>) {
187        self.inner().signature_script.replace(signature_script);
188    }
189
190    pub fn script_public_key(&self) -> Option<ScriptPublicKey> {
191        self.utxo().map(|utxo_ref| utxo_ref.utxo.script_public_key.clone())
192    }
193}
194
195impl AsRef<TransactionInput> for TransactionInput {
196    fn as_ref(&self) -> &TransactionInput {
197        self
198    }
199}
200
201impl TryCastFromJs for TransactionInput {
202    type Error = Error;
203    fn try_cast_from<'a, R>(value: &'a R) -> std::result::Result<Cast<Self>, Self::Error>
204    where
205        R: AsRef<JsValue> + 'a,
206    {
207        Self::resolve_cast(value, || {
208            if let Some(object) = Object::try_from(value.as_ref()) {
209                let previous_outpoint: TransactionOutpoint = object.get_value("previousOutpoint")?.as_ref().try_into()?;
210                let signature_script = object.get_vec_u8("signatureScript").ok();
211                let sequence = object.get_u64("sequence")?;
212                let sig_op_count = object.get_u8("sigOpCount")?;
213                let utxo = object.try_cast_into::<UtxoEntryReference>("utxo")?;
214                Ok(TransactionInput::new(previous_outpoint, signature_script, sequence, sig_op_count, utxo).into())
215            } else {
216                Err("TransactionInput must be an object".into())
217            }
218        })
219    }
220}
221
222impl From<cctx::TransactionInput> for TransactionInput {
223    fn from(tx_input: cctx::TransactionInput) -> Self {
224        TransactionInput::new(
225            tx_input.previous_outpoint.into(),
226            Some(tx_input.signature_script),
227            tx_input.sequence,
228            tx_input.sig_op_count,
229            None,
230        )
231    }
232}
233
234impl From<&TransactionInput> for cctx::TransactionInput {
235    fn from(tx_input: &TransactionInput) -> Self {
236        let inner = tx_input.inner();
237        cctx::TransactionInput::new(
238            inner.previous_outpoint.clone().into(),
239            // TODO - discuss: should this unwrap_or_default or return an error?
240            inner.signature_script.clone().unwrap_or_default(),
241            inner.sequence,
242            inner.sig_op_count,
243        )
244    }
245}