Skip to content

Commit e8df528

Browse files
committed
sui-graphql-rust-sdk: add checkpoint fetching API [10/n]
1 parent 31016cf commit e8df528

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//! Checkpoint-related convenience methods.
2+
3+
use base64ct::Base64;
4+
use base64ct::Encoding;
5+
use sui_graphql_macros::Response;
6+
use sui_sdk_types::CheckpointContents;
7+
use sui_sdk_types::CheckpointSummary;
8+
9+
use super::Client;
10+
use crate::error::Error;
11+
12+
/// A checkpoint response containing the summary and contents.
13+
///
14+
/// This struct combines the checkpoint header (summary) with its contents.
15+
#[derive(Debug, Clone)]
16+
#[non_exhaustive]
17+
pub struct CheckpointResponse {
18+
/// The checkpoint summary (epoch, sequence number, timestamp, etc.)
19+
pub summary: CheckpointSummary,
20+
/// The checkpoint contents (transaction digests and signatures)
21+
pub contents: CheckpointContents,
22+
}
23+
24+
impl Client {
25+
/// Fetch a checkpoint by its sequence number, or the latest checkpoint if not specified.
26+
///
27+
/// Returns:
28+
/// - `Ok(Some(response))` if the checkpoint exists
29+
/// - `Ok(None)` if the checkpoint does not exist
30+
/// - `Err(Error::Request)` for network errors
31+
/// - `Err(Error::Base64)` / `Err(Error::Bcs)` for decoding errors
32+
pub async fn get_checkpoint(
33+
&self,
34+
sequence_number: Option<u64>,
35+
) -> Result<Option<CheckpointResponse>, Error> {
36+
#[derive(Response)]
37+
struct Response {
38+
#[field(path = "checkpoint.summaryBcs")]
39+
summary_bcs: Option<String>,
40+
#[field(path = "checkpoint.contentBcs")]
41+
content_bcs: Option<String>,
42+
}
43+
44+
const QUERY: &str = r#"
45+
query($sequenceNumber: UInt53) {
46+
checkpoint(sequenceNumber: $sequenceNumber) {
47+
summaryBcs
48+
contentBcs
49+
}
50+
}
51+
"#;
52+
let variables = serde_json::json!({ "sequenceNumber": sequence_number });
53+
54+
let response = self.query::<Response>(QUERY, variables).await?;
55+
56+
let Some(data) = response.into_data() else {
57+
return Ok(None);
58+
};
59+
60+
let (Some(summary_bcs), Some(content_bcs)) = (data.summary_bcs, data.content_bcs) else {
61+
return Ok(None);
62+
};
63+
64+
let summary_bytes = Base64::decode_vec(&summary_bcs)?;
65+
let summary: CheckpointSummary = bcs::from_bytes(&summary_bytes)?;
66+
67+
let content_bytes = Base64::decode_vec(&content_bcs)?;
68+
let contents: CheckpointContents = bcs::from_bytes(&content_bytes)?;
69+
70+
Ok(Some(CheckpointResponse { summary, contents }))
71+
}
72+
}
73+
74+
#[cfg(test)]
75+
mod tests {
76+
use super::*;
77+
use wiremock::Mock;
78+
use wiremock::MockServer;
79+
use wiremock::ResponseTemplate;
80+
use wiremock::matchers::method;
81+
use wiremock::matchers::path;
82+
83+
#[tokio::test]
84+
async fn test_get_checkpoint_not_found() {
85+
let mock_server = MockServer::start().await;
86+
87+
Mock::given(method("POST"))
88+
.and(path("/"))
89+
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
90+
"data": {
91+
"checkpoint": null
92+
}
93+
})))
94+
.mount(&mock_server)
95+
.await;
96+
97+
let client = Client::new(&mock_server.uri()).unwrap();
98+
99+
let result = client.get_checkpoint(Some(999999999)).await;
100+
assert!(result.is_ok());
101+
assert!(result.unwrap().is_none());
102+
}
103+
}

crates/sui-graphql/src/client/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! GraphQL client for Sui blockchain.
22
33
pub mod chain;
4+
pub mod checkpoints;
45
pub mod coins;
56
mod objects;
67
pub mod transactions;

crates/sui-graphql/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod scalars;
1313

1414
pub use client::Client;
1515
pub use client::chain::Epoch;
16+
pub use client::checkpoints::CheckpointResponse;
1617
pub use client::coins::Balance;
1718
pub use client::transactions::TransactionResponse;
1819
pub use error::Error;

0 commit comments

Comments
 (0)