Skip to main content

poi_rs/
source.rs

1// Copyright 2020-2026 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use async_trait::async_trait;
5use iota_sdk_types::{CheckpointContents, ObjectId, TransactionDigest, Version};
6use iota_types::committee::{Committee, EpochId};
7use iota_types::digests::ChainIdentifier;
8use iota_types::effects::{TransactionEffects, TransactionEvents};
9use iota_types::messages_checkpoint::CertifiedCheckpointSummary;
10use iota_types::object::Object;
11use iota_types::transaction::Transaction;
12
13use crate::BoxError;
14
15#[cfg(feature = "native-grpc")]
16mod grpc;
17
18/// Error returned when a ledger source cannot provide requested data.
19#[derive(Debug, thiserror::Error)]
20#[non_exhaustive]
21pub enum SourceError {
22    /// A request to the source failed.
23    #[error("source request failed")]
24    Request {
25        /// Underlying source error.
26        #[source]
27        source: BoxError,
28    },
29    /// A response could not be decoded or converted.
30    #[error("source returned an invalid response")]
31    InvalidResponse {
32        /// Underlying response or conversion error.
33        #[source]
34        source: BoxError,
35    },
36    /// Required source data was omitted.
37    #[error("source response is missing required data")]
38    MissingData {
39        /// Underlying response error.
40        #[source]
41        source: BoxError,
42    },
43}
44
45impl SourceError {
46    /// Creates an error for a failed source request.
47    pub fn request(source: impl std::error::Error + Send + Sync + 'static) -> Self {
48        Self::Request {
49            source: Box::new(source),
50        }
51    }
52
53    /// Creates an error for an invalid source response.
54    pub fn invalid_response(source: impl std::error::Error + Send + Sync + 'static) -> Self {
55        Self::InvalidResponse {
56            source: Box::new(source),
57        }
58    }
59
60    /// Creates an error for required data omitted from a source response.
61    pub fn missing_data(source: impl std::error::Error + Send + Sync + 'static) -> Self {
62        Self::MissingData {
63            source: Box::new(source),
64        }
65    }
66}
67
68/// Decoded transaction evidence returned by a [`Source`].
69///
70/// This type contains IOTA domain values rather than transport-specific gRPC or
71/// protobuf messages.
72#[derive(Clone, Debug)]
73pub struct SourceTransaction {
74    /// Signed transaction being authenticated.
75    pub transaction: Transaction,
76    /// Effects produced by executing the transaction.
77    pub effects: TransactionEffects,
78    /// Events emitted by the transaction, when present.
79    pub events: Option<TransactionEvents>,
80    /// Sequence number of the checkpoint that includes the transaction.
81    pub checkpoint_sequence_number: u64,
82}
83
84/// Decoded checkpoint evidence returned by a [`Source`].
85///
86/// The certified summary authenticates the checkpoint contents used by the
87/// transaction proof.
88#[derive(Clone, Debug)]
89pub struct SourceCheckpoint {
90    /// Certified checkpoint summary.
91    pub summary: CertifiedCheckpointSummary,
92    /// Contents committed to by the checkpoint summary.
93    pub contents: CheckpointContents,
94}
95
96/// Ledger-read boundary used by [`crate::ProofBuilder`] and [`crate::CommitteeResolver`].
97///
98/// Implementations may fetch evidence from native gRPC, a JavaScript client,
99/// archive storage, fixtures, or another source. Proof assembly, target
100/// validation, committee authentication, and caching remain outside the source.
101#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
102#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
103pub trait Source {
104    /// Fetches the genesis-checkpoint digest that identifies the source chain.
105    async fn chain_identifier(&self) -> Result<ChainIdentifier, SourceError>;
106
107    /// Fetches and decodes one executed transaction.
108    async fn transaction(
109        &self,
110        transaction_digest: TransactionDigest,
111    ) -> Result<Option<SourceTransaction>, SourceError>;
112
113    /// Fetches and decodes an object, optionally at an exact version.
114    async fn object(&self, object_id: ObjectId, version: Option<Version>) -> Result<Option<Object>, SourceError>;
115
116    /// Fetches and decodes one certified checkpoint and its contents.
117    ///
118    /// Returns `None` when the checkpoint does not exist.
119    async fn checkpoint(&self, sequence_number: u64) -> Result<Option<SourceCheckpoint>, SourceError>;
120
121    /// Fetches the committee reported for `epoch`.
122    async fn committee(&self, epoch: EpochId) -> Result<Committee, SourceError>;
123
124    /// Fetches the current epoch reported by the source.
125    async fn current_epoch(&self) -> Result<Option<EpochId>, SourceError>;
126
127    /// Fetches the certified checkpoint summary that closed `epoch`.
128    async fn epoch_close_summary(&self, epoch: EpochId) -> Result<Option<CertifiedCheckpointSummary>, SourceError>;
129}