sui_json_rpc_api/
lib.rs

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