Skip to main content

soil_cli/
config.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Configuration trait for a CLI based on substrate
8
9use crate::{
10	arg_enums::Database, error::Result, DatabaseParams, ImportParams, KeystoreParams,
11	NetworkParams, NodeKeyParams, OffchainWorkerParams, PruningParams, RpcEndpoint, SharedParams,
12	SubstrateCli,
13};
14use log::warn;
15use names::{Generator, Name};
16use soil_client::tracing::logging::LoggerBuilder;
17use soil_service::{
18	config::{
19		BasePath, Configuration, DatabaseSource, ExecutorConfiguration, IpNetwork, KeystoreConfig,
20		NetworkConfiguration, NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode,
21		Role, RpcBatchRequestConfig, RpcConfiguration, RpcMethods, TelemetryEndpoints,
22		TransactionPoolOptions, WasmExecutionMethod,
23	},
24	BlocksPruning, ChainSpec, TracingReceiver,
25};
26use std::{num::NonZeroU32, path::PathBuf};
27
28/// The maximum number of characters for a node name.
29pub(crate) const NODE_NAME_MAX_LENGTH: usize = 64;
30
31/// Default sub directory to store network config.
32pub(crate) const DEFAULT_NETWORK_CONFIG_PATH: &str = "network";
33
34/// The recommended open file descriptor limit to be configured for the process.
35const RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT: u64 = 10_000;
36
37/// The default port.
38pub const RPC_DEFAULT_PORT: u16 = 9944;
39/// The default max number of subscriptions per connection.
40pub const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
41/// The default max request size in MB.
42pub const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
43/// The default max response size in MB.
44pub const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 15;
45/// The default concurrent connection limit.
46pub const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 100;
47/// The default number of messages the RPC server
48/// is allowed to keep in memory per connection.
49pub const RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN: u32 = 64;
50
51/// Default configuration values used by Substrate
52///
53/// These values will be used by [`CliConfiguration`] to set
54/// default values for e.g. the listen port or the RPC port.
55pub trait DefaultConfigurationValues {
56	/// The port Substrate should listen on for p2p connections.
57	///
58	/// By default this is `30333`.
59	fn p2p_listen_port() -> u16 {
60		30333
61	}
62
63	/// The port Substrate should listen on for JSON-RPC connections.
64	///
65	/// By default this is `9944`.
66	fn rpc_listen_port() -> u16 {
67		RPC_DEFAULT_PORT
68	}
69
70	/// The port Substrate should listen on for prometheus connections.
71	///
72	/// By default this is `9615`.
73	fn prometheus_listen_port() -> u16 {
74		9615
75	}
76}
77
78impl DefaultConfigurationValues for () {}
79
80/// A trait that allows converting an object to a Configuration
81pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
82	/// Get the SharedParams for this object
83	fn shared_params(&self) -> &SharedParams;
84
85	/// Get the ImportParams for this object
86	fn import_params(&self) -> Option<&ImportParams> {
87		None
88	}
89
90	/// Get the PruningParams for this object
91	fn pruning_params(&self) -> Option<&PruningParams> {
92		self.import_params().map(|x| &x.pruning_params)
93	}
94
95	/// Get the KeystoreParams for this object
96	fn keystore_params(&self) -> Option<&KeystoreParams> {
97		None
98	}
99
100	/// Get the NetworkParams for this object
101	fn network_params(&self) -> Option<&NetworkParams> {
102		None
103	}
104
105	/// Get a reference to `OffchainWorkerParams` for this object.
106	fn offchain_worker_params(&self) -> Option<&OffchainWorkerParams> {
107		None
108	}
109
110	/// Get the NodeKeyParams for this object
111	fn node_key_params(&self) -> Option<&NodeKeyParams> {
112		self.network_params().map(|x| &x.node_key_params)
113	}
114
115	/// Get the DatabaseParams for this object
116	fn database_params(&self) -> Option<&DatabaseParams> {
117		self.import_params().map(|x| &x.database_params)
118	}
119
120	/// Get the base path of the configuration (if any)
121	///
122	/// By default this is retrieved from `SharedParams`.
123	fn base_path(&self) -> Result<Option<BasePath>> {
124		self.shared_params().base_path()
125	}
126
127	/// Returns `true` if the node is for development or not
128	///
129	/// By default this is retrieved from `SharedParams`.
130	fn is_dev(&self) -> Result<bool> {
131		Ok(self.shared_params().is_dev())
132	}
133
134	/// Gets the role
135	///
136	/// By default this is `Role::Full`.
137	fn role(&self, _is_dev: bool) -> Result<Role> {
138		Ok(Role::Full)
139	}
140
141	/// Get the transaction pool options
142	///
143	/// By default this is `TransactionPoolOptions::default()`.
144	fn transaction_pool(&self, _is_dev: bool) -> Result<TransactionPoolOptions> {
145		Ok(Default::default())
146	}
147
148	/// Get the network configuration
149	///
150	/// By default this is retrieved from `NetworkParams` if it is available otherwise it creates
151	/// a default `NetworkConfiguration` based on `node_name`, `client_id`, `node_key` and
152	/// `net_config_dir`.
153	fn network_config(
154		&self,
155		chain_spec: &Box<dyn ChainSpec>,
156		is_dev: bool,
157		is_validator: bool,
158		net_config_dir: PathBuf,
159		client_id: &str,
160		node_name: &str,
161		node_key: NodeKeyConfig,
162		default_listen_port: u16,
163	) -> Result<NetworkConfiguration> {
164		let network_config = if let Some(network_params) = self.network_params() {
165			network_params.network_config(
166				chain_spec,
167				is_dev,
168				is_validator,
169				Some(net_config_dir),
170				client_id,
171				node_name,
172				node_key,
173				default_listen_port,
174			)
175		} else {
176			NetworkConfiguration::new(node_name, client_id, node_key, Some(net_config_dir))
177		};
178
179		// TODO: Return error here in the next release:
180		// https://github.com/paritytech/polkadot-sdk/issues/5266
181		// if is_validator && network_config.public_addresses.is_empty() {}
182
183		Ok(network_config)
184	}
185
186	/// Get the keystore configuration.
187	///
188	/// By default this is retrieved from `KeystoreParams` if it is available. Otherwise it uses
189	/// `KeystoreConfig::InMemory`.
190	fn keystore_config(&self, config_dir: &PathBuf) -> Result<KeystoreConfig> {
191		self.keystore_params()
192			.map(|x| x.keystore_config(config_dir))
193			.unwrap_or_else(|| Ok(KeystoreConfig::InMemory))
194	}
195
196	/// Get the database cache size.
197	///
198	/// By default this is retrieved from `DatabaseParams` if it is available. Otherwise its `None`.
199	fn database_cache_size(&self) -> Result<Option<usize>> {
200		Ok(self.database_params().map(|x| x.database_cache_size()).unwrap_or_default())
201	}
202
203	/// Get the database backend variant.
204	///
205	/// By default this is retrieved from `DatabaseParams` if it is available. Otherwise its `None`.
206	fn database(&self) -> Result<Option<Database>> {
207		Ok(self.database_params().and_then(|x| x.database()))
208	}
209
210	/// Get the database configuration object for the parameters provided
211	fn database_config(
212		&self,
213		base_path: &PathBuf,
214		cache_size: usize,
215		database: Database,
216	) -> Result<DatabaseSource> {
217		let role_dir = "full";
218		let rocksdb_path = base_path.join("db").join(role_dir);
219		let paritydb_path = base_path.join("paritydb").join(role_dir);
220		Ok(match database {
221			#[cfg(feature = "rocksdb")]
222			Database::RocksDb => DatabaseSource::RocksDb { path: rocksdb_path, cache_size },
223			Database::ParityDb => DatabaseSource::ParityDb { path: paritydb_path },
224			Database::ParityDbDeprecated => {
225				eprintln!(
226					"WARNING: \"paritydb-experimental\" database setting is deprecated and will be removed in future releases. \
227				Please update your setup to use the new value: \"paritydb\"."
228				);
229				DatabaseSource::ParityDb { path: paritydb_path }
230			},
231			Database::Auto => DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size },
232		})
233	}
234
235	/// Get the trie cache maximum size.
236	///
237	/// By default this is retrieved from `ImportParams` if it is available. Otherwise its `0`.
238	/// If `None` is returned the trie cache is disabled.
239	fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
240		Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default())
241	}
242
243	/// Get if we should warm up the trie cache.
244	///
245	/// By default this is retrieved from `ImportParams` if it is available. Otherwise its `None`.
246	fn warm_up_trie_cache(&self) -> Result<Option<soil_service::config::TrieCacheWarmUpStrategy>> {
247		Ok(self
248			.import_params()
249			.map(|x| x.warm_up_trie_cache().map(|x| x.into()))
250			.unwrap_or_default())
251	}
252
253	/// Get the state pruning mode.
254	///
255	/// By default this is retrieved from `PruningMode` if it is available. Otherwise its
256	/// `PruningMode::default()`.
257	fn state_pruning(&self) -> Result<Option<PruningMode>> {
258		self.pruning_params()
259			.map(|x| x.state_pruning())
260			.unwrap_or_else(|| Ok(Default::default()))
261	}
262
263	/// Get the block pruning mode.
264	///
265	/// By default this is retrieved from `block_pruning` if it is available. Otherwise its
266	/// `BlocksPruning::KeepFinalized`.
267	fn blocks_pruning(&self) -> Result<BlocksPruning> {
268		self.pruning_params()
269			.map(|x| x.blocks_pruning())
270			.unwrap_or_else(|| Ok(BlocksPruning::KeepFinalized))
271	}
272
273	/// Get the chain ID (string).
274	///
275	/// By default this is retrieved from `SharedParams`.
276	fn chain_id(&self, is_dev: bool) -> Result<String> {
277		Ok(self.shared_params().chain_id(is_dev))
278	}
279
280	/// Get the name of the node.
281	///
282	/// By default a random name is generated.
283	fn node_name(&self) -> Result<String> {
284		Ok(generate_node_name())
285	}
286
287	/// Get the WASM execution method.
288	///
289	/// By default this is retrieved from `ImportParams` if it is available. Otherwise its
290	/// `WasmExecutionMethod::default()`.
291	fn wasm_method(&self) -> Result<WasmExecutionMethod> {
292		Ok(self.import_params().map(|x| x.wasm_method()).unwrap_or_default())
293	}
294
295	/// Get the path where WASM overrides live.
296	///
297	/// By default this is `None`.
298	fn wasm_runtime_overrides(&self) -> Option<PathBuf> {
299		self.import_params().map(|x| x.wasm_runtime_overrides()).unwrap_or_default()
300	}
301
302	/// Get the RPC address.
303	fn rpc_addr(&self, _default_listen_port: u16) -> Result<Option<Vec<RpcEndpoint>>> {
304		Ok(None)
305	}
306
307	/// Returns the RPC method set to expose.
308	///
309	/// By default this is `RpcMethods::Auto` (unsafe RPCs are denied iff
310	/// `rpc_external` returns true, respectively).
311	fn rpc_methods(&self) -> Result<RpcMethods> {
312		Ok(Default::default())
313	}
314
315	/// Get the maximum number of RPC server connections.
316	fn rpc_max_connections(&self) -> Result<u32> {
317		Ok(RPC_DEFAULT_MAX_CONNECTIONS)
318	}
319
320	/// Get the RPC cors (`None` if disabled)
321	///
322	/// By default this is `Some(Vec::new())`.
323	fn rpc_cors(&self, _is_dev: bool) -> Result<Option<Vec<String>>> {
324		Ok(Some(Vec::new()))
325	}
326
327	/// Get maximum RPC request payload size.
328	fn rpc_max_request_size(&self) -> Result<u32> {
329		Ok(RPC_DEFAULT_MAX_REQUEST_SIZE_MB)
330	}
331
332	/// Get maximum RPC response payload size.
333	fn rpc_max_response_size(&self) -> Result<u32> {
334		Ok(RPC_DEFAULT_MAX_RESPONSE_SIZE_MB)
335	}
336
337	/// Get maximum number of subscriptions per connection.
338	fn rpc_max_subscriptions_per_connection(&self) -> Result<u32> {
339		Ok(RPC_DEFAULT_MAX_SUBS_PER_CONN)
340	}
341
342	/// The number of messages the RPC server is allowed to keep in memory per connection.
343	fn rpc_buffer_capacity_per_connection(&self) -> Result<u32> {
344		Ok(RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)
345	}
346
347	/// RPC server batch request configuration.
348	fn rpc_batch_config(&self) -> Result<RpcBatchRequestConfig> {
349		Ok(RpcBatchRequestConfig::Unlimited)
350	}
351
352	/// RPC rate limit configuration.
353	fn rpc_rate_limit(&self) -> Result<Option<NonZeroU32>> {
354		Ok(None)
355	}
356
357	/// RPC rate limit whitelisted ip addresses.
358	fn rpc_rate_limit_whitelisted_ips(&self) -> Result<Vec<IpNetwork>> {
359		Ok(vec![])
360	}
361
362	/// RPC rate limit trust proxy headers.
363	fn rpc_rate_limit_trust_proxy_headers(&self) -> Result<bool> {
364		Ok(false)
365	}
366
367	/// Get the prometheus configuration (`None` if disabled)
368	///
369	/// By default this is `None`.
370	fn prometheus_config(
371		&self,
372		_default_listen_port: u16,
373		_chain_spec: &Box<dyn ChainSpec>,
374	) -> Result<Option<PrometheusConfig>> {
375		Ok(None)
376	}
377
378	/// Get the telemetry endpoints (if any)
379	///
380	/// By default this is retrieved from the chain spec loaded by `load_spec`.
381	fn telemetry_endpoints(
382		&self,
383		chain_spec: &Box<dyn ChainSpec>,
384	) -> Result<Option<TelemetryEndpoints>> {
385		Ok(chain_spec.telemetry_endpoints().clone())
386	}
387
388	/// Get the default value for heap pages
389	///
390	/// By default this is `None`.
391	fn default_heap_pages(&self) -> Result<Option<u64>> {
392		Ok(None)
393	}
394
395	/// Returns an offchain worker config wrapped in `Ok(_)`
396	///
397	/// By default offchain workers are disabled.
398	fn offchain_worker(&self, role: &Role) -> Result<OffchainWorkerConfig> {
399		self.offchain_worker_params()
400			.map(|x| x.offchain_worker(role))
401			.unwrap_or_else(|| Ok(OffchainWorkerConfig::default()))
402	}
403
404	/// Returns `Ok(true)` if authoring should be forced
405	///
406	/// By default this is `false`.
407	fn force_authoring(&self) -> Result<bool> {
408		Ok(Default::default())
409	}
410
411	/// Returns `Ok(true)` if grandpa should be disabled
412	///
413	/// By default this is `false`.
414	fn disable_grandpa(&self) -> Result<bool> {
415		Ok(Default::default())
416	}
417
418	/// Get the development key seed from the current object
419	///
420	/// By default this is `None`.
421	fn dev_key_seed(&self, _is_dev: bool) -> Result<Option<String>> {
422		Ok(Default::default())
423	}
424
425	/// Get the tracing targets from the current object (if any)
426	///
427	/// By default this is retrieved from [`SharedParams`] if it is available. Otherwise its
428	/// `None`.
429	fn tracing_targets(&self) -> Result<Option<String>> {
430		Ok(self.shared_params().tracing_targets())
431	}
432
433	/// Get the TracingReceiver value from the current object
434	///
435	/// By default this is retrieved from [`SharedParams`] if it is available. Otherwise its
436	/// `TracingReceiver::default()`.
437	fn tracing_receiver(&self) -> Result<TracingReceiver> {
438		Ok(self.shared_params().tracing_receiver())
439	}
440
441	/// Get the node key from the current object
442	///
443	/// By default this is retrieved from `NodeKeyParams` if it is available. Otherwise its
444	/// `NodeKeyConfig::default()`.
445	fn node_key(&self, net_config_dir: &PathBuf) -> Result<NodeKeyConfig> {
446		let is_dev = self.is_dev()?;
447		let role = self.role(is_dev)?;
448		self.node_key_params()
449			.map(|x| x.node_key(net_config_dir, role, is_dev))
450			.unwrap_or_else(|| Ok(Default::default()))
451	}
452
453	/// Get maximum runtime instances
454	///
455	/// By default this is `None`.
456	fn max_runtime_instances(&self) -> Result<Option<usize>> {
457		Ok(Default::default())
458	}
459
460	/// Get maximum different runtimes in cache
461	///
462	/// By default this is `2`.
463	fn runtime_cache_size(&self) -> Result<u8> {
464		Ok(2)
465	}
466
467	/// Activate or not the automatic announcing of blocks after import
468	///
469	/// By default this is `false`.
470	fn announce_block(&self) -> Result<bool> {
471		Ok(true)
472	}
473
474	/// Create a Configuration object from the current object
475	fn create_configuration<C: SubstrateCli>(
476		&self,
477		cli: &C,
478		tokio_handle: tokio::runtime::Handle,
479	) -> Result<Configuration> {
480		let is_dev = self.is_dev()?;
481		let chain_id = self.chain_id(is_dev)?;
482		let chain_spec = cli.load_spec(&chain_id)?;
483		let base_path = base_path_or_default(self.base_path()?, &C::executable_name());
484		let config_dir = build_config_dir(&base_path, chain_spec.id());
485		let net_config_dir = build_net_config_dir(&config_dir);
486		let client_id = C::client_id();
487		let database_cache_size = self.database_cache_size()?.unwrap_or(1024);
488		let database = self.database()?.unwrap_or(
489			#[cfg(feature = "rocksdb")]
490			{
491				Database::RocksDb
492			},
493			#[cfg(not(feature = "rocksdb"))]
494			{
495				Database::ParityDb
496			},
497		);
498		let node_key = self.node_key(&net_config_dir)?;
499		let role = self.role(is_dev)?;
500		let max_runtime_instances = self.max_runtime_instances()?.unwrap_or(8);
501		let is_validator = role.is_authority();
502		let keystore = self.keystore_config(&config_dir)?;
503		let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?;
504		let runtime_cache_size = self.runtime_cache_size()?;
505
506		let rpc_addrs: Option<Vec<soil_service::config::RpcEndpoint>> = self
507			.rpc_addr(DCV::rpc_listen_port())?
508			.map(|addrs| addrs.into_iter().map(Into::into).collect());
509
510		Ok(Configuration {
511			impl_name: C::impl_name(),
512			impl_version: C::impl_version(),
513			tokio_handle,
514			transaction_pool: self.transaction_pool(is_dev)?,
515			network: self.network_config(
516				&chain_spec,
517				is_dev,
518				is_validator,
519				net_config_dir,
520				client_id.as_str(),
521				self.node_name()?.as_str(),
522				node_key,
523				DCV::p2p_listen_port(),
524			)?,
525			keystore,
526			database: self.database_config(&config_dir, database_cache_size, database)?,
527			data_path: config_dir,
528			trie_cache_maximum_size: self.trie_cache_maximum_size()?,
529			warm_up_trie_cache: self.warm_up_trie_cache()?,
530			state_pruning: self.state_pruning()?,
531			blocks_pruning: self.blocks_pruning()?,
532			executor: ExecutorConfiguration {
533				wasm_method: self.wasm_method()?,
534				default_heap_pages: self.default_heap_pages()?,
535				max_runtime_instances,
536				runtime_cache_size,
537			},
538			wasm_runtime_overrides: self.wasm_runtime_overrides(),
539			rpc: RpcConfiguration {
540				addr: rpc_addrs,
541				methods: self.rpc_methods()?,
542				max_connections: self.rpc_max_connections()?,
543				cors: self.rpc_cors(is_dev)?,
544				max_request_size: self.rpc_max_request_size()?,
545				max_response_size: self.rpc_max_response_size()?,
546				id_provider: None,
547				max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?,
548				port: DCV::rpc_listen_port(),
549				message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?,
550				batch_config: self.rpc_batch_config()?,
551				rate_limit: self.rpc_rate_limit()?,
552				rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips()?,
553				rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers()?,
554				request_logger_limit: if is_dev { 1024 * 1024 } else { 1024 },
555			},
556			prometheus_config: self
557				.prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?,
558			telemetry_endpoints,
559			offchain_worker: self.offchain_worker(&role)?,
560			force_authoring: self.force_authoring()?,
561			disable_grandpa: self.disable_grandpa()?,
562			dev_key_seed: self.dev_key_seed(is_dev)?,
563			tracing_targets: self.tracing_targets()?,
564			tracing_receiver: self.tracing_receiver()?,
565			chain_spec,
566			announce_block: self.announce_block()?,
567			role,
568			base_path,
569		})
570	}
571
572	/// Get the filters for the logging.
573	///
574	/// This should be a list of comma-separated values.
575	/// Example: `foo=trace,bar=debug,baz=info`
576	///
577	/// By default this is retrieved from `SharedParams`.
578	fn log_filters(&self) -> Result<String> {
579		Ok(self.shared_params().log_filters().join(","))
580	}
581
582	/// Should the detailed log output be enabled.
583	fn detailed_log_output(&self) -> Result<bool> {
584		Ok(self.shared_params().detailed_log_output())
585	}
586
587	/// Is log reloading enabled?
588	fn enable_log_reloading(&self) -> Result<bool> {
589		Ok(self.shared_params().enable_log_reloading())
590	}
591
592	/// Should the log color output be disabled?
593	fn disable_log_color(&self) -> Result<bool> {
594		Ok(self.shared_params().disable_log_color())
595	}
596
597	/// Initialize substrate. This must be done only once per process.
598	///
599	/// This method:
600	///
601	/// 1. Sets the panic handler
602	/// 2. Optionally customize logger/profiling
603	/// 2. Initializes the logger
604	/// 3. Raises the FD limit
605	///
606	/// The `logger_hook` closure is executed before the logger is constructed
607	/// and initialized. It is useful for setting up a custom profiler.
608	///
609	/// Example:
610	/// ```
611	/// use soil_client::tracing::{SpanDatum, TraceEvent};
612	/// struct TestProfiler;
613	///
614	/// impl soil_client::tracing::TraceHandler for TestProfiler {
615	///  	fn handle_span(&self, sd: &SpanDatum) {}
616	/// 		fn handle_event(&self, _event: &TraceEvent) {}
617	/// };
618	///
619	/// fn logger_hook() -> impl FnOnce(&mut soil_cli::LoggerBuilder, &soil_service::Configuration) -> () {
620	/// 	|logger_builder, config| {
621	/// 			logger_builder.with_custom_profiling(Box::new(TestProfiler{}));
622	/// 	}
623	/// }
624	/// ```
625	fn init<F>(&self, support_url: &String, impl_version: &String, logger_hook: F) -> Result<()>
626	where
627		F: FnOnce(&mut LoggerBuilder),
628	{
629		subsoil::panic_handler::set(support_url, impl_version);
630
631		let mut logger = LoggerBuilder::new(self.log_filters()?);
632		logger
633			.with_log_reloading(self.enable_log_reloading()?)
634			.with_detailed_output(self.detailed_log_output()?);
635
636		if let Some(tracing_targets) = self.tracing_targets()? {
637			let tracing_receiver = self.tracing_receiver()?;
638			logger.with_profiling(tracing_receiver, tracing_targets);
639		}
640
641		if self.disable_log_color()? {
642			logger.with_colors(false);
643		}
644
645		// Call hook for custom profiling setup.
646		logger_hook(&mut logger);
647
648		logger.init()?;
649
650		match fdlimit::raise_fd_limit() {
651			Ok(fdlimit::Outcome::LimitRaised { to, .. }) => {
652				if to < RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT {
653					warn!(
654						"Low open file descriptor limit configured for the process. \
655						Current value: {:?}, recommended value: {:?}.",
656						to, RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT,
657					);
658				}
659			},
660			Ok(fdlimit::Outcome::Unsupported) => {
661				// Unsupported platform (non-Linux)
662			},
663			Err(error) => {
664				warn!(
665					"Failed to configure file descriptor limit for the process: \
666					{}, recommended value: {:?}.",
667					error, RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT,
668				);
669			},
670		}
671
672		Ok(())
673	}
674}
675
676/// Generate a valid random name for the node
677pub fn generate_node_name() -> String {
678	loop {
679		let node_name = Generator::with_naming(Name::Numbered)
680			.next()
681			.expect("RNG is available on all supported platforms; qed");
682		let count = node_name.chars().count();
683
684		if count < NODE_NAME_MAX_LENGTH {
685			return node_name;
686		}
687	}
688}
689
690/// Returns the value of `base_path` or the default_path if it is None
691pub(crate) fn base_path_or_default(
692	base_path: Option<BasePath>,
693	executable_name: &String,
694) -> BasePath {
695	base_path.unwrap_or_else(|| BasePath::from_project("", "", executable_name))
696}
697
698/// Returns the default path for configuration  directory based on the chain_spec
699pub(crate) fn build_config_dir(base_path: &BasePath, chain_spec_id: &str) -> PathBuf {
700	base_path.config_dir(chain_spec_id)
701}
702
703/// Returns the default path for the network configuration inside the configuration dir
704pub(crate) fn build_net_config_dir(config_dir: &PathBuf) -> PathBuf {
705	config_dir.join(DEFAULT_NETWORK_CONFIG_PATH)
706}
707
708/// Returns the default path for the network directory starting from the provided base_path
709/// or from the default base_path.
710pub(crate) fn build_network_key_dir_or_default(
711	base_path: Option<BasePath>,
712	chain_spec_id: &str,
713	executable_name: &String,
714) -> PathBuf {
715	let config_dir =
716		build_config_dir(&base_path_or_default(base_path, executable_name), chain_spec_id);
717	build_net_config_dir(&config_dir)
718}