casper_rust_wasm_sdk/sdk/rpcs/
speculative_exec.rs1#[cfg(target_arch = "wasm32")]
2use crate::types::hash::block_hash::BlockHash;
3use crate::types::transaction::Transaction;
4use crate::{
5 types::{sdk_error::SdkError, verbosity::Verbosity},
6 SDK,
7};
8use casper_client::{
9 rpcs::results::SpeculativeExecTxnResult as _SpeculativeExecTxnResult,
10 speculative_exec_txn as speculative_exec_lib, JsonRpcId, SuccessResponse,
11};
12#[cfg(target_arch = "wasm32")]
13use gloo_utils::format::JsValueSerdeExt;
14use rand::Rng;
15#[cfg(target_arch = "wasm32")]
16use serde::{Deserialize, Serialize};
17#[cfg(target_arch = "wasm32")]
18use wasm_bindgen::prelude::*;
19
20#[cfg(target_arch = "wasm32")]
22#[derive(Debug, Deserialize, Clone, Serialize)]
23#[wasm_bindgen]
24pub struct SpeculativeExecTxnResult(_SpeculativeExecTxnResult);
25
26#[cfg(target_arch = "wasm32")]
27impl From<SpeculativeExecTxnResult> for _SpeculativeExecTxnResult {
28 fn from(result: SpeculativeExecTxnResult) -> Self {
29 result.0
30 }
31}
32
33#[cfg(target_arch = "wasm32")]
34impl From<_SpeculativeExecTxnResult> for SpeculativeExecTxnResult {
35 fn from(result: _SpeculativeExecTxnResult) -> Self {
36 SpeculativeExecTxnResult(result)
37 }
38}
39
40#[cfg(target_arch = "wasm32")]
41#[wasm_bindgen]
42impl SpeculativeExecTxnResult {
43 #[wasm_bindgen(getter)]
45 pub fn api_version(&self) -> JsValue {
46 JsValue::from_serde(&self.0.api_version).unwrap()
47 }
48
49 #[wasm_bindgen(getter)]
51 pub fn block_hash(&self) -> BlockHash {
52 self.0.execution_result.block_hash.into()
53 }
54
55 #[wasm_bindgen(getter)]
57 pub fn execution_result(&self) -> JsValue {
58 JsValue::from_serde(&self.0.execution_result).unwrap()
59 }
60
61 #[wasm_bindgen(js_name = "toJson")]
63 pub fn to_json(&self) -> JsValue {
64 JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
65 }
66}
67
68#[derive(Debug, Deserialize, Clone, Default, Serialize)]
70#[cfg(target_arch = "wasm32")]
71#[wasm_bindgen(js_name = "getSpeculativeExecTxnOptions", getter_with_clone)]
72pub struct GetSpeculativeExecTxnOptions {
73 pub transaction_as_string: Option<String>,
75
76 pub transaction: Option<Transaction>,
78
79 pub rpc_address: Option<String>,
81
82 pub verbosity: Option<Verbosity>,
84}
85
86#[cfg(target_arch = "wasm32")]
87#[wasm_bindgen]
88impl SDK {
89 pub fn get_speculative_exec_options(
91 &self,
92 options: JsValue,
93 ) -> Result<GetSpeculativeExecTxnOptions, JsError> {
94 options
95 .into_serde::<GetSpeculativeExecTxnOptions>()
96 .map_err(|err| JsError::new(&format!("Error deserializing options: {:?}", err)))
97 }
98
99 #[wasm_bindgen(js_name = "speculative_exec")]
109 pub async fn speculative_exec_js_alias(
110 &self,
111 options: Option<GetSpeculativeExecTxnOptions>,
112 ) -> Result<SpeculativeExecTxnResult, JsError> {
113 let GetSpeculativeExecTxnOptions {
114 transaction_as_string,
115 transaction,
116 verbosity,
117 rpc_address,
118 } = options.unwrap_or_default();
119
120 let transaction = if let Some(transaction_as_string) = transaction_as_string {
121 Transaction::new(transaction_as_string.into())
122 } else if let Some(transaction) = transaction {
123 transaction
124 } else {
125 let err = "Error: Missing transaction as json or transaction".to_string();
126 return Err(JsError::new(&err));
127 };
128
129 let result = self
130 .speculative_exec(transaction, verbosity, rpc_address)
131 .await;
132 match result {
133 Ok(data) => Ok(data.result.into()),
134 Err(err) => {
135 let err = &format!("Error occurred with {:?}", err);
136 Err(JsError::new(err))
137 }
138 }
139 }
140}
141
142impl SDK {
143 pub async fn speculative_exec(
155 &self,
156 transaction: Transaction,
157 verbosity: Option<Verbosity>,
158 rpc_address: Option<String>,
159 ) -> Result<SuccessResponse<_SpeculativeExecTxnResult>, SdkError> {
160 speculative_exec_lib(
163 JsonRpcId::from(rand::thread_rng().gen::<u64>().to_string()),
164 &self.get_rpc_address(rpc_address),
165 self.get_verbosity(verbosity).into(),
166 transaction.into(),
167 )
168 .await
169 .map_err(SdkError::from)
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use crate::{
177 helpers::public_key_from_secret_key,
178 types::transaction_params::transaction_str_params::TransactionStrParams,
179 };
180 use sdk_tests::{
181 config::TRANSFER_AMOUNT,
182 tests::helpers::{get_network_constants, get_user_secret_key},
183 };
184 use tokio;
185
186 fn get_transaction() -> Transaction {
187 let secret_key = get_user_secret_key(None).unwrap();
188 let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
189 let (_, _, _, _, chain_name) = get_network_constants();
190
191 let transaction_params = TransactionStrParams::default();
192 transaction_params.set_secret_key(&secret_key);
193 transaction_params.set_chain_name(&chain_name);
194 transaction_params.set_payment_amount(TRANSFER_AMOUNT);
195
196 Transaction::new_transfer(
197 None,
198 &initiator_addr, TRANSFER_AMOUNT,
200 transaction_params,
201 None,
202 )
203 .unwrap()
204 }
205
206 #[tokio::test]
207 async fn test_speculative_exec_with_none_values() {
208 let sdk = SDK::new(None, None, None);
210 let transaction = get_transaction();
211 let error_message = "failed to parse node address as valid URL";
212
213 let result = sdk.speculative_exec(transaction, None, None).await;
215
216 assert!(result.is_err());
218 let err_string = result.err().unwrap().to_string();
219 assert!(err_string.contains(error_message));
220 }
221
222 #[tokio::test]
223 #[ignore]
224 async fn _test_speculative_exec() {
225 let sdk = SDK::new(None, None, None);
227 let verbosity = Some(Verbosity::High);
228 let (_, _, default_speculative_address, _, _) = get_network_constants();
229 let transaction = get_transaction();
230
231 let result = sdk
233 .speculative_exec(transaction, verbosity, Some(default_speculative_address))
234 .await;
235
236 assert!(result.is_ok());
239 }
240
241 #[tokio::test]
242 async fn test_speculative_exec_with_error() {
243 let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
245 let transaction = get_transaction();
246 let error_message = "error sending request for url (http://localhost/rpc)";
247
248 let result = sdk.speculative_exec(transaction, None, None).await;
250
251 assert!(result.is_err());
253 let err_string = result.err().unwrap().to_string();
254 assert!(err_string.contains(error_message));
255 }
256}