casper_rust_wasm_sdk/sdk/rpcs/
speculative_exec_deploy.rs

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