casper_rust_wasm_sdk/sdk/rpcs/
speculative_exec.rs1#[cfg(all(feature = "js", 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(all(feature = "js", target_arch = "wasm32"))]
13use gloo_utils::format::JsValueSerdeExt;
14use rand::RngExt;
15#[cfg(all(feature = "js", target_arch = "wasm32"))]
16use serde::{Deserialize, Serialize};
17#[cfg(all(feature = "js", target_arch = "wasm32"))]
18use wasm_bindgen::prelude::*;
19
20#[cfg(all(feature = "js", target_arch = "wasm32"))]
22#[derive(Debug, Deserialize, Clone, Serialize)]
23#[cfg_attr(feature = "js", wasm_bindgen)]
24pub struct SpeculativeExecTxnResult(_SpeculativeExecTxnResult);
25
26#[cfg(all(feature = "js", target_arch = "wasm32"))]
27impl From<SpeculativeExecTxnResult> for _SpeculativeExecTxnResult {
28 fn from(result: SpeculativeExecTxnResult) -> Self {
29 result.0
30 }
31}
32
33#[cfg(all(feature = "js", target_arch = "wasm32"))]
34impl From<_SpeculativeExecTxnResult> for SpeculativeExecTxnResult {
35 fn from(result: _SpeculativeExecTxnResult) -> Self {
36 SpeculativeExecTxnResult(result)
37 }
38}
39
40#[cfg(all(feature = "js", target_arch = "wasm32"))]
41#[cfg_attr(feature = "js", wasm_bindgen)]
42impl SpeculativeExecTxnResult {
43 #[cfg_attr(feature = "js", wasm_bindgen(getter))]
45 #[cfg(feature = "js")]
46 pub fn api_version(&self) -> JsValue {
47 JsValue::from_serde(&self.0.api_version).unwrap()
48 }
49
50 #[cfg_attr(feature = "js", wasm_bindgen(getter))]
52 pub fn block_hash(&self) -> BlockHash {
53 self.0.execution_result.block_hash.into()
54 }
55
56 #[cfg_attr(feature = "js", wasm_bindgen(getter))]
58 #[cfg(feature = "js")]
59 pub fn execution_result(&self) -> JsValue {
60 JsValue::from_serde(&self.0.execution_result).unwrap()
61 }
62
63 #[cfg_attr(feature = "js", wasm_bindgen(js_name = "toJson"))]
65 #[cfg(feature = "js")]
66 pub fn to_json(&self) -> JsValue {
67 JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
68 }
69}
70
71#[derive(Debug, Deserialize, Clone, Default, Serialize)]
73#[cfg(all(feature = "js", target_arch = "wasm32"))]
74#[cfg_attr(
75 feature = "js",
76 wasm_bindgen(js_name = "getSpeculativeExecTxnOptions", getter_with_clone)
77)]
78pub struct GetSpeculativeExecTxnOptions {
79 pub transaction_as_string: Option<String>,
81
82 pub transaction: Option<Transaction>,
84
85 pub rpc_address: Option<String>,
87
88 pub verbosity: Option<Verbosity>,
90}
91
92#[cfg(all(feature = "js", target_arch = "wasm32"))]
93#[cfg_attr(feature = "js", wasm_bindgen)]
94impl SDK {
95 #[cfg(feature = "js")]
97 pub fn get_speculative_exec_options(
98 &self,
99 options: JsValue,
100 ) -> Result<GetSpeculativeExecTxnOptions, JsError> {
101 options
102 .into_serde::<GetSpeculativeExecTxnOptions>()
103 .map_err(|err| JsError::new(&format!("Error deserializing options: {err:?}")))
104 }
105
106 #[cfg_attr(feature = "js", wasm_bindgen(js_name = "speculative_exec"))]
116 #[cfg(feature = "js")]
117 pub async fn speculative_exec_js_alias(
118 &self,
119 options: Option<GetSpeculativeExecTxnOptions>,
120 ) -> Result<SpeculativeExecTxnResult, JsError> {
121 let GetSpeculativeExecTxnOptions {
122 transaction_as_string,
123 transaction,
124 verbosity,
125 rpc_address,
126 } = options.unwrap_or_default();
127
128 let transaction = if let Some(transaction_as_string) = transaction_as_string {
129 Transaction::new(transaction_as_string.into())
130 } else if let Some(transaction) = transaction {
131 transaction
132 } else {
133 let err = "Error: Missing transaction as json or transaction".to_string();
134 return Err(JsError::new(&err));
135 };
136
137 let result = self
138 .speculative_exec(transaction, verbosity, rpc_address)
139 .await;
140 match result {
141 Ok(data) => Ok(data.result.into()),
142 Err(err) => {
143 let err = &format!("Error occurred with {err:?}");
144 Err(JsError::new(err))
145 }
146 }
147 }
148}
149
150impl SDK {
151 pub async fn speculative_exec(
163 &self,
164 transaction: Transaction,
165 verbosity: Option<Verbosity>,
166 rpc_address: Option<String>,
167 ) -> Result<SuccessResponse<_SpeculativeExecTxnResult>, SdkError> {
168 let random_id = JsonRpcId::from(rand::rng().random::<u64>().to_string());
170 speculative_exec_lib(
171 random_id,
172 &self.get_rpc_address(rpc_address),
173 self.get_verbosity(verbosity).into(),
174 transaction.into(),
175 )
176 .await
177 .map_err(SdkError::from)
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use crate::{
185 helpers::public_key_from_secret_key,
186 types::transaction_params::transaction_str_params::TransactionStrParams,
187 };
188 use sdk_tests::{
189 config::TRANSFER_AMOUNT,
190 tests::helpers::{get_network_constants, get_user_secret_key},
191 };
192 use tokio;
193
194 fn get_transaction() -> Transaction {
195 let secret_key = get_user_secret_key(None).unwrap();
196 let initiator_addr = public_key_from_secret_key(&secret_key).unwrap();
197 let (_, _, _, _, chain_name) = get_network_constants();
198
199 let transaction_params = TransactionStrParams::default();
200 transaction_params.set_secret_key(&secret_key);
201 transaction_params.set_chain_name(&chain_name);
202 transaction_params.set_payment_amount(TRANSFER_AMOUNT);
203
204 Transaction::new_transfer(
205 None,
206 &initiator_addr, TRANSFER_AMOUNT,
208 transaction_params,
209 None,
210 )
211 .unwrap()
212 }
213
214 #[tokio::test]
215 async fn test_speculative_exec_with_none_values() {
216 let sdk = SDK::new(None, None, None);
218 let transaction = get_transaction();
219 let error_message = "failed to parse node address as valid URL";
220
221 let result = sdk.speculative_exec(transaction, None, None).await;
223
224 assert!(result.is_err());
226 let err_string = result.err().unwrap().to_string();
227 assert!(err_string.contains(error_message));
228 }
229
230 #[tokio::test]
231 #[ignore]
232 async fn _test_speculative_exec() {
233 let sdk = SDK::new(None, None, None);
235 let verbosity = Some(Verbosity::High);
236 let (_, _, default_speculative_address, _, _) = get_network_constants();
237 let transaction = get_transaction();
238
239 let result = sdk
241 .speculative_exec(transaction, verbosity, Some(default_speculative_address))
242 .await;
243
244 assert!(result.is_ok());
247 }
248
249 #[tokio::test]
250 async fn test_speculative_exec_with_error() {
251 let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
253 let transaction = get_transaction();
254 let error_message = "error sending request";
255
256 let result = sdk.speculative_exec(transaction, None, None).await;
258
259 assert!(result.is_err());
261 let err_string = result.err().unwrap().to_string();
262 assert!(err_string.contains(error_message));
263 }
264}