casper_rust_wasm_sdk/sdk/rpcs/
get_block.rs

1#[cfg(target_arch = "wasm32")]
2use crate::types::identifier::block_identifier::BlockIdentifier;
3use crate::{
4    types::{
5        identifier::block_identifier::BlockIdentifierInput, sdk_error::SdkError,
6        verbosity::Verbosity,
7    },
8    SDK,
9};
10use casper_client::{
11    cli::get_block as get_block_cli, get_block as get_block_lib,
12    rpcs::results::GetBlockResult as _GetBlockResult, JsonRpcId, SuccessResponse,
13};
14#[cfg(target_arch = "wasm32")]
15use casper_types::Block;
16#[cfg(target_arch = "wasm32")]
17use gloo_utils::format::JsValueSerdeExt;
18use rand::Rng;
19#[cfg(target_arch = "wasm32")]
20use serde::{Deserialize, Serialize};
21#[cfg(target_arch = "wasm32")]
22use wasm_bindgen::prelude::*;
23
24// Define a struct to wrap the GetBlockResult
25#[cfg(target_arch = "wasm32")]
26#[derive(Debug, Deserialize, Serialize)]
27#[wasm_bindgen]
28pub struct GetBlockResult(_GetBlockResult);
29
30#[cfg(target_arch = "wasm32")]
31impl From<GetBlockResult> for _GetBlockResult {
32    fn from(result: GetBlockResult) -> Self {
33        result.0
34    }
35}
36
37#[cfg(target_arch = "wasm32")]
38impl From<_GetBlockResult> for GetBlockResult {
39    fn from(result: _GetBlockResult) -> Self {
40        GetBlockResult(result)
41    }
42}
43#[cfg(target_arch = "wasm32")]
44#[wasm_bindgen]
45impl GetBlockResult {
46    /// Gets the API version as a JsValue.
47    #[wasm_bindgen(getter)]
48    pub fn api_version(&self) -> JsValue {
49        JsValue::from_serde(&self.0.api_version).unwrap()
50    }
51
52    /// Gets the block information as a JsValue.
53    #[wasm_bindgen(getter)]
54    pub fn block(&self) -> JsValue {
55        let block = self.0.block_with_signatures.clone().unwrap().block;
56
57        match block {
58            Block::V1(block_v1) => JsValue::from_serde(&block_v1).unwrap(),
59            Block::V2(block_v2) => JsValue::from_serde(&block_v2).unwrap(),
60        }
61    }
62
63    /// Converts the GetBlockResult to a JsValue.
64    #[wasm_bindgen(js_name = "toJson")]
65    pub fn to_json(&self) -> JsValue {
66        JsValue::from_serde(&self.0).unwrap_or(JsValue::null())
67    }
68}
69
70/// Options for the `get_block` method.
71#[derive(Debug, Deserialize, Default, Serialize)]
72#[cfg(target_arch = "wasm32")]
73#[wasm_bindgen(js_name = "getBlockOptions", getter_with_clone)]
74pub struct GetBlockOptions {
75    pub maybe_block_id_as_string: Option<String>,
76    pub maybe_block_identifier: Option<BlockIdentifier>,
77    pub rpc_address: Option<String>,
78    pub verbosity: Option<Verbosity>,
79}
80
81#[cfg(target_arch = "wasm32")]
82#[wasm_bindgen]
83impl SDK {
84    /// Parses block options from a JsValue.
85    ///
86    /// # Arguments
87    ///
88    /// * `options` - A JsValue containing block options to be parsed.
89    ///
90    /// # Returns
91    ///
92    /// Parsed block options as a `GetBlockOptions` struct.
93    pub fn get_block_options(&self, options: JsValue) -> Result<GetBlockOptions, JsError> {
94        options
95            .into_serde::<GetBlockOptions>()
96            .map_err(|err| JsError::new(&format!("Error deserializing options: {:?}", err)))
97    }
98
99    /// Retrieves block information using the provided options.
100    ///
101    /// # Arguments
102    ///
103    /// * `options` - An optional `GetBlockOptions` struct containing retrieval options.
104    ///
105    /// # Returns
106    ///
107    /// A `Result` containing either a `GetBlockResult` or a `JsError` in case of an error.
108    ///
109    /// # Errors
110    ///
111    /// Returns a `JsError` if there is an error during the retrieval process.
112    #[wasm_bindgen(js_name = "get_block")]
113    pub async fn get_block_js_alias(
114        &self,
115        options: Option<GetBlockOptions>,
116    ) -> Result<GetBlockResult, JsError> {
117        let GetBlockOptions {
118            maybe_block_id_as_string,
119            maybe_block_identifier,
120            verbosity,
121            rpc_address,
122        } = options.unwrap_or_default();
123
124        let maybe_block_identifier = if let Some(maybe_block_identifier) = maybe_block_identifier {
125            Some(BlockIdentifierInput::BlockIdentifier(
126                maybe_block_identifier,
127            ))
128        } else {
129            maybe_block_id_as_string.map(BlockIdentifierInput::String)
130        };
131
132        let result = self
133            .get_block(maybe_block_identifier, verbosity, rpc_address)
134            .await;
135        match result {
136            Ok(data) => Ok(data.result.into()),
137            Err(err) => {
138                let err = &format!("Error occurred with {:?}", err);
139                Err(JsError::new(err))
140            }
141        }
142    }
143
144    /// JavaScript Alias for the `get_block`.
145    ///
146    /// # Arguments
147    ///
148    /// * `options` - An optional `GetBlockOptions` struct containing retrieval options.
149    ///
150    /// # Returns
151    ///
152    /// A `Result` containing either a `GetBlockResult` or a `JsError` in case of an error.
153    ///
154    /// # Errors
155    ///
156    /// Returns a `JsError` if there is an error during the retrieval process.
157    #[deprecated(note = "This function is an alias. Please use `get_block` instead.")]
158    #[allow(deprecated)]
159    pub async fn chain_get_block(
160        &self,
161        options: Option<GetBlockOptions>,
162    ) -> Result<GetBlockResult, JsError> {
163        self.get_block_js_alias(options).await
164    }
165}
166
167impl SDK {
168    /// Retrieves block information using the provided options.
169    ///
170    /// # Arguments
171    ///
172    /// * `maybe_block_identifier` - An optional `BlockIdentifierInput` specifying the block identifier.
173    /// * `verbosity` - An optional `Verbosity` level for the retrieval.
174    /// * `rpc_address` - An optional rpc address to target for retrieval.
175    ///
176    /// # Returns
177    ///
178    /// A `Result` containing either a `_GetBlockResult` or a `SdkError` in case of an error.
179    ///
180    /// # Errors
181    ///
182    /// Returns a `SdkError` if there is an error during the retrieval process.
183    pub async fn get_block(
184        &self,
185        maybe_block_identifier: Option<BlockIdentifierInput>,
186        verbosity: Option<Verbosity>,
187        rpc_address: Option<String>,
188    ) -> Result<SuccessResponse<_GetBlockResult>, SdkError> {
189        //log("get_block!");
190
191        if let Some(BlockIdentifierInput::String(maybe_block_id)) = maybe_block_identifier {
192            get_block_cli(
193                &rand::thread_rng().gen::<u64>().to_string(),
194                &self.get_rpc_address(rpc_address),
195                self.get_verbosity(verbosity).into(),
196                &maybe_block_id,
197            )
198            .await
199            .map_err(SdkError::from)
200        } else {
201            let maybe_block_identifier =
202                if let Some(BlockIdentifierInput::BlockIdentifier(maybe_block_identifier)) =
203                    maybe_block_identifier
204                {
205                    Some(maybe_block_identifier)
206                } else {
207                    None
208                };
209            get_block_lib(
210                JsonRpcId::from(rand::thread_rng().gen::<u64>().to_string()),
211                &self.get_rpc_address(rpc_address),
212                self.get_verbosity(verbosity).into(),
213                maybe_block_identifier.map(Into::into),
214            )
215            .await
216            .map_err(SdkError::from)
217        }
218    }
219}
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224    use crate::types::{
225        hash::block_hash::BlockHash, identifier::block_identifier::BlockIdentifier,
226    };
227    use sdk_tests::tests::helpers::get_network_constants;
228
229    #[tokio::test]
230    async fn test_get_block_with_none_values() {
231        // Arrange
232        let sdk = SDK::new(None, None, None);
233        let error_message = "failed to parse node address as valid URL";
234
235        // Act
236        let result = sdk.get_block(None, None, None).await;
237
238        // Assert
239        assert!(result.is_err());
240        let err_string = result.err().unwrap().to_string();
241        assert!(err_string.contains(error_message));
242    }
243
244    #[tokio::test]
245    async fn test_get_block_with_block_id_string() {
246        // Arrange
247        let sdk = SDK::new(None, None, None);
248        let verbosity = Some(Verbosity::High);
249        let (rpc_address, _, _, _, _) = get_network_constants();
250        let result = sdk
251            .get_block(None, verbosity, Some(rpc_address.clone()))
252            .await;
253        let block_hash = BlockHash::from(
254            *result
255                .unwrap()
256                .result
257                .block_with_signatures
258                .unwrap()
259                .block
260                .hash(),
261        )
262        .to_string();
263        let block_identifier = BlockIdentifierInput::String(block_hash.to_string());
264
265        // Act
266        let result = sdk
267            .get_block(Some(block_identifier), verbosity, Some(rpc_address))
268            .await;
269
270        // Assert
271        assert!(result.is_ok());
272    }
273
274    #[tokio::test]
275    async fn test_get_block_with_block_identifier() {
276        // Arrange
277        let sdk = SDK::new(None, None, None);
278        let block_identifier =
279            BlockIdentifierInput::BlockIdentifier(BlockIdentifier::from_height(1));
280        let verbosity = Some(Verbosity::High);
281        let (rpc_address, _, _, _, _) = get_network_constants();
282
283        // Act
284        let result = sdk
285            .get_block(Some(block_identifier), verbosity, Some(rpc_address))
286            .await;
287        // Assert
288        assert!(result.is_ok());
289    }
290
291    #[tokio::test]
292    async fn test_get_block_with_error() {
293        let sdk = SDK::new(Some("http://localhost".to_string()), None, None);
294
295        let error_message = "error sending request for url (http://localhost/rpc)";
296
297        // Act
298        let result = sdk.get_block(None, None, None).await;
299
300        // Assert
301        assert!(result.is_err());
302        let err_string = result.err().unwrap().to_string();
303        assert!(err_string.contains(error_message));
304    }
305}