Skip to main content

casper_rust_wasm_sdk/sdk/transaction/
speculative_transaction.rs

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