1use anyhow::bail;
10pub use coin::{CoinReadApiClient, CoinReadApiOpenRpc, CoinReadApiServer};
11pub use extended::{ExtendedApiClient, ExtendedApiOpenRpc, ExtendedApiServer};
12pub use governance::{GovernanceReadApiClient, GovernanceReadApiOpenRpc, GovernanceReadApiServer};
13pub use indexer::{IndexerApiClient, IndexerApiOpenRpc, IndexerApiServer};
14use jsonrpsee::{
15 core::ClientError,
16 types::{
17 ErrorObjectOwned,
18 error::{INTERNAL_ERROR_CODE, UNKNOWN_ERROR_CODE},
19 },
20};
21pub use move_utils::{MoveUtilsClient, MoveUtilsOpenRpc, MoveUtilsServer};
22use once_cell::sync::Lazy;
23use prometheus::{
24 Histogram, IntCounter, register_histogram_with_registry, register_int_counter_with_registry,
25};
26pub use read::{ReadApiClient, ReadApiOpenRpc, ReadApiServer};
27use tap::TapFallible;
28use tracing::warn;
29pub use transaction_builder::{
30 TransactionBuilderClient, TransactionBuilderOpenRpc, TransactionBuilderServer,
31};
32pub use write::{WriteApiClient, WriteApiOpenRpc, WriteApiServer};
33
34mod coin;
35mod extended;
36mod governance;
37mod indexer;
38mod move_utils;
39mod read;
40mod transaction_builder;
41mod write;
42
43const RPC_QUERY_MAX_RESULT_LIMIT: &str = "RPC_QUERY_MAX_RESULT_LIMIT";
44const DEFAULT_RPC_QUERY_MAX_RESULT_LIMIT: usize = 50;
45
46pub static QUERY_MAX_RESULT_LIMIT: Lazy<usize> = Lazy::new(|| {
47 read_size_from_env(RPC_QUERY_MAX_RESULT_LIMIT).unwrap_or(DEFAULT_RPC_QUERY_MAX_RESULT_LIMIT)
48});
49
50pub const QUERY_MAX_RESULT_LIMIT_CHECKPOINTS: usize = 100;
52
53pub fn cap_page_limit(limit: Option<usize>) -> usize {
54 let limit = limit.unwrap_or_default();
55 if limit > *QUERY_MAX_RESULT_LIMIT || limit == 0 {
56 *QUERY_MAX_RESULT_LIMIT
57 } else {
58 limit
59 }
60}
61
62pub fn validate_limit(limit: Option<usize>, max: usize) -> Result<usize, anyhow::Error> {
63 Ok(match limit {
64 Some(l) if l > max => bail!("Page size limit {l} exceeds max limit {max}"),
65 Some(0) => bail!("Page size limit cannot be smaller than 1"),
66 Some(l) => l,
67 None => max,
68 })
69}
70
71#[derive(Clone)]
72pub struct JsonRpcMetrics {
73 pub get_objects_limit: Histogram,
74 pub get_objects_result_size: Histogram,
75 pub get_objects_result_size_total: IntCounter,
76 pub get_tx_blocks_limit: Histogram,
77 pub get_tx_blocks_result_size: Histogram,
78 pub get_tx_blocks_result_size_total: IntCounter,
79 pub get_checkpoints_limit: Histogram,
80 pub get_checkpoints_result_size: Histogram,
81 pub get_checkpoints_result_size_total: IntCounter,
82 pub get_owned_objects_limit: Histogram,
83 pub get_owned_objects_result_size: Histogram,
84 pub get_owned_objects_result_size_total: IntCounter,
85 pub get_coins_limit: Histogram,
86 pub get_coins_result_size: Histogram,
87 pub get_coins_result_size_total: IntCounter,
88 pub get_dynamic_fields_limit: Histogram,
89 pub get_dynamic_fields_result_size: Histogram,
90 pub get_dynamic_fields_result_size_total: IntCounter,
91 pub query_tx_blocks_limit: Histogram,
92 pub query_tx_blocks_result_size: Histogram,
93 pub query_tx_blocks_result_size_total: IntCounter,
94 pub query_events_limit: Histogram,
95 pub query_events_result_size: Histogram,
96 pub query_events_result_size_total: IntCounter,
97
98 pub get_stake_iota_result_size: Histogram,
99 pub get_stake_iota_result_size_total: IntCounter,
100
101 pub get_stake_iota_latency: Histogram,
102 pub get_delegated_iota_latency: Histogram,
103
104 pub orchestrator_latency_ms: Histogram,
105 pub post_orchestrator_latency_ms: Histogram,
106}
107
108impl JsonRpcMetrics {
109 pub fn new(registry: &prometheus::Registry) -> Self {
110 Self {
111 get_objects_limit: register_histogram_with_registry!(
112 "json_rpc_get_objects_limit",
113 "The input limit for multi_get_objects, after applying the cap",
114 iota_metrics::COUNT_BUCKETS.to_vec(),
115 registry,
116 )
117 .unwrap(),
118 get_objects_result_size: register_histogram_with_registry!(
119 "json_rpc_get_objects_result_size",
120 "The return size for multi_get_objects",
121 iota_metrics::COUNT_BUCKETS.to_vec(),
122 registry,
123 )
124 .unwrap(),
125 get_objects_result_size_total: register_int_counter_with_registry!(
126 "json_rpc_get_objects_result_size_total",
127 "The total return size for multi_get_objects",
128 registry
129 )
130 .unwrap(),
131 get_tx_blocks_limit: register_histogram_with_registry!(
132 "json_rpc_get_tx_blocks_limit",
133 "The input limit for get_tx_blocks, after applying the cap",
134 iota_metrics::COUNT_BUCKETS.to_vec(),
135 registry,
136 )
137 .unwrap(),
138 get_tx_blocks_result_size: register_histogram_with_registry!(
139 "json_rpc_get_tx_blocks_result_size",
140 "The return size for get_tx_blocks",
141 iota_metrics::COUNT_BUCKETS.to_vec(),
142 registry,
143 )
144 .unwrap(),
145 get_tx_blocks_result_size_total: register_int_counter_with_registry!(
146 "json_rpc_get_tx_blocks_result_size_total",
147 "The total return size for get_tx_blocks",
148 registry
149 )
150 .unwrap(),
151 get_checkpoints_limit: register_histogram_with_registry!(
152 "json_rpc_get_checkpoints_limit",
153 "The input limit for get_checkpoints, after applying the cap",
154 iota_metrics::COUNT_BUCKETS.to_vec(),
155 registry,
156 )
157 .unwrap(),
158 get_checkpoints_result_size: register_histogram_with_registry!(
159 "json_rpc_get_checkpoints_result_size",
160 "The return size for get_checkpoints",
161 iota_metrics::COUNT_BUCKETS.to_vec(),
162 registry,
163 )
164 .unwrap(),
165 get_checkpoints_result_size_total: register_int_counter_with_registry!(
166 "json_rpc_get_checkpoints_result_size_total",
167 "The total return size for get_checkpoints",
168 registry
169 )
170 .unwrap(),
171 get_owned_objects_limit: register_histogram_with_registry!(
172 "json_rpc_get_owned_objects_limit",
173 "The input limit for get_owned_objects, after applying the cap",
174 iota_metrics::COUNT_BUCKETS.to_vec(),
175 registry,
176 )
177 .unwrap(),
178 get_owned_objects_result_size: register_histogram_with_registry!(
179 "json_rpc_get_owned_objects_result_size",
180 "The return size for get_owned_objects",
181 iota_metrics::COUNT_BUCKETS.to_vec(),
182 registry,
183 )
184 .unwrap(),
185 get_owned_objects_result_size_total: register_int_counter_with_registry!(
186 "json_rpc_get_owned_objects_result_size_total",
187 "The total return size for get_owned_objects",
188 registry
189 )
190 .unwrap(),
191 get_coins_limit: register_histogram_with_registry!(
192 "json_rpc_get_coins_limit",
193 "The input limit for get_coins, after applying the cap",
194 iota_metrics::COUNT_BUCKETS.to_vec(),
195 registry,
196 )
197 .unwrap(),
198 get_coins_result_size: register_histogram_with_registry!(
199 "json_rpc_get_coins_result_size",
200 "The return size for get_coins",
201 iota_metrics::COUNT_BUCKETS.to_vec(),
202 registry,
203 )
204 .unwrap(),
205 get_coins_result_size_total: register_int_counter_with_registry!(
206 "json_rpc_get_coins_result_size_total",
207 "The total return size for get_coins",
208 registry
209 )
210 .unwrap(),
211 get_dynamic_fields_limit: register_histogram_with_registry!(
212 "json_rpc_get_dynamic_fields_limit",
213 "The input limit for get_dynamic_fields, after applying the cap",
214 iota_metrics::COUNT_BUCKETS.to_vec(),
215 registry,
216 )
217 .unwrap(),
218 get_dynamic_fields_result_size: register_histogram_with_registry!(
219 "json_rpc_get_dynamic_fields_result_size",
220 "The return size for get_dynamic_fields",
221 iota_metrics::COUNT_BUCKETS.to_vec(),
222 registry,
223 )
224 .unwrap(),
225 get_dynamic_fields_result_size_total: register_int_counter_with_registry!(
226 "json_rpc_get_dynamic_fields_result_size_total",
227 "The total return size for get_dynamic_fields",
228 registry
229 )
230 .unwrap(),
231 query_tx_blocks_limit: register_histogram_with_registry!(
232 "json_rpc_query_tx_blocks_limit",
233 "The input limit for query_tx_blocks, after applying the cap",
234 iota_metrics::COUNT_BUCKETS.to_vec(),
235 registry,
236 )
237 .unwrap(),
238 query_tx_blocks_result_size: register_histogram_with_registry!(
239 "json_rpc_query_tx_blocks_result_size",
240 "The return size for query_tx_blocks",
241 iota_metrics::COUNT_BUCKETS.to_vec(),
242 registry,
243 )
244 .unwrap(),
245 query_tx_blocks_result_size_total: register_int_counter_with_registry!(
246 "json_rpc_query_tx_blocks_result_size_total",
247 "The total return size for query_tx_blocks",
248 registry
249 )
250 .unwrap(),
251 query_events_limit: register_histogram_with_registry!(
252 "json_rpc_query_events_limit",
253 "The input limit for query_events, after applying the cap",
254 iota_metrics::COUNT_BUCKETS.to_vec(),
255 registry,
256 )
257 .unwrap(),
258 query_events_result_size: register_histogram_with_registry!(
259 "json_rpc_query_events_result_size",
260 "The return size for query_events",
261 iota_metrics::COUNT_BUCKETS.to_vec(),
262 registry,
263 )
264 .unwrap(),
265 query_events_result_size_total: register_int_counter_with_registry!(
266 "json_rpc_query_events_result_size_total",
267 "The total return size for query_events",
268 registry
269 )
270 .unwrap(),
271 get_stake_iota_result_size: register_histogram_with_registry!(
272 "json_rpc_get_stake_iota_result_size",
273 "The return size for get_stake_iota",
274 iota_metrics::COUNT_BUCKETS.to_vec(),
275 registry,
276 )
277 .unwrap(),
278 get_stake_iota_result_size_total: register_int_counter_with_registry!(
279 "json_rpc_get_stake_iota_result_size_total",
280 "The total return size for get_stake_iota",
281 registry
282 )
283 .unwrap(),
284 get_stake_iota_latency: register_histogram_with_registry!(
285 "get_stake_iota_latency",
286 "The latency of get stake iota, in ms",
287 iota_metrics::COARSE_LATENCY_SEC_BUCKETS.to_vec(),
288 registry,
289 )
290 .unwrap(),
291 get_delegated_iota_latency: register_histogram_with_registry!(
292 "get_delegated_iota_latency",
293 "The latency of get delegated iota, in ms",
294 iota_metrics::COARSE_LATENCY_SEC_BUCKETS.to_vec(),
295 registry,
296 )
297 .unwrap(),
298 orchestrator_latency_ms: register_histogram_with_registry!(
299 "json_rpc_orchestrator_latency",
300 "The latency of submitting transaction via transaction orchestrator, in ms",
301 iota_metrics::COARSE_LATENCY_SEC_BUCKETS.to_vec(),
302 registry,
303 )
304 .unwrap(),
305 post_orchestrator_latency_ms: register_histogram_with_registry!(
306 "json_rpc_post_orchestrator_latency",
307 "The latency of response processing after transaction orchestrator, in ms",
308 iota_metrics::COARSE_LATENCY_SEC_BUCKETS.to_vec(),
309 registry,
310 )
311 .unwrap(),
312 }
313 }
314
315 pub fn new_for_tests() -> Self {
316 let registry = prometheus::Registry::new();
317 Self::new(®istry)
318 }
319}
320
321pub fn read_size_from_env(var_name: &str) -> Option<usize> {
322 std::env::var(var_name)
323 .ok()?
324 .parse::<usize>()
325 .tap_err(|e| {
326 warn!(
327 "Env var {} does not contain valid usize integer: {}",
328 var_name, e
329 )
330 })
331 .ok()
332}
333
334pub const CLIENT_SDK_TYPE_HEADER: &str = "client-sdk-type";
335pub const CLIENT_SDK_VERSION_HEADER: &str = "client-sdk-version";
338pub const CLIENT_TARGET_API_VERSION_HEADER: &str = "client-target-api-version";
341
342pub const TRANSIENT_ERROR_CODE: i32 = -32050;
343pub const TRANSACTION_EXECUTION_CLIENT_ERROR_CODE: i32 = -32002;
344
345pub fn error_object_from_rpc(rpc_err: ClientError) -> ErrorObjectOwned {
347 match rpc_err {
348 ClientError::Call(e) => e,
349 _ => ErrorObjectOwned::owned::<()>(UNKNOWN_ERROR_CODE, rpc_err.to_string(), None),
350 }
351}
352
353pub fn internal_error(err: impl ToString) -> ErrorObjectOwned {
355 ErrorObjectOwned::owned::<()>(INTERNAL_ERROR_CODE, err.to_string(), None)
356}