casper_rust_wasm_sdk/sdk/transaction/
speculative_transaction.rs

1#[cfg(target_arch = "wasm32")]
2use crate::rpcs::speculative_exec::SpeculativeExecTxnResult;
3use crate::{
4    types::{
5        sdk_error::SdkError,
6        transaction_params::{
7            transaction_builder_params::{
8                transaction_builder_params_to_casper_client, TransactionBuilderParams,
9            },
10            transaction_str_params::{
11                transaction_str_params_to_casper_client, TransactionStrParams,
12            },
13        },
14        verbosity::Verbosity,
15    },
16    SDK,
17};
18use casper_client::{
19    cli::make_transaction, rpcs::results::SpeculativeExecTxnResult as _SpeculativeExecTxnResult,
20    SuccessResponse,
21};
22#[cfg(target_arch = "wasm32")]
23use wasm_bindgen::prelude::*;
24
25#[cfg(target_arch = "wasm32")]
26#[wasm_bindgen]
27impl SDK {
28    /// This function allows executing a transaction speculatively.
29    ///
30    /// # Arguments
31    ///
32    /// * `builder_params` - Transaction Builder parameters.
33    /// * `transaction_params` - Transactionment parameters for the transaction.
34    /// * `verbosity` - Optional verbosity level.
35    /// * `rpc_address` - Optional rpc address.
36    ///
37    /// # Returns
38    ///
39    /// A `Result` containing either a `SpeculativeExecTxnResult` or a `JsError` in case of an error.
40    #[wasm_bindgen(js_name = "speculative_transaction")]
41    #[allow(clippy::too_many_arguments)]
42    pub async fn speculative_transaction_js_alias(
43        &self,
44        builder_params: TransactionBuilderParams,
45        transaction_params: TransactionStrParams,
46        verbosity: Option<Verbosity>,
47        rpc_address: Option<String>,
48    ) -> Result<SpeculativeExecTxnResult, JsError> {
49        let result = self
50            .speculative_transaction(builder_params, transaction_params, verbosity, rpc_address)
51            .await;
52        match result {
53            Ok(data) => Ok(data.result.into()),
54            Err(err) => {
55                let err = &format!("Error occurred with {:?}", err);
56                Err(JsError::new(err))
57            }
58        }
59    }
60}
61
62impl SDK {
63    /// This function allows executing a transaction speculatively.
64    ///
65    /// # Arguments
66    ///
67    /// * `builder_params` - Transaction Builder parameters.
68    /// * `transaction_params` - Transactionment parameters for the transaction.
69    /// * `verbosity` - Optional verbosity level.
70    /// * `rpc_address` - Optional rpc address.
71    ///
72    /// # Returns
73    ///
74    /// A `Result` containing either a `SuccessResponse<_SpeculativeExecTxnResult>` or a `SdkError` in case of an error.
75    pub async fn speculative_transaction(
76        &self,
77        builder_params: TransactionBuilderParams,
78        transaction_params: TransactionStrParams,
79        verbosity: Option<Verbosity>,
80        rpc_address: Option<String>,
81    ) -> Result<SuccessResponse<_SpeculativeExecTxnResult>, SdkError> {
82        // log("speculative_transaction!");
83        let transaction = make_transaction(
84            transaction_builder_params_to_casper_client(&builder_params),
85            transaction_str_params_to_casper_client(&transaction_params),
86            false,
87        );
88
89        if let Err(err) = transaction {
90            return Err(SdkError::from(err));
91        }
92
93        self.speculative_exec(transaction.unwrap().into(), verbosity, rpc_address)
94            .await
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101    use crate::helpers::public_key_from_secret_key;
102    use once_cell::sync::Lazy;
103    use sdk_tests::{
104        config::{ARGS_SIMPLE, HELLO_CONTRACT, PAYMENT_AMOUNT, WASM_PATH},
105        tests::helpers::{get_network_constants, get_user_secret_key, read_wasm_file},
106    };
107    use std::sync::Mutex;
108
109    static ARGS: Lazy<Vec<String>> =
110        Lazy::new(|| ARGS_SIMPLE.iter().map(|s| s.to_string()).collect());
111
112    static BUILDER_PARAMS: Lazy<Mutex<Option<TransactionBuilderParams>>> =
113        Lazy::new(|| Mutex::new(None));
114
115    fn get_builder_params() -> TransactionBuilderParams {
116        let mut builder_params = BUILDER_PARAMS.lock().unwrap();
117
118        if builder_params.is_none() {
119            let file_path = &format!("{WASM_PATH}{HELLO_CONTRACT}");
120            let transaction_bytes = match read_wasm_file(file_path) {
121                Ok(transaction_bytes) => transaction_bytes,
122                Err(err) => {
123                    eprintln!("Error reading file: {:?}", err);
124                    unimplemented!()
125                }
126            };
127
128            let is_install_upgrade = Some(true);
129
130            let new_builder_params = TransactionBuilderParams::new_session(
131                Some(transaction_bytes.into()),
132                is_install_upgrade,
133            );
134            *builder_params = Some(new_builder_params);
135        }
136
137        builder_params.clone().unwrap()
138    }
139
140    #[tokio::test]
141    #[ignore]
142    async fn _test_speculative_transaction_with_valid_params() {
143        // Arrange
144        let sdk = SDK::new(None, None, None);
145        let verbosity = Some(Verbosity::High);
146        let (_, _, default_speculative_address, _, chain_name) = get_network_constants();
147
148        let secret_key = get_user_secret_key(None).unwrap();
149
150        let mut transaction_params = TransactionStrParams::default();
151        transaction_params.set_secret_key(&secret_key);
152        transaction_params.set_chain_name(&chain_name);
153        transaction_params.set_payment_amount(PAYMENT_AMOUNT);
154        transaction_params.set_session_args_simple(ARGS.to_vec());
155
156        // Act
157        let result = sdk
158            .speculative_transaction(
159                get_builder_params().clone(),
160                transaction_params,
161                verbosity,
162                Some(default_speculative_address),
163            )
164            .await;
165
166        // Assert
167        assert!(result.is_ok());
168    }
169
170    #[tokio::test]
171    async fn test_speculative_transaction_with_valid_params_without_secret_key() {
172        // Arrange
173        let sdk = SDK::new(None, None, None);
174        let verbosity = Some(Verbosity::High);
175        let (_, _, default_speculative_address, _, chain_name) = get_network_constants();
176        let secret_key = get_user_secret_key(None).unwrap();
177        let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
178
179        let mut transaction_params = TransactionStrParams::default();
180        transaction_params.set_chain_name(&chain_name);
181        transaction_params.set_initiator_addr(&initiator_addr);
182        transaction_params.set_payment_amount(PAYMENT_AMOUNT);
183        transaction_params.set_session_args_simple(ARGS.to_vec());
184
185        // Act
186        let result = sdk
187            .speculative_transaction(
188                get_builder_params().clone(),
189                transaction_params,
190                verbosity,
191                Some(default_speculative_address),
192            )
193            .await;
194
195        // Assert
196        assert!(result.is_err());
197    }
198
199    #[tokio::test]
200    async fn test_speculative_transaction_with_invalid_params() {
201        // Arrange
202        let sdk = SDK::new(None, None, None);
203        let verbosity = Some(Verbosity::High);
204        let (_, _, default_speculative_address, _, chain_name) = get_network_constants();
205
206        let secret_key = get_user_secret_key(None).unwrap();
207
208        let error_message = "Node request failure";
209
210        let transaction_params = TransactionStrParams::default();
211        transaction_params.set_secret_key(&secret_key);
212        transaction_params.set_chain_name(&chain_name);
213        transaction_params.set_payment_amount(PAYMENT_AMOUNT);
214
215        // Act
216        let result = sdk
217            .speculative_transaction(
218                get_builder_params().clone(),
219                transaction_params,
220                verbosity,
221                Some(default_speculative_address),
222            )
223            .await;
224
225        // Assert
226        assert!(result.is_err());
227        let err_string = result.err().unwrap().to_string();
228
229        assert!(err_string.contains(error_message));
230    }
231}