iota_grpc_client/api/
mod.rs

1// Copyright (c) 2026 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! High-level API for gRPC client operations.
5//!
6//! This module provides wrappers around the raw gRPC service clients.
7//! Proto types are exposed directly with lazy conversion methods, allowing
8//! users to convert only what they need to SDK types.
9
10use iota_sdk_types::CheckpointSequenceNumber;
11
12mod common;
13pub mod execution;
14pub mod ledger;
15mod metadata;
16pub mod move_package;
17pub mod state;
18
19pub use common::{Error, Page, Result, RpcStatus};
20pub(crate) use common::{
21    ProtoResult, TryFromProtoError, build_proto_transaction, collect_stream, define_list_query,
22    field_mask_with_default, proto_object_id, saturating_usize_to_u32,
23};
24pub use iota_grpc_types::read_masks::*;
25pub use metadata::MetadataEnvelope;
26
27/// An item from a checkpoint data stream.
28///
29/// When `filter_checkpoints` is enabled, the server may skip checkpoints that
30/// don't match the provided filters. In that case, `Progress` items are sent
31/// periodically to indicate liveness and the current scan position. When
32/// `filter_checkpoints` is disabled, only `Checkpoint` items are produced.
33///
34/// For liveness detection with `filter_checkpoints`, wrap `stream.next()` in
35/// `tokio::time::timeout()` — if neither a `Checkpoint` nor a `Progress`
36/// arrives within your chosen duration plus some buffer for connection latency,
37/// the connection is likely dead.
38#[derive(Debug, Clone)]
39pub enum CheckpointStreamItem {
40    /// A complete checkpoint with its transactions and events.
41    Checkpoint(Box<CheckpointResponse>),
42    /// A progress indicator sent during filtered scanning.
43    /// Contains the sequence number of the latest scanned checkpoint.
44    Progress {
45        latest_scanned_sequence_number: CheckpointSequenceNumber,
46    },
47}
48
49impl CheckpointStreamItem {
50    /// Returns the contained checkpoint, or `None` if this is a progress
51    /// message.
52    pub fn into_checkpoint(self) -> Option<CheckpointResponse> {
53        match self {
54            Self::Checkpoint(c) => Some(*c),
55            Self::Progress { .. } => None,
56        }
57    }
58
59    /// Returns the progress sequence number, or `None` if this is a
60    /// checkpoint.
61    pub fn into_progress(self) -> Option<CheckpointSequenceNumber> {
62        match self {
63            Self::Checkpoint(_) => None,
64            Self::Progress {
65                latest_scanned_sequence_number,
66            } => Some(latest_scanned_sequence_number),
67        }
68    }
69
70    /// Returns `true` if this is a checkpoint item.
71    pub fn is_checkpoint(&self) -> bool {
72        matches!(self, Self::Checkpoint(_))
73    }
74
75    /// Returns `true` if this is a progress item.
76    pub fn is_progress(&self) -> bool {
77        matches!(self, Self::Progress { .. })
78    }
79}
80
81/// Response for a checkpoint query.
82///
83/// Contains checkpoint summary, signature, contents, transactions, and events.
84/// Fields are proto types that can be accessed directly or converted to SDK
85/// types using their conversion methods (e.g.,
86/// `response.summary()?.summary()?`, `response.contents()?.contents()?`).
87#[derive(Debug, Clone)]
88pub struct CheckpointResponse {
89    /// The checkpoint sequence number.
90    pub sequence_number: CheckpointSequenceNumber,
91    /// Proto checkpoint summary. Use `response.summary()?.summary()` to convert
92    /// to SDK type.
93    pub summary: Option<iota_grpc_types::v1::checkpoint::CheckpointSummary>,
94    /// Proto validator signature. Use `response.signature()?.signature()` to
95    /// convert to SDK type.
96    pub signature: Option<iota_grpc_types::v1::signatures::ValidatorAggregatedSignature>,
97    /// Proto checkpoint contents. Use `response.contents()?.contents()` to
98    /// convert to SDK type.
99    pub contents: Option<iota_grpc_types::v1::checkpoint::CheckpointContents>,
100    /// Proto executed transactions. Use methods like `tx.effects()?`,
101    /// `tx.transaction()?`, etc.
102    pub executed_transactions: Vec<iota_grpc_types::v1::transaction::ExecutedTransaction>,
103    /// Proto events. Use `event.try_into()` or `event.events()` to convert to
104    /// SDK types.
105    pub events: Vec<iota_grpc_types::v1::event::Event>,
106}
107
108impl CheckpointResponse {
109    /// Get the checkpoint sequence number.
110    ///
111    /// Always available regardless of the read mask.
112    pub fn sequence_number(&self) -> CheckpointSequenceNumber {
113        self.sequence_number
114    }
115
116    /// Get the checkpoint summary.
117    ///
118    /// Returns the proto
119    /// [`CheckpointSummary`](iota_grpc_types::v1::checkpoint::CheckpointSummary)
120    /// which provides:
121    /// - [`digest()`](iota_grpc_types::v1::checkpoint::CheckpointSummary::digest) — the summary digest
122    /// - [`summary()`](iota_grpc_types::v1::checkpoint::CheckpointSummary::summary) — the deserialized SDK `CheckpointSummary`
123    ///
124    /// **Read mask:** `"checkpoint.summary"` (see
125    /// [`CHECKPOINT_RESPONSE_SUMMARY`])
126    pub fn summary(&self) -> Result<&iota_grpc_types::v1::checkpoint::CheckpointSummary> {
127        self.summary
128            .as_ref()
129            .ok_or_else(|| TryFromProtoError::missing("summary").into())
130    }
131
132    /// Build a [`SignedCheckpointSummary`](iota_sdk_types::SignedCheckpointSummary)
133    /// from the response.
134    ///
135    /// Requires the checkpoint summary and signature to be present.
136    ///
137    /// **Read mask:** see [`CHECKPOINT_RESPONSE_SIGNED_SUMMARY`]
138    pub fn signed_summary(&self) -> Result<iota_sdk_types::SignedCheckpointSummary> {
139        Ok(iota_sdk_types::SignedCheckpointSummary {
140            checkpoint: self.summary()?.summary()?,
141            signature: self.signature()?.signature()?,
142        })
143    }
144
145    /// Get the validator aggregated signature for the checkpoint.
146    ///
147    /// **Read mask:** `"checkpoint.signature"` (see
148    /// [`CHECKPOINT_RESPONSE_SIGNATURE`])
149    pub fn signature(
150        &self,
151    ) -> Result<&iota_grpc_types::v1::signatures::ValidatorAggregatedSignature> {
152        self.signature
153            .as_ref()
154            .ok_or_else(|| TryFromProtoError::missing("signature").into())
155    }
156
157    /// Get the checkpoint contents.
158    ///
159    /// Returns the proto
160    /// [`CheckpointContents`](iota_grpc_types::v1::checkpoint::CheckpointContents)
161    /// which provides:
162    /// - [`digest()`](iota_grpc_types::v1::checkpoint::CheckpointContents::digest) — the contents digest
163    /// - [`contents()`](iota_grpc_types::v1::checkpoint::CheckpointContents::contents) — the deserialized SDK `CheckpointContents`
164    ///
165    /// **Read mask:** `"checkpoint.contents"` (see
166    /// [`CHECKPOINT_RESPONSE_CONTENTS`])
167    pub fn contents(&self) -> Result<&iota_grpc_types::v1::checkpoint::CheckpointContents> {
168        self.contents
169            .as_ref()
170            .ok_or_else(|| TryFromProtoError::missing("contents").into())
171    }
172
173    /// Get the executed transactions in this checkpoint.
174    ///
175    /// Returns proto
176    /// [`ExecutedTransaction`](iota_grpc_types::v1::transaction::ExecutedTransaction)
177    /// values. Which sub-fields are populated depends on the read mask; use
178    /// paths like `"transactions.effects"` or `"transactions.transaction"`.
179    ///
180    /// **Read mask:** `"transactions"` for all sub-fields (see
181    /// [`CHECKPOINT_RESPONSE_EXECUTED_TRANSACTIONS`])
182    pub fn executed_transactions(
183        &self,
184    ) -> &Vec<iota_grpc_types::v1::transaction::ExecutedTransaction> {
185        &self.executed_transactions
186    }
187
188    /// Get the top-level events for this checkpoint.
189    ///
190    /// Returns proto [`Event`](iota_grpc_types::v1::event::Event) values.
191    /// Which sub-fields are populated depends on the read mask; use paths like
192    /// `"events.bcs"` or `"events.event_type"`.
193    ///
194    /// **Read mask:** `"events"` for all sub-fields (see
195    /// [`CHECKPOINT_RESPONSE_EVENTS`])
196    pub fn events(&self) -> &Vec<iota_grpc_types::v1::event::Event> {
197        &self.events
198    }
199
200    /// Build a full
201    /// [`CheckpointData`](iota_sdk_types::checkpoint::CheckpointData)
202    /// from the response.
203    ///
204    /// Requires the checkpoint summary, signature, contents, and all
205    /// transaction data (transaction, signatures, effects, events,
206    /// input_objects, output_objects) to be present in the response.
207    ///
208    /// **Read mask:** see [`CHECKPOINT_RESPONSE_CHECKPOINT_DATA`]
209    ///
210    /// # Example
211    ///
212    /// ```no_run
213    /// # use iota_grpc_client::Client;
214    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
215    /// use iota_grpc_client::CHECKPOINT_RESPONSE_CHECKPOINT_DATA;
216    /// let client = Client::connect("http://localhost:9000").await?;
217    /// let cp = client
218    ///     .get_checkpoint_latest(Some(CHECKPOINT_RESPONSE_CHECKPOINT_DATA), None, None)
219    ///     .await?;
220    /// let data = cp.body().checkpoint_data()?;
221    /// # Ok(())
222    /// # }
223    /// ```
224    pub fn checkpoint_data(&self) -> Result<iota_sdk_types::checkpoint::CheckpointData> {
225        Ok(iota_sdk_types::checkpoint::CheckpointData {
226            checkpoint_contents: self.contents()?.contents()?,
227            checkpoint_summary: iota_sdk_types::SignedCheckpointSummary {
228                checkpoint: self.summary()?.summary()?,
229                signature: self.signature()?.signature()?,
230            },
231            transactions: self
232                .executed_transactions()
233                .iter()
234                .map(TryInto::try_into)
235                .collect::<std::result::Result<Vec<_>, _>>()?,
236        })
237    }
238}