casper_rust_wasm_sdk/sdk/rpcs/
get_dictionary_item.rs1use crate::types::digest::Digest;
2use crate::{
3 types::{
4 deploy_params::dictionary_item_str_params::{
5 dictionary_item_str_params_to_casper_client, DictionaryItemStrParams,
6 },
7 digest::ToDigest,
8 identifier::dictionary_item_identifier::DictionaryItemIdentifier,
9 sdk_error::SdkError,
10 verbosity::Verbosity,
11 },
12 SDK,
13};
14use casper_client::{
15 cli::get_dictionary_item as get_dictionary_item_cli,
16 get_dictionary_item as get_dictionary_item_lib,
17 rpcs::results::GetDictionaryItemResult as _GetDictionaryItemResult, JsonRpcId, SuccessResponse,
18};
19#[cfg(target_arch = "wasm32")]
20use gloo_utils::format::JsValueSerdeExt;
21use rand::Rng;
22#[cfg(target_arch = "wasm32")]
23use serde::{Deserialize, Serialize};
24#[cfg(target_arch = "wasm32")]
25use wasm_bindgen::prelude::*;
26
27#[cfg(target_arch = "wasm32")]
29#[derive(Debug, Deserialize, Clone, Serialize)]
30#[wasm_bindgen]
31pub struct GetDictionaryItemResult(_GetDictionaryItemResult);
32
33#[cfg(target_arch = "wasm32")]
34impl From<GetDictionaryItemResult> for _GetDictionaryItemResult {
35 fn from(result: GetDictionaryItemResult) -> Self {
36 result.0
37 }
38}
39#[cfg(target_arch = "wasm32")]
40impl From<_GetDictionaryItemResult> for GetDictionaryItemResult {
41 fn from(result: _GetDictionaryItemResult) -> Self {
42 GetDictionaryItemResult(result)
43 }
44}
45
46#[cfg(target_arch = "wasm32")]
47#[wasm_bindgen]
48impl GetDictionaryItemResult {
49 #[wasm_bindgen(getter)]
51 pub fn api_version(&self) -> JsValue {
52 JsValue::from_serde(&self.0.api_version).unwrap()
53 }
54
55 #[wasm_bindgen(getter)]
57 pub fn dictionary_key(&self) -> String {
58 self.0.dictionary_key.clone()
59 }
60
61 #[wasm_bindgen(getter)]
63 pub fn stored_value(&self) -> JsValue {
64 JsValue::from_serde(&self.0.stored_value).unwrap()
65 }
66
67 #[wasm_bindgen(getter)]
69 pub fn merkle_proof(&self) -> String {
70 self.0.merkle_proof.clone()
71 }
72
73 #[wasm_bindgen(js_name = "toJson")]
75 pub fn to_json(&self) -> JsValue {
76 JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
77 }
78}
79
80#[derive(Default, Debug, Deserialize, Clone, Serialize)]
82#[cfg(target_arch = "wasm32")]
83#[wasm_bindgen(js_name = "getDictionaryItemOptions", getter_with_clone)]
84pub struct GetDictionaryItemOptions {
85 pub state_root_hash_as_string: Option<String>,
86 pub state_root_hash: Option<Digest>,
87 pub dictionary_item_params: Option<DictionaryItemStrParams>,
88 pub dictionary_item_identifier: Option<DictionaryItemIdentifier>,
89 pub rpc_address: Option<String>,
90 pub verbosity: Option<Verbosity>,
91}
92
93#[cfg(target_arch = "wasm32")]
94#[wasm_bindgen]
95impl SDK {
96 pub fn get_dictionary_item_options(
106 &self,
107 options: JsValue,
108 ) -> Result<GetDictionaryItemOptions, JsError> {
109 options
110 .into_serde::<GetDictionaryItemOptions>()
111 .map_err(|err| JsError::new(&format!("Error deserializing options: {:?}", err)))
112 }
113
114 #[wasm_bindgen(js_name = "get_dictionary_item")]
128 pub async fn get_dictionary_item_js_alias(
129 &self,
130 options: Option<GetDictionaryItemOptions>,
131 ) -> Result<GetDictionaryItemResult, JsError> {
132 let GetDictionaryItemOptions {
133 state_root_hash_as_string,
134 state_root_hash,
135 dictionary_item_params,
136 dictionary_item_identifier,
137 verbosity,
138 rpc_address,
139 } = options.unwrap_or_default();
140
141 let dictionary_item = if let Some(identifier) = dictionary_item_identifier {
142 DictionaryItemInput::Identifier(identifier)
143 } else if let Some(params) = dictionary_item_params {
144 DictionaryItemInput::Params(params)
145 } else {
146 let err = "Error: Missing dictionary item identifier or params";
147 return Err(JsError::new(err));
148 };
149
150 let result = if let Some(hash) = state_root_hash {
151 self.get_dictionary_item(dictionary_item, Some(hash), verbosity, rpc_address)
152 .await
153 } else if let Some(hash) = state_root_hash_as_string.clone() {
154 self.get_dictionary_item(dictionary_item, Some(hash.as_str()), verbosity, rpc_address)
155 .await
156 } else {
157 self.get_dictionary_item(dictionary_item, None::<&str>, verbosity, rpc_address)
158 .await
159 };
160
161 match result {
162 Ok(data) => Ok(data.result.into()),
163 Err(err) => {
164 let err = &format!("Error occurred with {:?}", err);
165 Err(JsError::new(err))
166 }
167 }
168 }
169
170 #[deprecated(note = "This function is an alias. Please use `get_dictionary_item` instead.")]
172 #[allow(deprecated)]
173 pub async fn state_get_dictionary_item(
174 &self,
175 options: Option<GetDictionaryItemOptions>,
176 ) -> Result<GetDictionaryItemResult, JsError> {
177 self.get_dictionary_item_js_alias(options).await
178 }
179}
180#[derive(Debug, Clone)]
181pub enum DictionaryItemInput {
182 Identifier(DictionaryItemIdentifier),
183 Params(DictionaryItemStrParams),
184}
185
186impl SDK {
187 pub async fn get_dictionary_item(
204 &self,
205 dictionary_item_input: DictionaryItemInput,
206 state_root_hash: Option<impl ToDigest>,
207 verbosity: Option<Verbosity>,
208 rpc_address: Option<String>,
209 ) -> Result<SuccessResponse<_GetDictionaryItemResult>, SdkError> {
210 let state_root_hash = if let Some(state_root_hash) = state_root_hash {
213 if state_root_hash.is_empty() {
214 let state_root_hash = self
215 .get_state_root_hash(
216 None,
217 None,
218 Some(self.get_rpc_address(rpc_address.clone())),
219 )
220 .await;
221
222 match state_root_hash {
223 Ok(state_root_hash) => {
224 let state_root_hash: Digest =
225 state_root_hash.result.state_root_hash.unwrap().into();
226 state_root_hash
227 }
228 Err(_) => "".to_digest(),
229 }
230 } else {
231 state_root_hash.to_digest()
232 }
233 } else {
234 let state_root_hash = self
235 .get_state_root_hash(None, None, Some(self.get_rpc_address(rpc_address.clone())))
236 .await;
237
238 match state_root_hash {
239 Ok(state_root_hash) => {
240 let state_root_hash: Digest =
241 state_root_hash.result.state_root_hash.unwrap().into();
242 state_root_hash
243 }
244 Err(_) => "".to_digest(),
245 }
246 };
247
248 match dictionary_item_input {
249 DictionaryItemInput::Params(dictionary_item_params) => get_dictionary_item_cli(
250 &rand::thread_rng().gen::<u64>().to_string(),
251 &self.get_rpc_address(rpc_address),
252 self.get_verbosity(verbosity).into(),
253 &state_root_hash.to_string(),
254 dictionary_item_str_params_to_casper_client(&dictionary_item_params),
255 )
256 .await
257 .map_err(SdkError::from),
258 DictionaryItemInput::Identifier(dictionary_item_identifier) => get_dictionary_item_lib(
259 JsonRpcId::from(rand::thread_rng().gen::<u64>().to_string()),
260 &self.get_rpc_address(rpc_address),
261 self.get_verbosity(verbosity).into(),
262 state_root_hash.into(),
263 dictionary_item_identifier.into(),
264 )
265 .await
266 .map_err(SdkError::from),
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274 use crate::get_dictionary_item;
275 use sdk_tests::tests::helpers::get_network_constants;
276
277 #[tokio::test]
278 async fn test_get_dictionary_item_with_none_values() {
279 let sdk = SDK::new(None, None, None);
281 let error_message = "failed to parse node address as valid URL";
282
283 let result = sdk
285 .get_dictionary_item(
286 get_dictionary_item(false).await,
287 Some("7d3dc9c74fe93e83fe6cc7a9830ba223035ad4fd4fd464489640742069ca31ed"), None,
289 None,
290 )
291 .await;
292
293 assert!(result.is_err());
295 let err_string = result.err().unwrap().to_string();
296 assert!(err_string.contains(error_message));
297 }
298
299 #[tokio::test]
300 async fn test_get_dictionary_item_with_state_root_hash() {
301 let sdk = SDK::new(None, None, None);
303 let verbosity = Some(Verbosity::High);
304 let (rpc_address, _, _, _, _) = get_network_constants();
305 let dictionary_item = get_dictionary_item(false).await;
306 let state_root_hash: Digest = sdk
307 .get_state_root_hash(None, verbosity, Some(rpc_address.clone()))
308 .await
309 .unwrap()
310 .result
311 .state_root_hash
312 .unwrap()
313 .into();
314
315 let result = sdk
317 .get_dictionary_item(
318 dictionary_item,
319 Some(state_root_hash),
320 verbosity,
321 Some(rpc_address),
322 )
323 .await;
324
325 assert!(result.is_ok());
327 }
328
329 #[tokio::test]
330 async fn test_get_dictionary_item_with_empty_state_root_hash() {
331 let sdk = SDK::new(None, None, None);
333 let verbosity = Some(Verbosity::High);
334 let (rpc_address, _, _, _, _) = get_network_constants();
335
336 let result = sdk
338 .get_dictionary_item(
339 get_dictionary_item(false).await,
340 None::<&str>,
341 verbosity,
342 Some(rpc_address),
343 )
344 .await;
345
346 assert!(result.is_ok());
348 }
349
350 #[tokio::test]
351 async fn test_get_dictionary_item_with_valid_identifier_input() {
352 let sdk = SDK::new(None, None, None);
354 let verbosity = Some(Verbosity::High);
355 let (rpc_address, _, _, _, _) = get_network_constants();
356
357 let result = sdk
359 .get_dictionary_item(
360 get_dictionary_item(false).await,
361 None::<&str>,
362 verbosity,
363 Some(rpc_address),
364 )
365 .await;
366
367 assert!(result.is_ok());
369 }
370
371 #[tokio::test]
372 async fn test_get_dictionary_item_with_valid_params_input() {
373 let sdk = SDK::new(None, None, None);
375 let verbosity = Some(Verbosity::High);
376 let (rpc_address, _, _, _, _) = get_network_constants();
377
378 let result = sdk
380 .get_dictionary_item(
381 get_dictionary_item(true).await,
382 None::<&str>,
383 verbosity,
384 Some(rpc_address),
385 )
386 .await;
387
388 assert!(result.is_ok());
390 }
391
392 #[tokio::test]
393 async fn test_get_dictionary_item_with_invalid_params_input() {
394 let sdk = SDK::new(None, None, None);
396 let verbosity = Some(Verbosity::High);
397 let (rpc_address, _, _, _, _) = get_network_constants();
398
399 let error_message =
400 "Failed to parse dictionary item address as a key: unknown prefix for key";
401
402 let state_root_hash = "";
403 let params = DictionaryItemStrParams::new();
404
405 let result = sdk
407 .get_dictionary_item(
408 DictionaryItemInput::Params(params),
409 Some(state_root_hash),
410 verbosity,
411 Some(rpc_address),
412 )
413 .await;
414
415 assert!(result.is_err());
417 let err_string = result.err().unwrap().to_string();
418 assert!(err_string.contains(error_message));
419 }
420
421 #[tokio::test]
422 async fn test_get_dictionary_item_with_error() {
423 let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
425 let error_message = "error sending request for url (http://localhost/rpc)";
426
427 let result = sdk
429 .get_dictionary_item(
430 get_dictionary_item(false).await,
431 Some("7d3dc9c74fe93e83fe6cc7a9830ba223035ad4fd4fd464489640742069ca31ed"), None,
433 None,
434 )
435 .await;
436
437 assert!(result.is_err());
439 let err_string = result.err().unwrap().to_string();
440 assert!(err_string.contains(error_message));
441 }
442}