Skip to main content

casper_rust_wasm_sdk/sdk/rpcs/
get_block.rs

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