Skip to main content

celestia_rpc/
blobstream.rs

1//! celestia-node rpc types and methods related to blobstream
2
3use std::future::Future;
4use std::marker::{Send, Sync};
5
6use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
7use celestia_types::MerkleProof;
8use celestia_types::consts::HASH_SIZE;
9use celestia_types::hash::Hash;
10use jsonrpsee::core::RpcResult;
11use jsonrpsee::core::client::{ClientT, Error};
12use jsonrpsee::proc_macros::rpc;
13
14use crate::custom_client_error;
15
16mod rpc {
17    use super::*;
18
19    /// Blobstream RPC methods.
20    #[rpc(client, server, namespace = "blobstream", namespace_separator = ".")]
21    pub trait Blobstream {
22        /// Collects the data roots over a provided ordered range of blocks, and then
23        /// creates a new Merkle root of those data roots.
24        ///
25        /// The range is end exclusive.
26        #[method(name = "GetDataRootTupleRoot")]
27        async fn blobstream_get_data_root_tuple_root(
28            &self,
29            start: u64,
30            end: u64,
31        ) -> RpcResult<String>;
32
33        /// Creates an inclusion proof, for the data root tuple of block height `height`,
34        /// in the set of blocks defined by `start` and `end`.
35        ///
36        /// The range is end exclusive.
37        #[method(name = "GetDataRootTupleInclusionProof")]
38        async fn blobstream_get_data_root_tuple_inclusion_proof(
39            &self,
40            height: u64,
41            start: u64,
42            end: u64,
43        ) -> RpcResult<MerkleProof>;
44    }
45}
46
47/// Client implementation for the Blobstream RPC API.
48// TODO: get rid of this after a release or two
49// https://github.com/eigerco/lumina/issues/683
50pub trait BlobstreamClient: ClientT {
51    /// Collects the data roots over a provided ordered range of blocks, and then
52    /// creates a new Merkle root of those data roots.
53    ///
54    /// The range is end exclusive.
55    fn blobstream_get_data_root_tuple_root<'a, 'fut>(
56        &'a self,
57        start: u64,
58        end: u64,
59    ) -> impl Future<Output = Result<Hash, Error>> + Send + 'fut
60    where
61        'a: 'fut,
62        Self: Sized + Sync + 'fut,
63    {
64        async move {
65            let root = rpc::BlobstreamClient::blobstream_get_data_root_tuple_root(self, start, end)
66                .await?;
67
68            if root.len() == 2 * HASH_SIZE {
69                root.parse::<Hash>().map_err(custom_client_error)
70            } else {
71                let decoded = BASE64.decode(&root).map_err(custom_client_error)?;
72                Hash::try_from(decoded).map_err(custom_client_error)
73            }
74        }
75    }
76
77    /// Creates an inclusion proof, for the data root tuple of block height `height`,
78    /// in the set of blocks defined by `start` and `end`.
79    ///
80    /// The range is end exclusive.
81    fn blobstream_get_data_root_tuple_inclusion_proof<'a, 'fut>(
82        &'a self,
83        height: u64,
84        start: u64,
85        end: u64,
86    ) -> impl Future<Output = Result<MerkleProof, Error>> + Send + 'fut
87    where
88        'a: 'fut,
89        Self: Sized + Sync + 'fut,
90    {
91        rpc::BlobstreamClient::blobstream_get_data_root_tuple_inclusion_proof(
92            self, height, start, end,
93        )
94    }
95}
96
97/// Server trait for Blobstream RPC endpoints.
98pub trait BlobstreamServer: rpc::BlobstreamServer {}
99
100impl<T> BlobstreamClient for T where T: ClientT {}
101
102impl<T> BlobstreamServer for T where T: rpc::BlobstreamServer {}
103
104pub use rpc::BlobstreamServer as BlobstreamRpcServer;