data_anchor_api/
rpc.rs

1use std::{collections::HashSet, str::FromStr};
2
3use chrono::{DateTime, Utc};
4use jsonrpsee::{
5    core::{RpcResult, SubscriptionResult},
6    proc_macros::rpc,
7};
8use serde::{Deserialize, Deserializer, Serialize, de};
9use solana_sdk::{clock::Slot, pubkey::Pubkey};
10
11use crate::CompoundProof;
12
13/// A data structure representing a blober's information, including the blober's pubkey, the
14/// payer's pubkey, and the network of the blober.
15#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16pub struct BloberData {
17    #[serde(deserialize_with = "deserialize_pubkey")]
18    pub blober: Pubkey,
19    pub payer: Pubkey,
20    pub network_id: u64,
21}
22
23/// A time range with optional start and end times, used for filtering time.
24#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
25pub struct TimeRange {
26    /// The start time of the range, inclusive.
27    pub start: Option<DateTime<Utc>>,
28    /// The end time of the range, inclusive.
29    pub end: Option<DateTime<Utc>>,
30}
31
32impl TimeRange {
33    /// Returns the start and end times as a tuple of `DateTime<Utc>`, with defaults for
34    /// missing values.
35    pub fn to_db_defaults(&self) -> (DateTime<Utc>, DateTime<Utc>) {
36        #[allow(clippy::unwrap_used, reason = "Hardcoding 0 will never panic")]
37        let default_start = DateTime::<Utc>::from_timestamp_micros(0).unwrap();
38
39        (
40            self.start.unwrap_or(default_start),
41            self.end.unwrap_or(Utc::now()),
42        )
43    }
44}
45
46/// Request parameters for retrieving blobs by a specific blober's pubkey and a time range.
47#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
48pub struct BlobsByBlober {
49    /// The blober's pubkey.
50    #[serde(deserialize_with = "deserialize_pubkey")]
51    pub blober: Pubkey,
52    /// The time range for which to retrieve blobs.
53    #[serde(flatten)]
54    pub time_range: TimeRange,
55}
56
57/// Request parameters for retrieving blobs by a specific payer's pubkey, network ID, and a time range.
58#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
59pub struct BlobsByPayer {
60    /// The payer's pubkey.
61    #[serde(deserialize_with = "deserialize_pubkey")]
62    pub payer: Pubkey,
63    /// The network name of the blobs.
64    pub network_name: String,
65    /// The time range for which to retrieve blobs.
66    #[serde(flatten)]
67    pub time_range: TimeRange,
68}
69
70/// A wrapper around a blober's pubkey, used to identify a blober in RPC calls.
71#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
72pub struct PubkeyFromStr(#[serde(deserialize_with = "deserialize_pubkey")] pub Pubkey);
73
74impl From<PubkeyFromStr> for Pubkey {
75    fn from(value: PubkeyFromStr) -> Self {
76        value.0
77    }
78}
79
80impl From<Pubkey> for PubkeyFromStr {
81    fn from(value: Pubkey) -> Self {
82        PubkeyFromStr(value)
83    }
84}
85
86/// The Indexer RPC interface.
87#[rpc(server, client)]
88pub trait IndexerRpc {
89    /// Retrieve a list of blobs for a given slot and blober pubkey. Returns an error if there was a
90    /// database or RPC failure, and None if the slot has not been completed yet. If the slot is
91    /// completed, an empty list will be returned.
92    #[method(name = "get_blobs")]
93    async fn get_blobs(&self, blober: PubkeyFromStr, slot: u64) -> RpcResult<Option<Vec<Vec<u8>>>>;
94
95    /// Retrieve a list of blobs for a given blober pubkey and time range. Returns an error if there
96    /// was a database or RPC failure, and an empty list if no blobs were found.
97    #[method(name = "get_blobs_by_blober")]
98    async fn get_blobs_by_blober(&self, blober: BlobsByBlober) -> RpcResult<Vec<Vec<u8>>>;
99
100    /// Retrieve a list of blobs for a given payer pubkey, network ID, and time range. Returns an
101    /// error if there was a database or RPC failure, and an empty list if no blobs were found.
102    #[method(name = "get_blobs_by_payer")]
103    async fn get_blobs_by_payer(&self, payer: BlobsByPayer) -> RpcResult<Vec<Vec<u8>>>;
104
105    /// Retrieve a list of blobs for a given network name and time range. Returns an error if there
106    /// was a database or RPC failure, and an empty list if no blobs were found.
107    #[method(name = "get_blobs_by_network")]
108    async fn get_blobs_by_network(
109        &self,
110        network_name: String,
111        time_range: TimeRange,
112    ) -> RpcResult<Vec<Vec<u8>>>;
113
114    /// Retrieve a list of blobs for a given namespace and time range. Returns an error if there
115    /// was a database or RPC failure, and an empty list if no blobs were found.
116    #[method(name = "get_blobs_by_namespace")]
117    async fn get_blobs_by_namespace_for_payer(
118        &self,
119        namespace: String,
120        payer: Option<PubkeyFromStr>,
121        time_range: TimeRange,
122    ) -> RpcResult<Vec<Vec<u8>>>;
123
124    /// Retrieve a list of payers for a given network name. Returns an error if there was a
125    /// database or RPC failure, and an empty list if no payers were found.
126    #[method(name = "get_payers_by_network")]
127    async fn get_payers_by_network(&self, network_name: String) -> RpcResult<Vec<PubkeyFromStr>>;
128
129    /// Retrieve a proof for a given slot and blober pubkey. Returns an error if there was a
130    /// database or RPC failure, and None if the slot has not been completed yet.
131    #[method(name = "get_proof")]
132    async fn get_proof(&self, blober: PubkeyFromStr, slot: u64)
133    -> RpcResult<Option<CompoundProof>>;
134
135    /// Retrieve a compound proof that covers a particular blob. Returns an error if there was a
136    /// database or RPC failure, and None if the blob does not exist.
137    #[method(name = "get_proof_for_blob")]
138    async fn get_proof_for_blob(
139        &self,
140        blob_address: PubkeyFromStr,
141    ) -> RpcResult<Option<CompoundProof>>;
142
143    /// Add a list of blober PDA addresses to the list of tracked blobers.
144    #[method(name = "add_blobers")]
145    async fn add_blobers(&self, blobers: HashSet<BloberData>) -> RpcResult<()>;
146
147    /// Remove a list of blober PDA addresses from the list of tracked blobers.
148    #[method(name = "remove_blobers")]
149    async fn remove_blobers(&self, blobers: HashSet<PubkeyFromStr>) -> RpcResult<()>;
150
151    /// Listen to blob finalization events from specified blobers. This will return a stream of
152    /// slots and blober PDAs that have finalized blobs. The stream will be closed when the RPC server is
153    /// shut down.
154    #[subscription(name = "subscribe_blob_finalization" => "listen_subscribe_blob_finalization", unsubscribe = "unsubscribe_blob_finalization", item = (Pubkey, Slot))]
155    async fn subscribe_blob_finalization(
156        &self,
157        blobers: HashSet<PubkeyFromStr>,
158    ) -> SubscriptionResult;
159}
160
161fn deserialize_pubkey<'de, D>(deserializer: D) -> Result<Pubkey, D::Error>
162where
163    D: Deserializer<'de>,
164{
165    String::deserialize(deserializer)
166        .and_then(|key| Pubkey::from_str(&key).map_err(de::Error::custom))
167}