Skip to main content

sui_indexer_alt_jsonrpc/
config.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use serde::Deserialize;
5use serde::Serialize;
6use sui_protocol_config::ProtocolConfig;
7use sui_types::base_types::ObjectID;
8use sui_types::base_types::SuiAddress;
9
10pub use sui_name_service::NameServiceConfig;
11
12#[derive(Debug)]
13pub struct RpcConfig {
14    /// Configuration for object-related RPC methods.
15    pub objects: ObjectsConfig,
16
17    /// Configuration for dynamic-field-related RPC methods.
18    pub dynamic_fields: DynamicFieldsConfig,
19
20    /// Configuration for transaction-related RPC methods.
21    pub transactions: TransactionsConfig,
22
23    /// Configuration for SuiNS related RPC methods.
24    pub name_service: NameServiceConfig,
25
26    /// Configuration for coin-related RPC methods.
27    pub coins: CoinsConfig,
28
29    /// Configuration for methods that require a fullnode RPC connection,
30    /// including transaction execution, dry-running, and delegation coin queries etc.
31    pub node: NodeConfig,
32
33    /// Configuring limits for the package resolver.
34    pub package_resolver: sui_package_resolver::Limits,
35}
36
37#[derive(Clone, Default, Debug, Deserialize, Serialize)]
38#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
39pub struct RpcLayer {
40    pub objects: ObjectsLayer,
41    pub dynamic_fields: DynamicFieldsLayer,
42    pub transactions: TransactionsLayer,
43    pub name_service: NameServiceLayer,
44    pub coins: CoinsLayer,
45    pub node: NodeLayer,
46    pub package_resolver: PackageResolverLayer,
47}
48
49#[derive(Debug, Clone)]
50pub struct ObjectsConfig {
51    /// The maximum number of keys that can be queried in a single multi-get request.
52    pub max_multi_get_objects: usize,
53
54    /// The default page size limit when querying objects, if none is provided.
55    pub default_page_size: usize,
56
57    /// The largest acceptable page size when querying objects. Requesting a page larger than
58    /// this is a user error.
59    pub max_page_size: usize,
60
61    /// The maximum depth a Display format string is allowed to nest field accesses.
62    pub max_display_field_depth: usize,
63
64    /// The maximum number of components in a Display v2 format string.
65    pub max_display_format_nodes: usize,
66
67    /// The maximum number of objects that can be loaded while evaluating a Display v2 format.
68    pub max_display_object_loads: usize,
69
70    /// The maximum number of bytes occupied by Display field names and values in the output.
71    pub max_display_output_size: usize,
72
73    /// The maximum nesting depth of an owned object filter.
74    pub max_filter_depth: usize,
75
76    /// The maximum number of type filters in an owned object filter.
77    pub max_type_filters: usize,
78
79    /// The number of owned objects to fetch in one go when fulfilling a compound owned object
80    /// filter.
81    pub filter_scan_size: usize,
82
83    /// The number of times to retry a kv get operation. Retry is needed when a version of the object
84    /// is not yet found in the kv store due to the kv being behind the pg table's checkpoint watermark.
85    pub obj_retry_count: usize,
86
87    /// The interval between kv retry attempts in milliseconds.
88    pub obj_retry_interval_ms: u64,
89}
90
91#[derive(Clone, Default, Debug, Deserialize, Serialize)]
92#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
93pub struct ObjectsLayer {
94    pub max_multi_get_objects: Option<usize>,
95    pub default_page_size: Option<usize>,
96    pub max_page_size: Option<usize>,
97    pub max_display_field_depth: Option<usize>,
98    pub max_display_format_nodes: Option<usize>,
99    pub max_display_object_loads: Option<usize>,
100    pub max_display_output_size: Option<usize>,
101    pub max_filter_depth: Option<usize>,
102    pub max_type_filters: Option<usize>,
103    pub filter_scan_size: Option<usize>,
104    pub obj_retry_count: Option<usize>,
105    pub obj_retry_interval_ms: Option<u64>,
106}
107
108#[derive(Debug, Clone)]
109pub struct DynamicFieldsConfig {
110    /// The default page size limit when querying dynamic fields, if none is provided.
111    pub default_page_size: usize,
112
113    /// The largest acceptable page size when querying dynamic fields. Requesting a page larger
114    /// than this is a user error.
115    pub max_page_size: usize,
116}
117
118#[derive(Clone, Default, Debug, Deserialize, Serialize)]
119#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
120pub struct DynamicFieldsLayer {
121    pub default_page_size: Option<usize>,
122    pub max_page_size: Option<usize>,
123}
124
125#[derive(Debug, Clone)]
126pub struct TransactionsConfig {
127    /// The default page size limit when querying transactions, if none is provided.
128    pub default_page_size: usize,
129
130    /// The largest acceptable page size when querying transactions. Requesting a page larger than
131    /// this is a user error.
132    pub max_page_size: usize,
133
134    /// The number of times to retry a read from kv or pg transaction tables. Retry is needed when a tx digest
135    /// is not yet found in the table due to it being behind other transaction table's checkpoint watermark.
136    pub tx_retry_count: usize,
137
138    /// The interval between tx_digest retry attempts in milliseconds.
139    pub tx_retry_interval_ms: u64,
140}
141
142#[derive(Clone, Default, Debug, Deserialize, Serialize)]
143#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
144pub struct TransactionsLayer {
145    pub default_page_size: Option<usize>,
146    pub max_page_size: Option<usize>,
147    pub tx_retry_count: Option<usize>,
148    pub tx_retry_interval_ms: Option<u64>,
149}
150
151#[derive(Clone, Default, Debug, Deserialize, Serialize)]
152#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
153pub struct NameServiceLayer {
154    pub package_address: Option<SuiAddress>,
155    pub registry_id: Option<ObjectID>,
156    pub reverse_registry_id: Option<ObjectID>,
157}
158
159#[derive(Debug, Clone)]
160pub struct CoinsConfig {
161    /// The default page size limit when querying coins, if none is provided.
162    pub default_page_size: usize,
163
164    /// The largest acceptable page size when querying coins. Requesting a page larger than
165    /// this is a user error.
166    pub max_page_size: usize,
167}
168
169#[derive(Clone, Default, Debug, Deserialize, Serialize)]
170#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
171pub struct CoinsLayer {
172    pub default_page_size: Option<usize>,
173    pub max_page_size: Option<usize>,
174}
175
176#[derive(Clone, Debug)]
177pub struct NodeConfig {
178    /// The value of the header to be sent to the fullnode RPC, used to distinguish between different instances.
179    pub header_value: String,
180    /// The maximum size of the request body allowed.
181    pub max_request_size: u32,
182}
183
184#[derive(Clone, Default, Debug, Deserialize, Serialize)]
185#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
186pub struct NodeLayer {
187    pub header_value: Option<String>,
188    pub max_request_size: Option<u32>,
189}
190
191#[derive(Clone, Debug, Deserialize, Serialize)]
192#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
193pub struct PackageResolverLayer {
194    pub max_type_argument_depth: usize,
195    pub max_type_argument_width: usize,
196    pub max_type_nodes: usize,
197    pub max_move_value_depth: usize,
198}
199
200impl RpcLayer {
201    /// Generate an example configuration, suitable for demonstrating the fields available to
202    /// configure.
203    pub fn example() -> Self {
204        Self {
205            objects: ObjectsConfig::default().into(),
206            dynamic_fields: DynamicFieldsConfig::default().into(),
207            transactions: TransactionsConfig::default().into(),
208            name_service: NameServiceConfig::default().into(),
209            coins: CoinsConfig::default().into(),
210            package_resolver: PackageResolverLayer::default(),
211            node: NodeConfig::default().into(),
212        }
213    }
214
215    pub fn finish(self) -> RpcConfig {
216        RpcConfig {
217            objects: self.objects.finish(ObjectsConfig::default()),
218            dynamic_fields: self.dynamic_fields.finish(DynamicFieldsConfig::default()),
219            transactions: self.transactions.finish(TransactionsConfig::default()),
220            name_service: self.name_service.finish(NameServiceConfig::default()),
221            coins: self.coins.finish(CoinsConfig::default()),
222            node: self.node.finish(NodeConfig::default()),
223            package_resolver: self.package_resolver.finish(),
224        }
225    }
226}
227
228impl ObjectsLayer {
229    pub fn finish(self, base: ObjectsConfig) -> ObjectsConfig {
230        ObjectsConfig {
231            max_multi_get_objects: self
232                .max_multi_get_objects
233                .unwrap_or(base.max_multi_get_objects),
234            default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
235            max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
236            max_display_field_depth: self
237                .max_display_field_depth
238                .unwrap_or(base.max_display_field_depth),
239            max_display_format_nodes: self
240                .max_display_format_nodes
241                .unwrap_or(base.max_display_format_nodes),
242            max_display_object_loads: self
243                .max_display_object_loads
244                .unwrap_or(base.max_display_object_loads),
245            max_display_output_size: self
246                .max_display_output_size
247                .unwrap_or(base.max_display_output_size),
248            max_filter_depth: self.max_filter_depth.unwrap_or(base.max_filter_depth),
249            max_type_filters: self.max_type_filters.unwrap_or(base.max_type_filters),
250            filter_scan_size: self.filter_scan_size.unwrap_or(base.filter_scan_size),
251            obj_retry_count: self.obj_retry_count.unwrap_or(base.obj_retry_count),
252            obj_retry_interval_ms: self
253                .obj_retry_interval_ms
254                .unwrap_or(base.obj_retry_interval_ms),
255        }
256    }
257}
258
259impl DynamicFieldsLayer {
260    pub fn finish(self, base: DynamicFieldsConfig) -> DynamicFieldsConfig {
261        DynamicFieldsConfig {
262            default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
263            max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
264        }
265    }
266}
267
268impl TransactionsLayer {
269    pub fn finish(self, base: TransactionsConfig) -> TransactionsConfig {
270        TransactionsConfig {
271            default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
272            max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
273            tx_retry_count: self.tx_retry_count.unwrap_or(base.tx_retry_count),
274            tx_retry_interval_ms: self
275                .tx_retry_interval_ms
276                .unwrap_or(base.tx_retry_interval_ms),
277        }
278    }
279}
280
281impl NameServiceLayer {
282    pub fn finish(self, base: NameServiceConfig) -> NameServiceConfig {
283        NameServiceConfig {
284            package_address: self.package_address.unwrap_or(base.package_address),
285            registry_id: self.registry_id.unwrap_or(base.registry_id),
286            reverse_registry_id: self.reverse_registry_id.unwrap_or(base.reverse_registry_id),
287        }
288    }
289}
290
291impl CoinsLayer {
292    pub fn finish(self, base: CoinsConfig) -> CoinsConfig {
293        CoinsConfig {
294            default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
295            max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
296        }
297    }
298}
299
300impl NodeLayer {
301    pub fn finish(self, base: NodeConfig) -> NodeConfig {
302        NodeConfig {
303            header_value: self.header_value.unwrap_or(base.header_value),
304            max_request_size: self.max_request_size.unwrap_or(base.max_request_size),
305        }
306    }
307}
308
309impl PackageResolverLayer {
310    pub fn finish(self) -> sui_package_resolver::Limits {
311        sui_package_resolver::Limits {
312            max_type_argument_depth: self.max_type_argument_depth,
313            max_type_argument_width: self.max_type_argument_width,
314            max_type_nodes: self.max_type_nodes,
315            max_move_value_depth: self.max_move_value_depth,
316        }
317    }
318}
319
320impl Default for RpcConfig {
321    fn default() -> Self {
322        Self {
323            objects: ObjectsConfig::default(),
324            dynamic_fields: DynamicFieldsConfig::default(),
325            transactions: TransactionsConfig::default(),
326            name_service: NameServiceConfig::default(),
327            coins: CoinsConfig::default(),
328            node: NodeConfig::default(),
329            package_resolver: PackageResolverLayer::default().finish(),
330        }
331    }
332}
333
334impl Default for ObjectsConfig {
335    fn default() -> Self {
336        let display_limits = sui_display::v2::Limits::default();
337
338        Self {
339            max_multi_get_objects: 50,
340            default_page_size: 50,
341            max_page_size: 100,
342            max_display_field_depth: display_limits.max_depth,
343            max_display_format_nodes: display_limits.max_nodes,
344            max_display_object_loads: display_limits.max_loads,
345            max_display_output_size: 1024 * 1024,
346            max_filter_depth: 3,
347            max_type_filters: 10,
348            filter_scan_size: 200,
349            obj_retry_count: 5,
350            obj_retry_interval_ms: 100,
351        }
352    }
353}
354
355impl Default for DynamicFieldsConfig {
356    fn default() -> Self {
357        Self {
358            default_page_size: 50,
359            max_page_size: 100,
360        }
361    }
362}
363
364impl Default for TransactionsConfig {
365    fn default() -> Self {
366        Self {
367            default_page_size: 50,
368            max_page_size: 100,
369            tx_retry_count: 5,
370            tx_retry_interval_ms: 100,
371        }
372    }
373}
374
375impl Default for CoinsConfig {
376    fn default() -> Self {
377        Self {
378            default_page_size: 50,
379            max_page_size: 100,
380        }
381    }
382}
383
384impl Default for NodeConfig {
385    fn default() -> Self {
386        Self {
387            header_value: "sui-indexer-alt-jsonrpc".to_string(),
388            max_request_size: (10 * 2) << 20, // 10MB
389        }
390    }
391}
392
393impl Default for PackageResolverLayer {
394    fn default() -> Self {
395        // SAFETY: Accessing the max supported config by the binary (and disregarding specific
396        // chain state) is a safe operation for the RPC because we are only using this to set
397        // default values which can be overridden by configuration.
398        let config = ProtocolConfig::get_for_max_version_UNSAFE();
399
400        Self {
401            max_type_argument_depth: config.max_type_argument_depth() as usize,
402            max_type_argument_width: config.max_generic_instantiation_length() as usize,
403            max_type_nodes: config.max_type_nodes() as usize,
404            max_move_value_depth: config.max_move_value_depth() as usize,
405        }
406    }
407}
408
409impl From<ObjectsConfig> for ObjectsLayer {
410    fn from(config: ObjectsConfig) -> Self {
411        Self {
412            max_multi_get_objects: Some(config.max_multi_get_objects),
413            default_page_size: Some(config.default_page_size),
414            max_page_size: Some(config.max_page_size),
415            max_display_field_depth: Some(config.max_display_field_depth),
416            max_display_format_nodes: Some(config.max_display_format_nodes),
417            max_display_object_loads: Some(config.max_display_object_loads),
418            max_display_output_size: Some(config.max_display_output_size),
419            max_filter_depth: Some(config.max_filter_depth),
420            max_type_filters: Some(config.max_type_filters),
421            filter_scan_size: Some(config.filter_scan_size),
422            obj_retry_count: Some(config.obj_retry_count),
423            obj_retry_interval_ms: Some(config.obj_retry_interval_ms),
424        }
425    }
426}
427
428impl ObjectsConfig {
429    pub(crate) fn display(&self) -> sui_display::v2::Limits {
430        sui_display::v2::Limits {
431            max_depth: self.max_display_field_depth,
432            max_nodes: self.max_display_format_nodes,
433            max_loads: self.max_display_object_loads,
434        }
435    }
436}
437
438impl From<DynamicFieldsConfig> for DynamicFieldsLayer {
439    fn from(config: DynamicFieldsConfig) -> Self {
440        Self {
441            default_page_size: Some(config.default_page_size),
442            max_page_size: Some(config.max_page_size),
443        }
444    }
445}
446
447impl From<TransactionsConfig> for TransactionsLayer {
448    fn from(config: TransactionsConfig) -> Self {
449        Self {
450            default_page_size: Some(config.default_page_size),
451            max_page_size: Some(config.max_page_size),
452            tx_retry_count: Some(config.tx_retry_count),
453            tx_retry_interval_ms: Some(config.tx_retry_interval_ms),
454        }
455    }
456}
457
458impl From<NameServiceConfig> for NameServiceLayer {
459    fn from(config: NameServiceConfig) -> Self {
460        Self {
461            package_address: Some(config.package_address),
462            registry_id: Some(config.registry_id),
463            reverse_registry_id: Some(config.reverse_registry_id),
464        }
465    }
466}
467
468impl From<CoinsConfig> for CoinsLayer {
469    fn from(config: CoinsConfig) -> Self {
470        Self {
471            default_page_size: Some(config.default_page_size),
472            max_page_size: Some(config.max_page_size),
473        }
474    }
475}
476
477impl From<NodeConfig> for NodeLayer {
478    fn from(config: NodeConfig) -> Self {
479        Self {
480            header_value: Some(config.header_value),
481            max_request_size: Some(config.max_request_size),
482        }
483    }
484}