1use anyhow::Context as _;
5use jsonrpsee::http_client::HeaderMap;
6use jsonrpsee::http_client::HeaderValue;
7use jsonrpsee::http_client::HttpClient;
8use jsonrpsee::http_client::HttpClientBuilder;
9use sui_default_config::DefaultConfig;
10use sui_protocol_config::ProtocolConfig;
11use sui_types::base_types::ObjectID;
12use sui_types::base_types::SuiAddress;
13
14pub use sui_name_service::NameServiceConfig;
15
16pub const CLIENT_SDK_TYPE_HEADER: &str = "client-sdk-type";
17
18#[derive(Debug)]
19pub struct RpcConfig {
20 pub objects: ObjectsConfig,
22
23 pub dynamic_fields: DynamicFieldsConfig,
25
26 pub transactions: TransactionsConfig,
28
29 pub name_service: NameServiceConfig,
31
32 pub coins: CoinsConfig,
34
35 pub node: NodeConfig,
38
39 pub package_resolver: sui_package_resolver::Limits,
41}
42
43#[DefaultConfig]
44#[derive(Clone, Default, Debug)]
45#[serde(deny_unknown_fields)]
46pub struct RpcLayer {
47 pub objects: ObjectsLayer,
48 pub dynamic_fields: DynamicFieldsLayer,
49 pub transactions: TransactionsLayer,
50 pub name_service: NameServiceLayer,
51 pub coins: CoinsLayer,
52 pub node: NodeLayer,
53 pub package_resolver: PackageResolverLayer,
54}
55
56#[derive(Debug, Clone)]
57pub struct ObjectsConfig {
58 pub max_multi_get_objects: usize,
60
61 pub default_page_size: usize,
63
64 pub max_page_size: usize,
67
68 pub max_display_field_depth: usize,
70
71 pub max_display_format_nodes: usize,
73
74 pub max_display_object_loads: usize,
76
77 pub max_display_output_size: usize,
79
80 pub max_filter_depth: usize,
82
83 pub max_type_filters: usize,
85
86 pub filter_scan_size: usize,
89
90 pub obj_retry_count: usize,
93
94 pub obj_retry_interval_ms: u64,
96}
97
98#[DefaultConfig]
99#[derive(Clone, Default, Debug)]
100#[serde(deny_unknown_fields)]
101pub struct ObjectsLayer {
102 pub max_multi_get_objects: Option<usize>,
103 pub default_page_size: Option<usize>,
104 pub max_page_size: Option<usize>,
105 pub max_display_field_depth: Option<usize>,
106 pub max_display_format_nodes: Option<usize>,
107 pub max_display_object_loads: Option<usize>,
108 pub max_display_output_size: Option<usize>,
109 pub max_filter_depth: Option<usize>,
110 pub max_type_filters: Option<usize>,
111 pub filter_scan_size: Option<usize>,
112 pub obj_retry_count: Option<usize>,
113 pub obj_retry_interval_ms: Option<u64>,
114}
115
116#[derive(Debug, Clone)]
117pub struct DynamicFieldsConfig {
118 pub default_page_size: usize,
120
121 pub max_page_size: usize,
124}
125
126#[DefaultConfig]
127#[derive(Clone, Default, Debug)]
128#[serde(deny_unknown_fields)]
129pub struct DynamicFieldsLayer {
130 pub default_page_size: Option<usize>,
131 pub max_page_size: Option<usize>,
132}
133
134#[derive(Debug, Clone)]
135pub struct TransactionsConfig {
136 pub default_page_size: usize,
138
139 pub max_page_size: usize,
142
143 pub tx_retry_count: usize,
146
147 pub tx_retry_interval_ms: u64,
149}
150
151#[DefaultConfig]
152#[derive(Clone, Default, Debug)]
153#[serde(deny_unknown_fields)]
154pub struct TransactionsLayer {
155 pub default_page_size: Option<usize>,
156 pub max_page_size: Option<usize>,
157 pub tx_retry_count: Option<usize>,
158 pub tx_retry_interval_ms: Option<u64>,
159}
160
161#[DefaultConfig]
162#[derive(Clone, Default, Debug)]
163#[serde(deny_unknown_fields)]
164pub struct NameServiceLayer {
165 pub package_address: Option<SuiAddress>,
166 pub registry_id: Option<ObjectID>,
167 pub reverse_registry_id: Option<ObjectID>,
168}
169
170#[derive(Debug, Clone)]
171pub struct CoinsConfig {
172 pub default_page_size: usize,
174
175 pub max_page_size: usize,
178}
179
180#[DefaultConfig]
181#[derive(Clone, Default, Debug)]
182#[serde(deny_unknown_fields)]
183pub struct CoinsLayer {
184 pub default_page_size: Option<usize>,
185 pub max_page_size: Option<usize>,
186}
187
188#[derive(Clone, Debug)]
189pub struct NodeConfig {
190 pub header_value: String,
192 pub max_request_size: u32,
194}
195
196#[DefaultConfig]
197#[derive(Clone, Default, Debug)]
198#[serde(deny_unknown_fields)]
199pub struct NodeLayer {
200 pub header_value: Option<String>,
201 pub max_request_size: Option<u32>,
202}
203
204#[DefaultConfig]
205#[derive(Clone, Debug)]
206#[serde(deny_unknown_fields)]
207pub struct PackageResolverLayer {
208 pub max_type_argument_depth: usize,
209 pub max_type_argument_width: usize,
210 pub max_type_nodes: usize,
211 pub max_move_value_depth: usize,
212}
213
214impl RpcLayer {
215 pub fn example() -> Self {
218 Self {
219 objects: ObjectsConfig::default().into(),
220 dynamic_fields: DynamicFieldsConfig::default().into(),
221 transactions: TransactionsConfig::default().into(),
222 name_service: NameServiceConfig::default().into(),
223 coins: CoinsConfig::default().into(),
224 package_resolver: PackageResolverLayer::default(),
225 node: NodeConfig::default().into(),
226 }
227 }
228
229 pub fn finish(self) -> RpcConfig {
230 RpcConfig {
231 objects: self.objects.finish(ObjectsConfig::default()),
232 dynamic_fields: self.dynamic_fields.finish(DynamicFieldsConfig::default()),
233 transactions: self.transactions.finish(TransactionsConfig::default()),
234 name_service: self.name_service.finish(NameServiceConfig::default()),
235 coins: self.coins.finish(CoinsConfig::default()),
236 node: self.node.finish(NodeConfig::default()),
237 package_resolver: self.package_resolver.finish(),
238 }
239 }
240}
241
242impl ObjectsLayer {
243 pub fn finish(self, base: ObjectsConfig) -> ObjectsConfig {
244 ObjectsConfig {
245 max_multi_get_objects: self
246 .max_multi_get_objects
247 .unwrap_or(base.max_multi_get_objects),
248 default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
249 max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
250 max_display_field_depth: self
251 .max_display_field_depth
252 .unwrap_or(base.max_display_field_depth),
253 max_display_format_nodes: self
254 .max_display_format_nodes
255 .unwrap_or(base.max_display_format_nodes),
256 max_display_object_loads: self
257 .max_display_object_loads
258 .unwrap_or(base.max_display_object_loads),
259 max_display_output_size: self
260 .max_display_output_size
261 .unwrap_or(base.max_display_output_size),
262 max_filter_depth: self.max_filter_depth.unwrap_or(base.max_filter_depth),
263 max_type_filters: self.max_type_filters.unwrap_or(base.max_type_filters),
264 filter_scan_size: self.filter_scan_size.unwrap_or(base.filter_scan_size),
265 obj_retry_count: self.obj_retry_count.unwrap_or(base.obj_retry_count),
266 obj_retry_interval_ms: self
267 .obj_retry_interval_ms
268 .unwrap_or(base.obj_retry_interval_ms),
269 }
270 }
271}
272
273impl DynamicFieldsLayer {
274 pub fn finish(self, base: DynamicFieldsConfig) -> DynamicFieldsConfig {
275 DynamicFieldsConfig {
276 default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
277 max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
278 }
279 }
280}
281
282impl TransactionsLayer {
283 pub fn finish(self, base: TransactionsConfig) -> TransactionsConfig {
284 TransactionsConfig {
285 default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
286 max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
287 tx_retry_count: self.tx_retry_count.unwrap_or(base.tx_retry_count),
288 tx_retry_interval_ms: self
289 .tx_retry_interval_ms
290 .unwrap_or(base.tx_retry_interval_ms),
291 }
292 }
293}
294
295impl NameServiceLayer {
296 pub fn finish(self, base: NameServiceConfig) -> NameServiceConfig {
297 NameServiceConfig {
298 package_address: self.package_address.unwrap_or(base.package_address),
299 registry_id: self.registry_id.unwrap_or(base.registry_id),
300 reverse_registry_id: self.reverse_registry_id.unwrap_or(base.reverse_registry_id),
301 }
302 }
303}
304
305impl CoinsLayer {
306 pub fn finish(self, base: CoinsConfig) -> CoinsConfig {
307 CoinsConfig {
308 default_page_size: self.default_page_size.unwrap_or(base.default_page_size),
309 max_page_size: self.max_page_size.unwrap_or(base.max_page_size),
310 }
311 }
312}
313
314impl NodeConfig {
315 pub fn client(&self, fullnode_rpc_url: url::Url) -> anyhow::Result<HttpClient> {
316 let mut headers = HeaderMap::new();
317 headers.insert(
318 CLIENT_SDK_TYPE_HEADER,
319 HeaderValue::from_str(&self.header_value)?,
320 );
321
322 HttpClientBuilder::default()
323 .max_request_size(self.max_request_size)
324 .set_headers(headers)
325 .build(&fullnode_rpc_url)
326 .context("Failed to initialize fullnode RPC client")
327 }
328}
329
330impl NodeLayer {
331 pub fn finish(self, base: NodeConfig) -> NodeConfig {
332 NodeConfig {
333 header_value: self.header_value.unwrap_or(base.header_value),
334 max_request_size: self.max_request_size.unwrap_or(base.max_request_size),
335 }
336 }
337}
338
339impl PackageResolverLayer {
340 pub fn finish(self) -> sui_package_resolver::Limits {
341 sui_package_resolver::Limits {
342 max_type_argument_depth: self.max_type_argument_depth,
343 max_type_argument_width: self.max_type_argument_width,
344 max_type_nodes: self.max_type_nodes,
345 max_move_value_depth: self.max_move_value_depth,
346 }
347 }
348}
349
350impl Default for RpcConfig {
351 fn default() -> Self {
352 Self {
353 objects: ObjectsConfig::default(),
354 dynamic_fields: DynamicFieldsConfig::default(),
355 transactions: TransactionsConfig::default(),
356 name_service: NameServiceConfig::default(),
357 coins: CoinsConfig::default(),
358 node: NodeConfig::default(),
359 package_resolver: PackageResolverLayer::default().finish(),
360 }
361 }
362}
363
364impl Default for ObjectsConfig {
365 fn default() -> Self {
366 let display_limits = sui_display::v2::Limits::default();
367
368 Self {
369 max_multi_get_objects: 50,
370 default_page_size: 50,
371 max_page_size: 100,
372 max_display_field_depth: display_limits.max_depth,
373 max_display_format_nodes: display_limits.max_nodes,
374 max_display_object_loads: display_limits.max_loads,
375 max_display_output_size: 1024 * 1024,
376 max_filter_depth: 3,
377 max_type_filters: 10,
378 filter_scan_size: 200,
379 obj_retry_count: 5,
380 obj_retry_interval_ms: 100,
381 }
382 }
383}
384
385impl Default for DynamicFieldsConfig {
386 fn default() -> Self {
387 Self {
388 default_page_size: 50,
389 max_page_size: 100,
390 }
391 }
392}
393
394impl Default for TransactionsConfig {
395 fn default() -> Self {
396 Self {
397 default_page_size: 50,
398 max_page_size: 100,
399 tx_retry_count: 5,
400 tx_retry_interval_ms: 100,
401 }
402 }
403}
404
405impl Default for CoinsConfig {
406 fn default() -> Self {
407 Self {
408 default_page_size: 50,
409 max_page_size: 100,
410 }
411 }
412}
413
414impl Default for NodeConfig {
415 fn default() -> Self {
416 Self {
417 header_value: "sui-indexer-alt-jsonrpc".to_string(),
418 max_request_size: (10 * 2) << 20, }
420 }
421}
422
423impl Default for PackageResolverLayer {
424 fn default() -> Self {
425 let config = ProtocolConfig::get_for_max_version_UNSAFE();
429
430 Self {
431 max_type_argument_depth: config.max_type_argument_depth() as usize,
432 max_type_argument_width: config.max_generic_instantiation_length() as usize,
433 max_type_nodes: config.max_type_nodes() as usize,
434 max_move_value_depth: config.max_move_value_depth() as usize,
435 }
436 }
437}
438
439impl From<ObjectsConfig> for ObjectsLayer {
440 fn from(config: ObjectsConfig) -> Self {
441 Self {
442 max_multi_get_objects: Some(config.max_multi_get_objects),
443 default_page_size: Some(config.default_page_size),
444 max_page_size: Some(config.max_page_size),
445 max_display_field_depth: Some(config.max_display_field_depth),
446 max_display_format_nodes: Some(config.max_display_format_nodes),
447 max_display_object_loads: Some(config.max_display_object_loads),
448 max_display_output_size: Some(config.max_display_output_size),
449 max_filter_depth: Some(config.max_filter_depth),
450 max_type_filters: Some(config.max_type_filters),
451 filter_scan_size: Some(config.filter_scan_size),
452 obj_retry_count: Some(config.obj_retry_count),
453 obj_retry_interval_ms: Some(config.obj_retry_interval_ms),
454 }
455 }
456}
457
458impl ObjectsConfig {
459 pub(crate) fn display(&self) -> sui_display::v2::Limits {
460 sui_display::v2::Limits {
461 max_depth: self.max_display_field_depth,
462 max_nodes: self.max_display_format_nodes,
463 max_loads: self.max_display_object_loads,
464 }
465 }
466}
467
468impl From<DynamicFieldsConfig> for DynamicFieldsLayer {
469 fn from(config: DynamicFieldsConfig) -> 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<TransactionsConfig> for TransactionsLayer {
478 fn from(config: TransactionsConfig) -> Self {
479 Self {
480 default_page_size: Some(config.default_page_size),
481 max_page_size: Some(config.max_page_size),
482 tx_retry_count: Some(config.tx_retry_count),
483 tx_retry_interval_ms: Some(config.tx_retry_interval_ms),
484 }
485 }
486}
487
488impl From<NameServiceConfig> for NameServiceLayer {
489 fn from(config: NameServiceConfig) -> Self {
490 Self {
491 package_address: Some(config.package_address),
492 registry_id: Some(config.registry_id),
493 reverse_registry_id: Some(config.reverse_registry_id),
494 }
495 }
496}
497
498impl From<CoinsConfig> for CoinsLayer {
499 fn from(config: CoinsConfig) -> Self {
500 Self {
501 default_page_size: Some(config.default_page_size),
502 max_page_size: Some(config.max_page_size),
503 }
504 }
505}
506
507impl From<NodeConfig> for NodeLayer {
508 fn from(config: NodeConfig) -> Self {
509 Self {
510 header_value: Some(config.header_value),
511 max_request_size: Some(config.max_request_size),
512 }
513 }
514}