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