casper_rust_wasm_sdk/sdk/rpcs/
get_state_root_hash.rs1#[cfg(all(feature = "js", target_arch = "wasm32"))]
2use crate::types::digest::Digest;
3#[cfg(all(feature = "js", target_arch = "wasm32"))]
4use crate::types::identifier::block_identifier::BlockIdentifier;
5use crate::{
6 types::{
7 identifier::block_identifier::BlockIdentifierInput, sdk_error::SdkError,
8 verbosity::Verbosity,
9 },
10 SDK,
11};
12use casper_client::{
13 cli::get_state_root_hash as get_state_root_hash_cli,
14 get_state_root_hash as get_state_root_hash_lib,
15 rpcs::results::GetStateRootHashResult as _GetStateRootHashResult, JsonRpcId, SuccessResponse,
16};
17#[cfg(all(feature = "js", target_arch = "wasm32"))]
18use gloo_utils::format::JsValueSerdeExt;
19use rand::RngExt;
20#[cfg(all(feature = "js", target_arch = "wasm32"))]
21use serde::{Deserialize, Serialize};
22#[cfg(all(feature = "js", target_arch = "wasm32"))]
23use wasm_bindgen::prelude::*;
24
25#[cfg(all(feature = "js", target_arch = "wasm32"))]
27#[derive(Debug, Deserialize, Clone, Serialize)]
28#[cfg_attr(feature = "js", wasm_bindgen)]
29pub struct GetStateRootHashResult(_GetStateRootHashResult);
30
31#[cfg(all(feature = "js", target_arch = "wasm32"))]
32impl From<GetStateRootHashResult> for _GetStateRootHashResult {
33 fn from(result: GetStateRootHashResult) -> Self {
34 result.0
35 }
36}
37
38#[cfg(all(feature = "js", target_arch = "wasm32"))]
39impl From<_GetStateRootHashResult> for GetStateRootHashResult {
40 fn from(result: _GetStateRootHashResult) -> Self {
41 GetStateRootHashResult(result)
42 }
43}
44
45#[cfg(all(feature = "js", target_arch = "wasm32"))]
46#[cfg_attr(feature = "js", wasm_bindgen)]
47impl GetStateRootHashResult {
48 #[cfg_attr(feature = "js", wasm_bindgen(getter))]
50 #[cfg(feature = "js")]
51 pub fn api_version(&self) -> JsValue {
52 JsValue::from_serde(&self.0.api_version).unwrap()
53 }
54
55 #[cfg_attr(feature = "js", wasm_bindgen(getter))]
57 pub fn state_root_hash(&self) -> Option<Digest> {
58 self.0.state_root_hash.map(Into::into)
59 }
60
61 #[cfg_attr(feature = "js", wasm_bindgen(getter))]
63 pub fn state_root_hash_as_string(&self) -> String {
64 self.0
65 .state_root_hash
66 .map(Into::<Digest>::into)
67 .map(|digest| digest.to_string())
68 .unwrap_or_default()
69 }
70
71 #[cfg_attr(feature = "js", wasm_bindgen(js_name = "toString"))]
73 pub fn to_string_js_alias(&self) -> String {
74 self.state_root_hash_as_string()
76 }
77
78 #[cfg_attr(feature = "js", wasm_bindgen(js_name = "toJson"))]
80 #[cfg(feature = "js")]
81 pub fn to_json(&self) -> JsValue {
82 JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
83 }
84}
85
86#[derive(Debug, Deserialize, Clone, Default, Serialize)]
88#[cfg(all(feature = "js", target_arch = "wasm32"))]
89#[cfg_attr(
90 feature = "js",
91 wasm_bindgen(js_name = "getStateRootHashOptions", getter_with_clone)
92)]
93pub struct GetStateRootHashOptions {
94 pub maybe_block_id_as_string: Option<String>,
95 pub maybe_block_identifier: Option<BlockIdentifier>,
96 pub rpc_address: Option<String>,
97 pub verbosity: Option<Verbosity>,
98}
99
100#[cfg(all(feature = "js", target_arch = "wasm32"))]
101#[cfg_attr(feature = "js", wasm_bindgen)]
102impl SDK {
103 #[cfg(feature = "js")]
113 pub fn get_state_root_hash_options(
114 &self,
115 options: JsValue,
116 ) -> Result<GetStateRootHashOptions, JsError> {
117 options
118 .into_serde::<GetStateRootHashOptions>()
119 .map_err(|err| JsError::new(&format!("Error deserializing options: {err:?}")))
120 }
121
122 #[cfg_attr(feature = "js", wasm_bindgen(js_name = "get_state_root_hash"))]
136 #[cfg(feature = "js")]
137 pub async fn get_state_root_hash_js_alias(
138 &self,
139 options: Option<GetStateRootHashOptions>,
140 ) -> Result<GetStateRootHashResult, JsError> {
141 let GetStateRootHashOptions {
142 maybe_block_id_as_string,
143 maybe_block_identifier,
144 verbosity,
145 rpc_address,
146 } = options.unwrap_or_default();
147
148 let maybe_block_identifier = if let Some(maybe_block_identifier) = maybe_block_identifier {
149 Some(BlockIdentifierInput::BlockIdentifier(
150 maybe_block_identifier,
151 ))
152 } else {
153 maybe_block_id_as_string.map(BlockIdentifierInput::String)
154 };
155
156 let result = self
157 .get_state_root_hash(maybe_block_identifier, verbosity, rpc_address)
158 .await;
159 match result {
160 Ok(data) => Ok(data.result.into()),
161 Err(err) => {
162 let err = &format!("Error occurred with {err:?}");
163 Err(JsError::new(err))
164 }
165 }
166 }
167
168 #[deprecated(note = "This function is an alias. Please use `get_state_root_hash` instead.")]
182 #[allow(deprecated)]
183 #[cfg(feature = "js")]
184 pub async fn chain_get_state_root_hash(
185 &self,
186 options: Option<GetStateRootHashOptions>,
187 ) -> Result<GetStateRootHashResult, JsError> {
188 self.get_state_root_hash_js_alias(options).await
189 }
190}
191
192impl SDK {
193 pub async fn get_state_root_hash(
209 &self,
210 maybe_block_identifier: Option<BlockIdentifierInput>,
211 verbosity: Option<Verbosity>,
212 rpc_address: Option<String>,
213 ) -> Result<SuccessResponse<_GetStateRootHashResult>, SdkError> {
214 let random_id = rand::rng().random::<u64>().to_string();
216
217 if let Some(BlockIdentifierInput::String(maybe_block_id)) = maybe_block_identifier {
218 get_state_root_hash_cli(
219 &random_id,
220 &self.get_rpc_address(rpc_address),
221 self.get_verbosity(verbosity).into(),
222 &maybe_block_id,
223 )
224 .await
225 .map_err(SdkError::from)
226 } else {
227 let maybe_block_identifier =
228 if let Some(BlockIdentifierInput::BlockIdentifier(maybe_block_identifier)) =
229 maybe_block_identifier
230 {
231 Some(maybe_block_identifier)
232 } else {
233 None
234 };
235
236 get_state_root_hash_lib(
237 JsonRpcId::from(random_id),
238 &self.get_rpc_address(rpc_address),
239 self.get_verbosity(verbosity).into(),
240 maybe_block_identifier.map(Into::into),
241 )
242 .await
243 .map_err(SdkError::from)
244 }
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251 use crate::types::{
252 hash::block_hash::BlockHash, identifier::block_identifier::BlockIdentifier,
253 };
254 use sdk_tests::tests::helpers::get_network_constants;
255
256 #[tokio::test]
257 async fn test_get_state_root_hash_with_none_values() {
258 let sdk = SDK::new(None, None, None);
260 let error_message = "failed to parse node address as valid URL";
261
262 let result = sdk.get_state_root_hash(None, None, None).await;
264
265 assert!(result.is_err());
267 let err_string = result.err().unwrap().to_string();
268 assert!(err_string.contains(error_message));
269 }
270
271 #[tokio::test]
272 async fn test_get_state_root_hash_with_block_id_string() {
273 let sdk = SDK::new(None, None, None);
275 let verbosity = Some(Verbosity::High);
276 let (rpc_address, _, _, _, _) = get_network_constants();
277 let result = sdk
278 .get_block(None, verbosity, Some(rpc_address.clone()))
279 .await;
280 let block_hash = BlockHash::from(
281 *result
282 .unwrap()
283 .result
284 .block_with_signatures
285 .unwrap()
286 .block
287 .hash(),
288 )
289 .to_string();
290 let block_identifier = BlockIdentifierInput::String(block_hash.to_string());
291
292 let result = sdk
294 .get_state_root_hash(Some(block_identifier), verbosity, Some(rpc_address))
295 .await;
296 assert!(result.is_ok());
298 }
299
300 #[tokio::test]
301 async fn test_get_state_root_hash_with_block_identifier() {
302 let sdk = SDK::new(None, None, None);
304 let block_identifier =
305 BlockIdentifierInput::BlockIdentifier(BlockIdentifier::from_height(1));
306 let verbosity = Some(Verbosity::High);
307 let (rpc_address, _, _, _, _) = get_network_constants();
308
309 let result = sdk
311 .get_state_root_hash(Some(block_identifier), verbosity, Some(rpc_address.clone()))
312 .await;
313
314 assert!(result.is_ok());
316 }
317
318 #[tokio::test]
319 async fn test_get_state_root_hash_with_error() {
320 let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
321
322 let error_message = "error sending request";
323
324 let result = sdk.get_state_root_hash(None, None, None).await;
326
327 assert!(result.is_err());
329 let err_string = result.err().unwrap().to_string();
330 assert!(err_string.contains(error_message));
331 }
332}