iota_indexer/apis/
extended_api.rs1use iota_json_rpc::IotaRpcModule;
6use iota_json_rpc_api::{
7 ExtendedApiServer, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS, internal_error, validate_limit,
8};
9use iota_json_rpc_types::{
10 AddressMetrics, EpochInfo, EpochMetrics, EpochMetricsPage, EpochPage, MoveCallMetrics,
11 NetworkMetrics, Page, ParticipationMetrics,
12};
13use iota_open_rpc::Module;
14use iota_types::iota_serde::BigInt;
15use jsonrpsee::{RpcModule, core::RpcResult};
16
17use crate::indexer_reader::IndexerReader;
18
19pub(crate) struct ExtendedApi {
20 inner: IndexerReader,
21}
22
23impl ExtendedApi {
24 pub fn new(inner: IndexerReader) -> Self {
25 Self { inner }
26 }
27}
28
29#[async_trait::async_trait]
30impl ExtendedApiServer for ExtendedApi {
31 async fn get_epochs(
32 &self,
33 cursor: Option<BigInt<u64>>,
34 limit: Option<usize>,
35 descending_order: Option<bool>,
36 ) -> RpcResult<EpochPage> {
37 let limit =
38 validate_limit(limit, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS).map_err(internal_error)?;
39 let mut epochs = self
40 .inner
41 .spawn_blocking(move |this| {
42 this.get_epochs(
43 cursor.map(|x| *x),
44 limit + 1,
45 descending_order.unwrap_or(false),
46 )
47 })
48 .await?;
49
50 let has_next_page = epochs.len() > limit;
51 epochs.truncate(limit);
52 let next_cursor = epochs.last().map(|e| e.epoch);
53 Ok(Page {
54 data: epochs,
55 next_cursor: next_cursor.map(|id| id.into()),
56 has_next_page,
57 })
58 }
59
60 async fn get_epoch_metrics(
61 &self,
62 cursor: Option<BigInt<u64>>,
63 limit: Option<usize>,
64 descending_order: Option<bool>,
65 ) -> RpcResult<EpochMetricsPage> {
66 let limit =
67 validate_limit(limit, QUERY_MAX_RESULT_LIMIT_CHECKPOINTS).map_err(internal_error)?;
68 let epochs = self
69 .inner
70 .spawn_blocking(move |this| {
71 this.get_epochs(
72 cursor.map(|x| *x),
73 limit + 1,
74 descending_order.unwrap_or(false),
75 )
76 })
77 .await?;
78
79 let mut epoch_metrics = epochs
80 .into_iter()
81 .map(|e| EpochMetrics {
82 epoch: e.epoch,
83 epoch_total_transactions: e.epoch_total_transactions,
84 first_checkpoint_id: e.first_checkpoint_id,
85 epoch_start_timestamp: e.epoch_start_timestamp,
86 end_of_epoch_info: e.end_of_epoch_info,
87 })
88 .collect::<Vec<_>>();
89
90 let has_next_page = epoch_metrics.len() > limit;
91 epoch_metrics.truncate(limit);
92 let next_cursor = epoch_metrics.last().map(|e| e.epoch);
93 Ok(Page {
94 data: epoch_metrics,
95 next_cursor: next_cursor.map(|id| id.into()),
96 has_next_page,
97 })
98 }
99
100 async fn get_current_epoch(&self) -> RpcResult<EpochInfo> {
101 let stored_epoch = self
102 .inner
103 .spawn_blocking(|this| this.get_latest_epoch_info_from_db())
104 .await?;
105 EpochInfo::try_from(stored_epoch).map_err(Into::into)
106 }
107
108 async fn get_network_metrics(&self) -> RpcResult<NetworkMetrics> {
109 let network_metrics = self
110 .inner
111 .spawn_blocking(|this| this.get_latest_network_metrics())
112 .await?;
113 Ok(network_metrics)
114 }
115
116 async fn get_move_call_metrics(&self) -> RpcResult<MoveCallMetrics> {
117 let move_call_metrics = self
118 .inner
119 .spawn_blocking(|this| this.get_latest_move_call_metrics())
120 .await?;
121 Ok(move_call_metrics)
122 }
123
124 async fn get_latest_address_metrics(&self) -> RpcResult<AddressMetrics> {
125 let latest_address_metrics = self
126 .inner
127 .spawn_blocking(|this| this.get_latest_address_metrics())
128 .await?;
129 Ok(latest_address_metrics)
130 }
131
132 async fn get_checkpoint_address_metrics(&self, checkpoint: u64) -> RpcResult<AddressMetrics> {
133 let checkpoint_address_metrics = self
134 .inner
135 .spawn_blocking(move |this| this.get_checkpoint_address_metrics(checkpoint))
136 .await?;
137 Ok(checkpoint_address_metrics)
138 }
139
140 async fn get_all_epoch_address_metrics(
141 &self,
142 descending_order: Option<bool>,
143 ) -> RpcResult<Vec<AddressMetrics>> {
144 let all_epoch_address_metrics = self
145 .inner
146 .spawn_blocking(move |this| this.get_all_epoch_address_metrics(descending_order))
147 .await?;
148 Ok(all_epoch_address_metrics)
149 }
150
151 async fn get_total_transactions(&self) -> RpcResult<BigInt<u64>> {
152 let latest_checkpoint = self
153 .inner
154 .spawn_blocking(|this| this.get_latest_checkpoint())
155 .await?;
156 Ok(latest_checkpoint.network_total_transactions.into())
157 }
158
159 async fn get_participation_metrics(&self) -> RpcResult<ParticipationMetrics> {
160 self.inner
161 .spawn_blocking(|this| this.get_participation_metrics())
162 .await
163 .map_err(Into::into)
164 }
165}
166
167impl IotaRpcModule for ExtendedApi {
168 fn rpc(self) -> RpcModule<Self> {
169 self.into_rpc()
170 }
171
172 fn rpc_doc_module() -> Module {
173 iota_json_rpc_api::ExtendedApiOpenRpc::module_doc()
174 }
175}