referrerpolicy=no-referrer-when-downgrade

sc_cli/
config.rs

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