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

            
21
use crate::{
22
	arg_enums::Database, error::Result, DatabaseParams, ImportParams, KeystoreParams,
23
	NetworkParams, NodeKeyParams, OffchainWorkerParams, PruningParams, SharedParams, SubstrateCli,
24
};
25
use log::warn;
26
use names::{Generator, Name};
27
use sc_service::{
28
	config::{
29
		BasePath, Configuration, DatabaseSource, IpNetwork, KeystoreConfig, NetworkConfiguration,
30
		NodeKeyConfig, OffchainWorkerConfig, OutputFormat, PrometheusConfig, PruningMode, Role,
31
		RpcBatchRequestConfig, RpcMethods, TelemetryEndpoints, TransactionPoolOptions,
32
		WasmExecutionMethod,
33
	},
34
	BlocksPruning, ChainSpec, TracingReceiver,
35
};
36
use sc_tracing::logging::LoggerBuilder;
37
use std::{net::SocketAddr, num::NonZeroU32, path::PathBuf};
38

            
39
/// The maximum number of characters for a node name.
40
pub(crate) const NODE_NAME_MAX_LENGTH: usize = 64;
41

            
42
/// Default sub directory to store network config.
43
pub(crate) const DEFAULT_NETWORK_CONFIG_PATH: &str = "network";
44

            
45
/// The recommended open file descriptor limit to be configured for the process.
46
const RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT: u64 = 10_000;
47

            
48
/// The default port.
49
pub const RPC_DEFAULT_PORT: u16 = 9944;
50
/// The default max number of subscriptions per connection.
51
pub const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
52
/// The default max request size in MB.
53
pub const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
54
/// The default max response size in MB.
55
pub const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 15;
56
/// The default concurrent connection limit.
57
pub const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 100;
58
/// The default number of messages the RPC server
59
/// is allowed to keep in memory per connection.
60
pub const RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN: u32 = 64;
61

            
62
/// Default configuration values used by Substrate
63
///
64
/// These values will be used by [`CliConfiguration`] to set
65
/// default values for e.g. the listen port or the RPC port.
66
pub trait DefaultConfigurationValues {
67
	/// The port Substrate should listen on for p2p connections.
68
	///
69
	/// By default this is `30333`.
70
	fn p2p_listen_port() -> u16 {
71
		30333
72
	}
73

            
74
	/// The port Substrate should listen on for JSON-RPC connections.
75
	///
76
	/// By default this is `9944`.
77
	fn rpc_listen_port() -> u16 {
78
		RPC_DEFAULT_PORT
79
	}
80

            
81
	/// The port Substrate should listen on for prometheus connections.
82
	///
83
	/// By default this is `9615`.
84
	fn prometheus_listen_port() -> u16 {
85
		9615
86
	}
87
}
88

            
89
impl DefaultConfigurationValues for () {}
90

            
91
/// A trait that allows converting an object to a Configuration
92
pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
93
	/// Get the SharedParams for this object
94
	fn shared_params(&self) -> &SharedParams;
95

            
96
	/// Get the ImportParams for this object
97
	fn import_params(&self) -> Option<&ImportParams> {
98
		None
99
	}
100

            
101
	/// Get the PruningParams for this object
102
	fn pruning_params(&self) -> Option<&PruningParams> {
103
		self.import_params().map(|x| &x.pruning_params)
104
	}
105

            
106
	/// Get the KeystoreParams for this object
107
	fn keystore_params(&self) -> Option<&KeystoreParams> {
108
		None
109
	}
110

            
111
	/// Get the NetworkParams for this object
112
	fn network_params(&self) -> Option<&NetworkParams> {
113
		None
114
	}
115

            
116
	/// Get a reference to `OffchainWorkerParams` for this object.
117
	fn offchain_worker_params(&self) -> Option<&OffchainWorkerParams> {
118
		None
119
	}
120

            
121
	/// Get the NodeKeyParams for this object
122
	fn node_key_params(&self) -> Option<&NodeKeyParams> {
123
		self.network_params().map(|x| &x.node_key_params)
124
	}
125

            
126
	/// Get the DatabaseParams for this object
127
	fn database_params(&self) -> Option<&DatabaseParams> {
128
		self.import_params().map(|x| &x.database_params)
129
	}
130

            
131
	/// Get the base path of the configuration (if any)
132
	///
133
	/// By default this is retrieved from `SharedParams`.
134
	fn base_path(&self) -> Result<Option<BasePath>> {
135
		self.shared_params().base_path()
136
	}
137

            
138
	/// Returns `true` if the node is for development or not
139
	///
140
	/// By default this is retrieved from `SharedParams`.
141
	fn is_dev(&self) -> Result<bool> {
142
		Ok(self.shared_params().is_dev())
143
	}
144

            
145
	/// Gets the role
146
	///
147
	/// By default this is `Role::Full`.
148
	fn role(&self, _is_dev: bool) -> Result<Role> {
149
		Ok(Role::Full)
150
	}
151

            
152
	/// Get the transaction pool options
153
	///
154
	/// By default this is `TransactionPoolOptions::default()`.
155
	fn transaction_pool(&self, _is_dev: bool) -> Result<TransactionPoolOptions> {
156
		Ok(Default::default())
157
	}
158

            
159
	/// Get the network configuration
160
	///
161
	/// By default this is retrieved from `NetworkParams` if it is available otherwise it creates
162
	/// a default `NetworkConfiguration` based on `node_name`, `client_id`, `node_key` and
163
	/// `net_config_dir`.
164
	fn network_config(
165
		&self,
166
		chain_spec: &Box<dyn ChainSpec>,
167
		is_dev: bool,
168
		is_validator: bool,
169
		net_config_dir: PathBuf,
170
		client_id: &str,
171
		node_name: &str,
172
		node_key: NodeKeyConfig,
173
		default_listen_port: u16,
174
	) -> Result<NetworkConfiguration> {
175
		Ok(if let Some(network_params) = self.network_params() {
176
			network_params.network_config(
177
				chain_spec,
178
				is_dev,
179
				is_validator,
180
				Some(net_config_dir),
181
				client_id,
182
				node_name,
183
				node_key,
184
				default_listen_port,
185
			)
186
		} else {
187
			NetworkConfiguration::new(node_name, client_id, node_key, Some(net_config_dir))
188
		})
189
	}
190

            
191
	/// Get the keystore configuration.
192
	///
193
	/// By default this is retrieved from `KeystoreParams` if it is available. Otherwise it uses
194
	/// `KeystoreConfig::InMemory`.
195
	fn keystore_config(&self, config_dir: &PathBuf) -> Result<KeystoreConfig> {
196
		self.keystore_params()
197
			.map(|x| x.keystore_config(config_dir))
198
			.unwrap_or_else(|| Ok(KeystoreConfig::InMemory))
199
	}
200

            
201
	/// Get the database cache size.
202
	///
203
	/// By default this is retrieved from `DatabaseParams` if it is available. Otherwise its `None`.
204
	fn database_cache_size(&self) -> Result<Option<usize>> {
205
		Ok(self.database_params().map(|x| x.database_cache_size()).unwrap_or_default())
206
	}
207

            
208
	/// Get the database backend variant.
209
	///
210
	/// By default this is retrieved from `DatabaseParams` if it is available. Otherwise its `None`.
211
	fn database(&self) -> Result<Option<Database>> {
212
		Ok(self.database_params().and_then(|x| x.database()))
213
	}
214

            
215
	/// Get the database configuration object for the parameters provided
216
	fn database_config(
217
		&self,
218
		base_path: &PathBuf,
219
		cache_size: usize,
220
		database: Database,
221
	) -> Result<DatabaseSource> {
222
		let role_dir = "full";
223
		let rocksdb_path = base_path.join("db").join(role_dir);
224
		let paritydb_path = base_path.join("paritydb").join(role_dir);
225
		Ok(match database {
226
			#[cfg(feature = "rocksdb")]
227
			Database::RocksDb => DatabaseSource::RocksDb { path: rocksdb_path, cache_size },
228
			Database::ParityDb => DatabaseSource::ParityDb { path: paritydb_path },
229
			Database::ParityDbDeprecated => {
230
				eprintln!(
231
					"WARNING: \"paritydb-experimental\" database setting is deprecated and will be removed in future releases. \
232
				Please update your setup to use the new value: \"paritydb\"."
233
				);
234
				DatabaseSource::ParityDb { path: paritydb_path }
235
			},
236
			Database::Auto => DatabaseSource::Auto { paritydb_path, rocksdb_path, cache_size },
237
		})
238
	}
239

            
240
	/// Get the trie cache maximum size.
241
	///
242
	/// By default this is retrieved from `ImportParams` if it is available. Otherwise its `0`.
243
	/// If `None` is returned the trie cache is disabled.
244
	fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
245
		Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default())
246
	}
247

            
248
	/// Get the state pruning mode.
249
	///
250
	/// By default this is retrieved from `PruningMode` if it is available. Otherwise its
251
	/// `PruningMode::default()`.
252
	fn state_pruning(&self) -> Result<Option<PruningMode>> {
253
		self.pruning_params()
254
			.map(|x| x.state_pruning())
255
			.unwrap_or_else(|| Ok(Default::default()))
256
	}
257

            
258
	/// Get the block pruning mode.
259
	///
260
	/// By default this is retrieved from `block_pruning` if it is available. Otherwise its
261
	/// `BlocksPruning::KeepFinalized`.
262
	fn blocks_pruning(&self) -> Result<BlocksPruning> {
263
		self.pruning_params()
264
			.map(|x| x.blocks_pruning())
265
			.unwrap_or_else(|| Ok(BlocksPruning::KeepFinalized))
266
	}
267

            
268
	/// Get the chain ID (string).
269
	///
270
	/// By default this is retrieved from `SharedParams`.
271
	fn chain_id(&self, is_dev: bool) -> Result<String> {
272
		Ok(self.shared_params().chain_id(is_dev))
273
	}
274

            
275
	/// Get the name of the node.
276
	///
277
	/// By default a random name is generated.
278
	fn node_name(&self) -> Result<String> {
279
		Ok(generate_node_name())
280
	}
281

            
282
	/// Get the WASM execution method.
283
	///
284
	/// By default this is retrieved from `ImportParams` if it is available. Otherwise its
285
	/// `WasmExecutionMethod::default()`.
286
	fn wasm_method(&self) -> Result<WasmExecutionMethod> {
287
		Ok(self.import_params().map(|x| x.wasm_method()).unwrap_or_default())
288
	}
289

            
290
	/// Get the path where WASM precompiled artifacts live.
291
	///
292
	/// By default this is `None`.
293
	fn wasmtime_precompiled(&self) -> Option<PathBuf> {
294
		self.import_params().map(|x| x.wasmtime_precompiled()).unwrap_or_default()
295
	}
296

            
297
	/// Get the path where WASM overrides live.
298
	///
299
	/// By default this is `None`.
300
	fn wasm_runtime_overrides(&self) -> Option<PathBuf> {
301
		self.import_params().map(|x| x.wasm_runtime_overrides()).unwrap_or_default()
302
	}
303

            
304
	/// Get the RPC address.
305
	fn rpc_addr(&self, _default_listen_port: u16) -> Result<Option<SocketAddr>> {
306
		Ok(None)
307
	}
308

            
309
	/// Returns the RPC method set to expose.
310
	///
311
	/// By default this is `RpcMethods::Auto` (unsafe RPCs are denied iff
312
	/// `rpc_external` returns true, respectively).
313
	fn rpc_methods(&self) -> Result<RpcMethods> {
314
		Ok(Default::default())
315
	}
316

            
317
	/// Get the maximum number of RPC server connections.
318
	fn rpc_max_connections(&self) -> Result<u32> {
319
		Ok(RPC_DEFAULT_MAX_CONNECTIONS)
320
	}
321

            
322
	/// Get the RPC cors (`None` if disabled)
323
	///
324
	/// By default this is `Some(Vec::new())`.
325
	fn rpc_cors(&self, _is_dev: bool) -> Result<Option<Vec<String>>> {
326
		Ok(Some(Vec::new()))
327
	}
328

            
329
	/// Get maximum RPC request payload size.
330
	fn rpc_max_request_size(&self) -> Result<u32> {
331
		Ok(RPC_DEFAULT_MAX_REQUEST_SIZE_MB)
332
	}
333

            
334
	/// Get maximum RPC response payload size.
335
	fn rpc_max_response_size(&self) -> Result<u32> {
336
		Ok(RPC_DEFAULT_MAX_RESPONSE_SIZE_MB)
337
	}
338

            
339
	/// Get maximum number of subscriptions per connection.
340
	fn rpc_max_subscriptions_per_connection(&self) -> Result<u32> {
341
		Ok(RPC_DEFAULT_MAX_SUBS_PER_CONN)
342
	}
343

            
344
	/// The number of messages the RPC server is allowed to keep in memory per connection.
345
	fn rpc_buffer_capacity_per_connection(&self) -> Result<u32> {
346
		Ok(RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)
347
	}
348

            
349
	/// RPC server batch request configuration.
350
	fn rpc_batch_config(&self) -> Result<RpcBatchRequestConfig> {
351
		Ok(RpcBatchRequestConfig::Unlimited)
352
	}
353

            
354
	/// RPC rate limit configuration.
355
	fn rpc_rate_limit(&self) -> Result<Option<NonZeroU32>> {
356
		Ok(None)
357
	}
358

            
359
	/// RPC rate limit whitelisted ip addresses.
360
	fn rpc_rate_limit_whitelisted_ips(&self) -> Result<Vec<IpNetwork>> {
361
		Ok(vec![])
362
	}
363

            
364
	/// RPC rate limit trust proxy headers.
365
	fn rpc_rate_limit_trust_proxy_headers(&self) -> Result<bool> {
366
		Ok(false)
367
	}
368

            
369
	/// Get the prometheus configuration (`None` if disabled)
370
	///
371
	/// By default this is `None`.
372
	fn prometheus_config(
373
		&self,
374
		_default_listen_port: u16,
375
		_chain_spec: &Box<dyn ChainSpec>,
376
	) -> Result<Option<PrometheusConfig>> {
377
		Ok(None)
378
	}
379

            
380
	/// Get the telemetry endpoints (if any)
381
	///
382
	/// By default this is retrieved from the chain spec loaded by `load_spec`.
383
	fn telemetry_endpoints(
384
		&self,
385
		chain_spec: &Box<dyn ChainSpec>,
386
	) -> Result<Option<TelemetryEndpoints>> {
387
		Ok(chain_spec.telemetry_endpoints().clone())
388
	}
389

            
390
	/// Get the default value for heap pages
391
	///
392
	/// By default this is `None`.
393
	fn default_heap_pages(&self) -> Result<Option<u64>> {
394
		Ok(None)
395
	}
396

            
397
	/// Returns an offchain worker config wrapped in `Ok(_)`
398
	///
399
	/// By default offchain workers are disabled.
400
	fn offchain_worker(&self, role: &Role) -> Result<OffchainWorkerConfig> {
401
		self.offchain_worker_params()
402
			.map(|x| x.offchain_worker(role))
403
			.unwrap_or_else(|| Ok(OffchainWorkerConfig::default()))
404
	}
405

            
406
	/// Returns `Ok(true)` if authoring should be forced
407
	///
408
	/// By default this is `false`.
409
	fn force_authoring(&self) -> Result<bool> {
410
		Ok(Default::default())
411
	}
412

            
413
	/// Returns `Ok(true)` if grandpa should be disabled
414
	///
415
	/// By default this is `false`.
416
	fn disable_grandpa(&self) -> Result<bool> {
417
		Ok(Default::default())
418
	}
419

            
420
	/// Get the development key seed from the current object
421
	///
422
	/// By default this is `None`.
423
	fn dev_key_seed(&self, _is_dev: bool) -> Result<Option<String>> {
424
		Ok(Default::default())
425
	}
426

            
427
	/// Get the tracing targets from the current object (if any)
428
	///
429
	/// By default this is retrieved from [`SharedParams`] if it is available. Otherwise its
430
	/// `None`.
431
	fn tracing_targets(&self) -> Result<Option<String>> {
432
		Ok(self.shared_params().tracing_targets())
433
	}
434

            
435
	/// Get the TracingReceiver value from the current object
436
	///
437
	/// By default this is retrieved from [`SharedParams`] if it is available. Otherwise its
438
	/// `TracingReceiver::default()`.
439
	fn tracing_receiver(&self) -> Result<TracingReceiver> {
440
		Ok(self.shared_params().tracing_receiver())
441
	}
442

            
443
	/// Get the node key from the current object
444
	///
445
	/// By default this is retrieved from `NodeKeyParams` if it is available. Otherwise its
446
	/// `NodeKeyConfig::default()`.
447
	fn node_key(&self, net_config_dir: &PathBuf) -> Result<NodeKeyConfig> {
448
		let is_dev = self.is_dev()?;
449
		let role = self.role(is_dev)?;
450
		self.node_key_params()
451
			.map(|x| x.node_key(net_config_dir, role, is_dev))
452
			.unwrap_or_else(|| Ok(Default::default()))
453
	}
454

            
455
	/// Get maximum runtime instances
456
	///
457
	/// By default this is `None`.
458
	fn max_runtime_instances(&self) -> Result<Option<usize>> {
459
		Ok(Default::default())
460
	}
461

            
462
	/// Get maximum different runtimes in cache
463
	///
464
	/// By default this is `2`.
465
	fn runtime_cache_size(&self) -> Result<u8> {
466
		Ok(2)
467
	}
468

            
469
	/// Activate or not the automatic announcing of blocks after import
470
	///
471
	/// By default this is `false`.
472
	fn announce_block(&self) -> Result<bool> {
473
		Ok(true)
474
	}
475

            
476
	/// Create a Configuration object from the current object
477
	fn create_configuration<C: SubstrateCli>(
478
		&self,
479
		cli: &C,
480
		tokio_handle: tokio::runtime::Handle,
481
	) -> Result<Configuration> {
482
		let is_dev = self.is_dev()?;
483
		let chain_id = self.chain_id(is_dev)?;
484
		let chain_spec = cli.load_spec(&chain_id)?;
485
		let base_path = base_path_or_default(self.base_path()?, &C::executable_name());
486
		let config_dir = build_config_dir(&base_path, chain_spec.id());
487
		let net_config_dir = build_net_config_dir(&config_dir);
488
		let client_id = C::client_id();
489
		let database_cache_size = self.database_cache_size()?.unwrap_or(1024);
490
		let database = self.database()?.unwrap_or(
491
			#[cfg(feature = "rocksdb")]
492
			{
493
				Database::RocksDb
494
			},
495
			#[cfg(not(feature = "rocksdb"))]
496
			{
497
				Database::ParityDb
498
			},
499
		);
500
		let node_key = self.node_key(&net_config_dir)?;
501
		let role = self.role(is_dev)?;
502
		let max_runtime_instances = self.max_runtime_instances()?.unwrap_or(8);
503
		let is_validator = role.is_authority();
504
		let keystore = self.keystore_config(&config_dir)?;
505
		let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?;
506
		let runtime_cache_size = self.runtime_cache_size()?;
507

            
508
		Ok(Configuration {
509
			impl_name: C::impl_name(),
510
			impl_version: C::impl_version(),
511
			tokio_handle,
512
			transaction_pool: self.transaction_pool(is_dev)?,
513
			network: self.network_config(
514
				&chain_spec,
515
				is_dev,
516
				is_validator,
517
				net_config_dir,
518
				client_id.as_str(),
519
				self.node_name()?.as_str(),
520
				node_key,
521
				DCV::p2p_listen_port(),
522
			)?,
523
			keystore,
524
			database: self.database_config(&config_dir, database_cache_size, database)?,
525
			data_path: config_dir,
526
			trie_cache_maximum_size: self.trie_cache_maximum_size()?,
527
			state_pruning: self.state_pruning()?,
528
			blocks_pruning: self.blocks_pruning()?,
529
			wasm_method: self.wasm_method()?,
530
			wasmtime_precompiled: self.wasmtime_precompiled(),
531
			wasm_runtime_overrides: self.wasm_runtime_overrides(),
532
			rpc_addr: self.rpc_addr(DCV::rpc_listen_port())?,
533
			rpc_methods: self.rpc_methods()?,
534
			rpc_max_connections: self.rpc_max_connections()?,
535
			rpc_cors: self.rpc_cors(is_dev)?,
536
			rpc_max_request_size: self.rpc_max_request_size()?,
537
			rpc_max_response_size: self.rpc_max_response_size()?,
538
			rpc_id_provider: None,
539
			rpc_max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?,
540
			rpc_port: DCV::rpc_listen_port(),
541
			rpc_message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?,
542
			rpc_batch_config: self.rpc_batch_config()?,
543
			rpc_rate_limit: self.rpc_rate_limit()?,
544
			rpc_rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips()?,
545
			rpc_rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers()?,
546
			prometheus_config: self
547
				.prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?,
548
			telemetry_endpoints,
549
			default_heap_pages: self.default_heap_pages()?,
550
			offchain_worker: self.offchain_worker(&role)?,
551
			force_authoring: self.force_authoring()?,
552
			disable_grandpa: self.disable_grandpa()?,
553
			dev_key_seed: self.dev_key_seed(is_dev)?,
554
			tracing_targets: self.tracing_targets()?,
555
			tracing_receiver: self.tracing_receiver()?,
556
			chain_spec,
557
			max_runtime_instances,
558
			announce_block: self.announce_block()?,
559
			role,
560
			base_path,
561
			informant_output_format: OutputFormat { enable_color: !self.disable_log_color()? },
562
			runtime_cache_size,
563
		})
564
	}
565

            
566
	/// Get the filters for the logging.
567
	///
568
	/// This should be a list of comma-separated values.
569
	/// Example: `foo=trace,bar=debug,baz=info`
570
	///
571
	/// By default this is retrieved from `SharedParams`.
572
	fn log_filters(&self) -> Result<String> {
573
		Ok(self.shared_params().log_filters().join(","))
574
	}
575

            
576
	/// Should the detailed log output be enabled.
577
	fn detailed_log_output(&self) -> Result<bool> {
578
		Ok(self.shared_params().detailed_log_output())
579
	}
580

            
581
	/// Is log reloading enabled?
582
	fn enable_log_reloading(&self) -> Result<bool> {
583
		Ok(self.shared_params().enable_log_reloading())
584
	}
585

            
586
	/// Should the log color output be disabled?
587
	fn disable_log_color(&self) -> Result<bool> {
588
		Ok(self.shared_params().disable_log_color())
589
	}
590

            
591
	/// Initialize substrate. This must be done only once per process.
592
	///
593
	/// This method:
594
	///
595
	/// 1. Sets the panic handler
596
	/// 2. Optionally customize logger/profiling
597
	/// 2. Initializes the logger
598
	/// 3. Raises the FD limit
599
	///
600
	/// The `logger_hook` closure is executed before the logger is constructed
601
	/// and initialized. It is useful for setting up a custom profiler.
602
	///
603
	/// Example:
604
	/// ```
605
	/// use sc_tracing::{SpanDatum, TraceEvent};
606
	/// struct TestProfiler;
607
	///
608
	/// impl sc_tracing::TraceHandler for TestProfiler {
609
	///  	fn handle_span(&self, sd: &SpanDatum) {}
610
	/// 		fn handle_event(&self, _event: &TraceEvent) {}
611
	/// };
612
	///
613
	/// fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () {
614
	/// 	|logger_builder, config| {
615
	/// 			logger_builder.with_custom_profiling(Box::new(TestProfiler{}));
616
	/// 	}
617
	/// }
618
	/// ```
619
	fn init<F>(
620
		&self,
621
		support_url: &String,
622
		impl_version: &String,
623
		logger_hook: F,
624
		config: &Configuration,
625
	) -> Result<()>
626
	where
627
		F: FnOnce(&mut LoggerBuilder, &Configuration),
628
	{
629
		sp_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, config);
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
			Ok(fdlimit::Outcome::Unsupported) => {
660
				// Unsupported platform (non-Linux)
661
			},
662
			Err(error) => {
663
				warn!(
664
					"Failed to configure file descriptor limit for the process: \
665
					{}, recommended value: {:?}.",
666
					error, RECOMMENDED_OPEN_FILE_DESCRIPTOR_LIMIT,
667
				);
668
			},
669
		}
670

            
671
		Ok(())
672
	}
673
}
674

            
675
/// Generate a valid random name for the node
676
pub fn generate_node_name() -> String {
677
	loop {
678
		let node_name = Generator::with_naming(Name::Numbered)
679
			.next()
680
			.expect("RNG is available on all supported platforms; qed");
681
		let count = node_name.chars().count();
682

            
683
		if count < NODE_NAME_MAX_LENGTH {
684
			return node_name
685
		}
686
	}
687
}
688

            
689
/// Returns the value of `base_path` or the default_path if it is None
690
pub(crate) fn base_path_or_default(
691
	base_path: Option<BasePath>,
692
	executable_name: &String,
693
) -> BasePath {
694
	base_path.unwrap_or_else(|| BasePath::from_project("", "", executable_name))
695
}
696

            
697
/// Returns the default path for configuration  directory based on the chain_spec
698
pub(crate) fn build_config_dir(base_path: &BasePath, chain_spec_id: &str) -> PathBuf {
699
	base_path.config_dir(chain_spec_id)
700
}
701

            
702
/// Returns the default path for the network configuration inside the configuration dir
703
pub(crate) fn build_net_config_dir(config_dir: &PathBuf) -> PathBuf {
704
	config_dir.join(DEFAULT_NETWORK_CONFIG_PATH)
705
}
706

            
707
/// Returns the default path for the network directory starting from the provided base_path
708
/// or from the default base_path.
709
pub(crate) fn build_network_key_dir_or_default(
710
	base_path: Option<BasePath>,
711
	chain_spec_id: &str,
712
	executable_name: &String,
713
) -> PathBuf {
714
	let config_dir =
715
		build_config_dir(&base_path_or_default(base_path, executable_name), chain_spec_id);
716
	build_net_config_dir(&config_dir)
717
}