sui_indexer_alt_reader/
checkpoints.rs1use std::collections::HashMap;
5
6use anyhow::Context;
7use async_graphql::dataloader::Loader;
8use futures::future::try_join_all;
9use prost_types::FieldMask;
10use sui_rpc::field::FieldMaskUtil;
11use sui_rpc::proto::sui::rpc::v2 as proto;
12use sui_types::crypto::AuthorityQuorumSignInfo;
13use sui_types::messages_checkpoint::CheckpointContents;
14use sui_types::messages_checkpoint::CheckpointSummary;
15
16use crate::error::Error;
17use crate::ledger_grpc_reader::LedgerGrpcReader;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct CheckpointKey(pub u64);
22
23#[async_trait::async_trait]
24impl Loader<CheckpointKey> for LedgerGrpcReader {
25 type Value = (
26 CheckpointSummary,
27 CheckpointContents,
28 AuthorityQuorumSignInfo<true>,
29 );
30 type Error = Error;
31
32 async fn load(
33 &self,
34 keys: &[CheckpointKey],
35 ) -> Result<HashMap<CheckpointKey, Self::Value>, Error> {
36 if keys.is_empty() {
37 return Ok(HashMap::new());
38 }
39
40 let futures = keys.iter().map(|key| async {
41 let request = proto::GetCheckpointRequest::by_sequence_number(key.0).with_read_mask(
42 FieldMask::from_paths(["summary.bcs", "signature", "contents.bcs"]),
43 );
44
45 match self.get_checkpoint(request).await {
46 Ok(response) => {
47 let checkpoint = response.checkpoint.context("No checkpoint returned")?;
48
49 let summary: CheckpointSummary = checkpoint
50 .summary
51 .as_ref()
52 .and_then(|s| s.bcs.as_ref())
53 .context("Missing summary.bcs")?
54 .deserialize()
55 .context("Failed to deserialize checkpoint summary")?;
56
57 let contents: CheckpointContents = checkpoint
58 .contents
59 .as_ref()
60 .and_then(|c| c.bcs.as_ref())
61 .context("Missing contents.bcs")?
62 .deserialize()
63 .context("Failed to deserialize checkpoint contents")?;
64
65 let signature: AuthorityQuorumSignInfo<true> = {
66 let sdk_sig = sui_sdk_types::ValidatorAggregatedSignature::try_from(
67 checkpoint.signature.as_ref().context("Missing signature")?,
68 )
69 .context("Failed to parse signature")?;
70 AuthorityQuorumSignInfo::from(sdk_sig)
71 };
72
73 Ok(Some((*key, (summary, contents, signature))))
74 }
75 Err(status) if status.code() == tonic::Code::NotFound => Ok(None),
76 Err(e) => Err(Error::from(e)),
77 }
78 });
79
80 let results: Vec<_> = try_join_all(futures).await?;
81 Ok(results.into_iter().flatten().collect())
82 }
83}