1use std::collections::HashSet;
2
3use anchor_lang::prelude::Pubkey;
4use chrono::{DateTime, Utc};
5use clap::ValueEnum;
6use data_anchor_blober::GROTH16_PROOF_SIZE;
7use data_anchor_proofs::compound::CompoundInclusionProof;
8use jsonrpsee::{
9 core::{RpcResult, SubscriptionResult},
10 proc_macros::rpc,
11};
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub struct BloberData {
18 #[serde(with = "pubkey_with_str")]
19 pub blober: Pubkey,
20 pub payer: Pubkey,
21 pub network_id: u64,
22}
23
24#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
26pub struct TimeRange {
27 pub start: Option<DateTime<Utc>>,
29 pub end: Option<DateTime<Utc>>,
31}
32
33impl TimeRange {
34 pub fn to_db_defaults(&self) -> (DateTime<Utc>, DateTime<Utc>) {
37 #[allow(clippy::unwrap_used, reason = "Hardcoding 0 will never panic")]
38 let default_start = DateTime::<Utc>::from_timestamp_micros(0).unwrap();
39
40 (
41 self.start.unwrap_or(default_start),
42 self.end.unwrap_or(Utc::now()),
43 )
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
49pub struct PubkeyFromStr(#[serde(with = "pubkey_with_str")] pub Pubkey);
50
51impl From<PubkeyFromStr> for Pubkey {
52 fn from(value: PubkeyFromStr) -> Self {
53 value.0
54 }
55}
56
57impl From<Pubkey> for PubkeyFromStr {
58 fn from(value: Pubkey) -> Self {
59 PubkeyFromStr(value)
60 }
61}
62
63#[serde_with::serde_as]
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66pub struct ProofData {
67 #[serde_as(as = "serde_with::Bytes")]
69 pub proof: [u8; GROTH16_PROOF_SIZE],
70 pub public_values: Vec<u8>,
72 pub verification_key: String,
74}
75
76#[rpc(server, client)]
78pub trait IndexerRpc {
79 #[method(name = "health")]
81 async fn health(&self) -> RpcResult<()>;
82
83 #[method(name = "get_blobs")]
87 async fn get_blobs(&self, blober: PubkeyFromStr, slot: u64) -> RpcResult<Option<Vec<Vec<u8>>>>;
88
89 #[method(name = "get_blobs_by_blober")]
92 async fn get_blobs_by_blober(
93 &self,
94 blober: PubkeyFromStr,
95 time_range: Option<TimeRange>,
96 ) -> RpcResult<Vec<Vec<u8>>>;
97
98 #[method(name = "get_blobs_by_payer")]
101 async fn get_blobs_by_payer(
102 &self,
103 payer: PubkeyFromStr,
104 network_name: String,
105 time_range: Option<TimeRange>,
106 ) -> RpcResult<Vec<Vec<u8>>>;
107
108 #[method(name = "get_blobs_by_network")]
111 async fn get_blobs_by_network(
112 &self,
113 network_name: String,
114 time_range: Option<TimeRange>,
115 ) -> RpcResult<Vec<Vec<u8>>>;
116
117 #[method(name = "get_blobs_by_namespace")]
120 async fn get_blobs_by_namespace_for_payer(
121 &self,
122 namespace: String,
123 payer: Option<PubkeyFromStr>,
124 time_range: Option<TimeRange>,
125 ) -> RpcResult<Vec<Vec<u8>>>;
126
127 #[method(name = "get_payers_by_network")]
130 async fn get_payers_by_network(&self, network_name: String) -> RpcResult<Vec<PubkeyFromStr>>;
131
132 #[deprecated(since = "0.4.3", note = "please use `checkpoint_proof` instead")]
135 #[method(name = "get_proof")]
136 async fn get_proof(
137 &self,
138 blober: PubkeyFromStr,
139 slot: u64,
140 ) -> RpcResult<Option<CompoundInclusionProof>>;
141
142 #[deprecated(since = "0.4.3", note = "please use `checkpoint_proof` instead")]
145 #[method(name = "get_proof_for_blob")]
146 async fn get_proof_for_blob(
147 &self,
148 blob_address: PubkeyFromStr,
149 ) -> RpcResult<Option<CompoundInclusionProof>>;
150
151 #[subscription(
155 name = "subscribe_blob_finalization" => "listen_subscribe_blob_finalization",
156 unsubscribe = "unsubscribe_blob_finalization",
157 item = (Pubkey, u64)
158 )]
159 async fn subscribe_blob_finalization(
160 &self,
161 blobers: HashSet<PubkeyFromStr>,
162 ) -> SubscriptionResult;
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, ValueEnum)]
166#[serde(rename_all = "kebab-case")]
167pub enum CustomerElf {
168 DataCorrectness,
170 PobSla,
172}
173
174impl std::fmt::Display for CustomerElf {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 CustomerElf::DataCorrectness => write!(f, "data-correctness"),
178 CustomerElf::PobSla => write!(f, "pob-sla"),
179 }
180 }
181}
182
183impl CustomerElf {
184 pub fn authority(&self) -> Pubkey {
185 match self {
186 CustomerElf::DataCorrectness => data_anchor_data_correctness_verifier::id(),
187 CustomerElf::PobSla => data_anchor_pob_sla_verifier::id(),
188 }
189 }
190}
191
192#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
193#[repr(i8)]
194pub enum RequestFailureReason {
195 #[default]
196 Unknown,
197 ProofGenerationFailed,
198 TransactionError,
199 RpcConnection,
200}
201
202impl From<RequestFailureReason> for i16 {
203 fn from(reason: RequestFailureReason) -> Self {
204 match reason {
205 RequestFailureReason::Unknown => -1,
206 RequestFailureReason::ProofGenerationFailed => -2,
207 RequestFailureReason::TransactionError => -3,
208 RequestFailureReason::RpcConnection => -4,
209 }
210 }
211}
212
213impl From<i16> for RequestFailureReason {
214 fn from(reason: i16) -> Self {
215 match reason {
216 -1 => RequestFailureReason::Unknown,
217 -2 => RequestFailureReason::ProofGenerationFailed,
218 -3 => RequestFailureReason::TransactionError,
219 -4 => RequestFailureReason::RpcConnection,
220 #[allow(
221 clippy::panic,
222 reason = "This should never happen as we only use this for reading from the database"
223 )]
224 _ => panic!("Invalid request failure reason: {reason}"),
225 }
226 }
227}
228
229#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
230#[repr(i8)]
231pub enum RequestStatus {
232 #[default]
233 Created,
234 Submitted,
235 Completed,
236 Posted,
237 Failed(RequestFailureReason),
238}
239
240impl From<RequestStatus> for i16 {
241 fn from(status: RequestStatus) -> Self {
242 match status {
243 RequestStatus::Created => 0,
244 RequestStatus::Submitted => 1,
245 RequestStatus::Completed => 2,
246 RequestStatus::Posted => 3,
247 RequestStatus::Failed(reason) => reason.into(),
248 }
249 }
250}
251
252impl From<i16> for RequestStatus {
253 fn from(status: i16) -> Self {
254 match status {
255 0 => RequestStatus::Created,
256 1 => RequestStatus::Submitted,
257 2 => RequestStatus::Completed,
258 3 => RequestStatus::Posted,
259 x if x < 0 => RequestStatus::Failed(x.into()),
260 #[allow(
261 clippy::panic,
262 reason = "This should never happen as we only use this for reading from the database"
263 )]
264 _ => panic!("Invalid request status: {status}"),
265 }
266 }
267}
268
269#[rpc(server, client)]
271pub trait ProofRpc {
272 #[method(name = "health")]
274 async fn health(&self) -> RpcResult<()>;
275
276 #[method(name = "checkpoint_proof")]
279 async fn checkpoint_proof(
280 &self,
281 blober: PubkeyFromStr,
282 slot: u64,
283 customer_elf: CustomerElf,
284 ) -> RpcResult<String>;
285
286 #[method(name = "get_proof_request_status")]
289 async fn get_proof_request_status(&self, request_id: String) -> RpcResult<RequestStatus>;
290}
291
292pub mod pubkey_with_str {
293 use std::str::FromStr;
294
295 use anchor_lang::prelude::Pubkey;
296 use serde::{Deserialize, Deserializer, de};
297
298 pub fn deserialize<'de, D>(deserializer: D) -> Result<Pubkey, D::Error>
299 where
300 D: Deserializer<'de>,
301 {
302 String::deserialize(deserializer)
303 .and_then(|key| Pubkey::from_str(&key).map_err(de::Error::custom))
304 }
305
306 pub fn serialize<S>(pubkey: &Pubkey, serializer: S) -> Result<S::Ok, S::Error>
307 where
308 S: serde::Serializer,
309 {
310 serializer.serialize_str(&pubkey.to_string())
311 }
312}