Skip to main content

casper_rust_wasm_sdk/sdk/rpcs/
speculative_exec_deploy.rs

1use crate::types::deploy::Deploy;
2#[cfg(all(feature = "js", target_arch = "wasm32"))]
3use crate::types::hash::block_hash::BlockHash;
4use crate::{
5    types::{sdk_error::SdkError, verbosity::Verbosity},
6    SDK,
7};
8#[allow(deprecated)]
9use casper_client::{
10    rpcs::results::SpeculativeExecResult as _SpeculativeExecResult,
11    speculative_exec as speculative_exec_deploy_lib, JsonRpcId, SuccessResponse,
12};
13#[cfg(all(feature = "js", target_arch = "wasm32"))]
14use gloo_utils::format::JsValueSerdeExt;
15use rand::RngExt;
16#[cfg(all(feature = "js", target_arch = "wasm32"))]
17use serde::{Deserialize, Serialize};
18#[cfg(all(feature = "js", target_arch = "wasm32"))]
19use wasm_bindgen::prelude::*;
20
21// Define a struct to wrap the result of a speculative execution.
22#[cfg(all(feature = "js", target_arch = "wasm32"))]
23#[derive(Debug, Deserialize, Clone, Serialize)]
24#[cfg_attr(feature = "js", wasm_bindgen)]
25pub struct SpeculativeExecResult(_SpeculativeExecResult);
26
27#[cfg(all(feature = "js", target_arch = "wasm32"))]
28impl From<SpeculativeExecResult> for _SpeculativeExecResult {
29    fn from(result: SpeculativeExecResult) -> Self {
30        result.0
31    }
32}
33
34#[cfg(all(feature = "js", target_arch = "wasm32"))]
35impl From<_SpeculativeExecResult> for SpeculativeExecResult {
36    fn from(result: _SpeculativeExecResult) -> Self {
37        SpeculativeExecResult(result)
38    }
39}
40
41#[cfg(all(feature = "js", target_arch = "wasm32"))]
42#[cfg_attr(feature = "js", wasm_bindgen)]
43impl SpeculativeExecResult {
44    /// Get the API version of the result.
45    #[cfg_attr(feature = "js", wasm_bindgen(getter))]
46    #[cfg(feature = "js")]
47    pub fn api_version(&self) -> JsValue {
48        JsValue::from_serde(&self.0.api_version).unwrap()
49    }
50
51    /// Get the block hash.
52    #[cfg_attr(feature = "js", wasm_bindgen(getter))]
53    pub fn block_hash(&self) -> BlockHash {
54        self.0.execution_result.block_hash.into()
55    }
56
57    /// Get the execution result.
58    #[cfg_attr(feature = "js", wasm_bindgen(getter))]
59    #[cfg(feature = "js")]
60    pub fn execution_result(&self) -> JsValue {
61        JsValue::from_serde(&self.0.execution_result).unwrap()
62    }
63
64    /// Convert the result to JSON format.
65    #[cfg_attr(feature = "js", wasm_bindgen(js_name = "toJson"))]
66    #[cfg(feature = "js")]
67    pub fn to_json(&self) -> JsValue {
68        JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
69    }
70}
71
72/// Options for speculative execution.
73#[derive(Debug, Deserialize, Clone, Default, Serialize)]
74#[cfg(all(feature = "js", target_arch = "wasm32"))]
75#[cfg_attr(
76    feature = "js",
77    wasm_bindgen(js_name = "getSpeculativeExecDeployOptions", getter_with_clone)
78)]
79pub struct GetSpeculativeExecDeployOptions {
80    /// The deploy as a JSON string.
81    pub deploy_as_string: Option<String>,
82
83    /// The deploy to execute.
84    pub deploy: Option<Deploy>,
85
86    /// The rpc address.
87    pub rpc_address: Option<String>,
88
89    /// The verbosity level for logging.
90    pub verbosity: Option<Verbosity>,
91}
92
93#[cfg(all(feature = "js", target_arch = "wasm32"))]
94#[cfg_attr(feature = "js", wasm_bindgen)]
95impl SDK {
96    /// Get options for speculative execution from a JavaScript value.
97    #[deprecated(note = "prefer speculative_exec_transaction_options")]
98    #[allow(deprecated)]
99    #[cfg(feature = "js")]
100    pub fn get_speculative_exec_deploy_options(
101        &self,
102        options: JsValue,
103    ) -> Result<GetSpeculativeExecDeployOptions, JsError> {
104        options
105            .into_serde::<GetSpeculativeExecDeployOptions>()
106            .map_err(|err| JsError::new(&format!("Error deserializing options: {err:?}")))
107    }
108
109    /// JS function for speculative execution.
110    ///
111    /// # Arguments
112    ///
113    /// * `options` - The options for speculative execution.
114    ///
115    /// # Returns
116    ///
117    /// A `Result` containing the result of the speculative execution or a `JsError` in case of an error.
118    #[deprecated(note = "prefer speculative_exec_transaction")]
119    #[allow(deprecated)]
120    #[cfg_attr(feature = "js", wasm_bindgen(js_name = "speculative_exec_deploy"))]
121    #[cfg(feature = "js")]
122    pub async fn speculative_exec_deploy_js_alias(
123        &self,
124        options: Option<GetSpeculativeExecDeployOptions>,
125    ) -> Result<SpeculativeExecResult, JsError> {
126        let GetSpeculativeExecDeployOptions {
127            deploy_as_string,
128            deploy,
129            verbosity,
130            rpc_address,
131        } = options.unwrap_or_default();
132
133        let deploy = if let Some(deploy_as_string) = deploy_as_string {
134            Deploy::new(deploy_as_string.into())
135        } else if let Some(deploy) = deploy {
136            deploy
137        } else {
138            let err = "Error: Missing deploy as json or deploy".to_string();
139            return Err(JsError::new(&err));
140        };
141
142        let result = self
143            .speculative_exec_deploy(deploy, verbosity, rpc_address)
144            .await;
145        match result {
146            Ok(data) => Ok(data.result.into()),
147            Err(err) => {
148                let err = &format!("Error occurred with {err:?}");
149                Err(JsError::new(err))
150            }
151        }
152    }
153}
154
155impl SDK {
156    /// Perform speculative execution.
157    ///
158    /// # Arguments
159    ///
160    /// * `deploy` - The deploy to execute.
161    /// * `verbosity` - The verbosity level for logging.
162    /// * `rpc_address` - The address of the node to connect to.
163    ///
164    /// # Returns
165    ///
166    /// A `Result` containing the result of _SpeculativeExecResult or a `SdkError` in case of an error.
167    #[deprecated(note = "prefer speculative_exec_transaction")]
168    #[allow(deprecated)]
169    pub async fn speculative_exec_deploy(
170        &self,
171        deploy: Deploy,
172        verbosity: Option<Verbosity>,
173        rpc_address: Option<String>,
174    ) -> Result<SuccessResponse<_SpeculativeExecResult>, SdkError> {
175        //log("speculative_exec_deploy!");
176        let random_id = JsonRpcId::from(rand::rng().random::<u64>().to_string());
177        speculative_exec_deploy_lib(
178            random_id,
179            &self.get_rpc_address(rpc_address),
180            self.get_verbosity(verbosity).into(),
181            deploy.into(),
182        )
183        .await
184        .map_err(SdkError::from)
185    }
186}
187
188#[cfg(test)]
189#[allow(deprecated)]
190mod tests {
191    use super::*;
192    use crate::{
193        helpers::public_key_from_secret_key,
194        types::deploy_params::{
195            deploy_str_params::DeployStrParams, payment_str_params::PaymentStrParams,
196        },
197    };
198    use sdk_tests::{
199        config::{PAYMENT_TRANSFER_AMOUNT, TRANSFER_AMOUNT},
200        tests::helpers::{get_network_constants, get_user_secret_key},
201    };
202    use tokio;
203
204    fn get_deploy() -> Deploy {
205        let secret_key = get_user_secret_key(None).unwrap();
206        let account = public_key_from_secret_key(&secret_key).unwrap();
207        let (_, _, _, _, chain_name) = get_network_constants();
208        let deploy_params =
209            DeployStrParams::new(&chain_name, &account, Some(secret_key), None, None, None);
210        let payment_params = PaymentStrParams::default();
211        payment_params.set_payment_amount(PAYMENT_TRANSFER_AMOUNT);
212
213        Deploy::with_transfer(
214            TRANSFER_AMOUNT,
215            &account, // self transfer
216            None,
217            deploy_params,
218            payment_params,
219        )
220        .unwrap()
221    }
222
223    #[tokio::test]
224    async fn test_speculative_exec_deploy_with_none_values() {
225        // Arrange
226        let sdk = SDK::new(None, None, None);
227        let deploy = get_deploy();
228        let error_message = "failed to parse node address as valid URL";
229
230        // Act
231        let result = sdk.speculative_exec_deploy(deploy, None, None).await;
232
233        // Assert
234        assert!(result.is_err());
235        let err_string = result.err().unwrap().to_string();
236        assert!(err_string.contains(error_message));
237    }
238
239    #[tokio::test]
240    #[ignore]
241    async fn _test_speculative_exec_deploy() {
242        // Arrange
243        let sdk = SDK::new(None, None, None);
244        let verbosity = Some(Verbosity::High);
245        let (_, _, default_speculative_address, _, _) = get_network_constants();
246        let deploy = get_deploy();
247        // Act
248        let result = sdk
249            .speculative_exec_deploy(deploy, verbosity, Some(default_speculative_address))
250            .await;
251
252        // Assert
253        assert!(result.is_ok());
254    }
255
256    #[tokio::test]
257    async fn test_speculative_exec_deploy_with_error() {
258        // Arrange
259        let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
260        let deploy = get_deploy();
261        let error_message = "error sending request";
262
263        // Act
264        let result = sdk.speculative_exec_deploy(deploy, None, None).await;
265
266        // Assert
267        assert!(result.is_err());
268        let err_string = result.err().unwrap().to_string();
269        assert!(err_string.contains(error_message));
270    }
271}