Skip to main content

soil_service/
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//! Service configuration.
8
9pub use jsonrpsee::server::BatchRequestConfig as RpcBatchRequestConfig;
10use soil_prometheus::Registry;
11use soil_chain_spec::ChainSpec;
12pub use soil_client::db::{BlocksPruning, Database, DatabaseSource, PruningMode};
13pub use soil_client::executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy};
14pub use soil_network::{
15	config::{
16		MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, ProtocolId,
17		Role, SetConfig, SyncMode, TransportConfig,
18	},
19	request_responses::{
20		IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig,
21	},
22	Multiaddr,
23};
24pub use soil_rpc::server::{
25	IpNetwork, RpcEndpoint, RpcMethods, SubscriptionIdProvider as RpcSubscriptionIdProvider,
26};
27pub use soil_telemetry::TelemetryEndpoints;
28pub use soil_txpool::TransactionPoolOptions;
29use std::{
30	io, iter,
31	net::SocketAddr,
32	num::NonZeroU32,
33	path::{Path, PathBuf},
34};
35use subsoil::core::crypto::SecretString;
36use tempfile::TempDir;
37
38/// Service configuration.
39#[derive(Debug)]
40pub struct Configuration {
41	/// Implementation name
42	pub impl_name: String,
43	/// Implementation version (see soil-cli to see an example of format)
44	pub impl_version: String,
45	/// Node role.
46	pub role: Role,
47	/// Handle to the tokio runtime. Will be used to spawn futures by the task manager.
48	pub tokio_handle: tokio::runtime::Handle,
49	/// Extrinsic pool configuration.
50	pub transaction_pool: TransactionPoolOptions,
51	/// Network configuration.
52	pub network: NetworkConfiguration,
53	/// Configuration for the keystore.
54	pub keystore: KeystoreConfig,
55	/// Configuration for the database.
56	pub database: DatabaseSource,
57	/// Maximum size of internal trie cache in bytes.
58	///
59	/// If `None` is given the cache is disabled.
60	pub trie_cache_maximum_size: Option<usize>,
61	/// Force the trie cache to be in memory.
62	pub warm_up_trie_cache: Option<TrieCacheWarmUpStrategy>,
63	/// State pruning settings.
64	pub state_pruning: Option<PruningMode>,
65	/// Number of blocks to keep in the db.
66	///
67	/// NOTE: only finalized blocks are subject for removal!
68	pub blocks_pruning: BlocksPruning,
69	/// Chain configuration.
70	pub chain_spec: Box<dyn ChainSpec>,
71	/// Runtime executor configuration.
72	pub executor: ExecutorConfiguration,
73	/// Directory where local WASM runtimes live. These runtimes take precedence
74	/// over on-chain runtimes when the spec version matches. Set to `None` to
75	/// disable overrides (default).
76	pub wasm_runtime_overrides: Option<PathBuf>,
77	/// RPC configuration.
78	pub rpc: RpcConfiguration,
79	/// Prometheus endpoint configuration. `None` if disabled.
80	pub prometheus_config: Option<PrometheusConfig>,
81	/// Telemetry service URL. `None` if disabled.
82	pub telemetry_endpoints: Option<TelemetryEndpoints>,
83	/// Should offchain workers be executed.
84	pub offchain_worker: OffchainWorkerConfig,
85	/// Enable authoring even when offline.
86	pub force_authoring: bool,
87	/// Disable GRANDPA when running in validator mode
88	pub disable_grandpa: bool,
89	/// Development key seed.
90	///
91	/// When running in development mode, the seed will be used to generate authority keys by the
92	/// keystore.
93	///
94	/// Should only be set when `node` is running development mode.
95	pub dev_key_seed: Option<String>,
96	/// Tracing targets
97	pub tracing_targets: Option<String>,
98	/// Tracing receiver
99	pub tracing_receiver: soil_client::tracing::TracingReceiver,
100	/// Announce block automatically after they have been imported
101	pub announce_block: bool,
102	/// Data path root for the configured chain.
103	pub data_path: PathBuf,
104	/// Base path of the configuration. This is shared between chains.
105	pub base_path: BasePath,
106}
107
108/// Warmup strategy for the trie cache.
109#[derive(Debug, Clone, Copy)]
110pub enum TrieCacheWarmUpStrategy {
111	/// Warm up the cache in a non-blocking way.
112	NonBlocking,
113	/// Warm up the cache in a blocking way.
114	Blocking,
115}
116
117impl TrieCacheWarmUpStrategy {
118	/// Returns true if the warmup strategy is blocking.
119	pub(crate) fn is_blocking(&self) -> bool {
120		matches!(self, Self::Blocking)
121	}
122}
123
124/// Type for tasks spawned by the executor.
125#[derive(PartialEq)]
126pub enum TaskType {
127	/// Regular non-blocking futures. Polling the task is expected to be a lightweight operation.
128	Async,
129	/// The task might perform a lot of expensive CPU operations and/or call `thread::sleep`.
130	Blocking,
131}
132
133/// Configuration of the client keystore.
134#[derive(Debug, Clone)]
135pub enum KeystoreConfig {
136	/// Keystore at a path on-disk. Recommended for native nodes.
137	Path {
138		/// The path of the keystore.
139		path: PathBuf,
140		/// Node keystore's password.
141		password: Option<SecretString>,
142	},
143	/// In-memory keystore. Recommended for in-browser nodes.
144	InMemory,
145}
146
147impl KeystoreConfig {
148	/// Returns the path for the keystore.
149	pub fn path(&self) -> Option<&Path> {
150		match self {
151			Self::Path { path, .. } => Some(path),
152			Self::InMemory => None,
153		}
154	}
155}
156/// Configuration of the database of the client.
157#[derive(Debug, Clone, Default)]
158pub struct OffchainWorkerConfig {
159	/// If this is allowed.
160	pub enabled: bool,
161	/// allow writes from the runtime to the offchain worker database.
162	pub indexing_enabled: bool,
163}
164
165/// Configuration of the Prometheus endpoint.
166#[derive(Debug, Clone)]
167pub struct PrometheusConfig {
168	/// Port to use.
169	pub port: SocketAddr,
170	/// A metrics registry to use. Useful for setting the metric prefix.
171	pub registry: Registry,
172}
173
174impl PrometheusConfig {
175	/// Create a new config using the default registry.
176	pub fn new_with_default_registry(port: SocketAddr, chain_id: String) -> Self {
177		let param = iter::once((String::from("chain"), chain_id)).collect();
178		Self {
179			port,
180			registry: Registry::new_custom(None, Some(param))
181				.expect("this can only fail if the prefix is empty"),
182		}
183	}
184}
185
186impl Configuration {
187	/// Returns a string displaying the node role.
188	pub fn display_role(&self) -> String {
189		self.role.to_string()
190	}
191
192	/// Returns the prometheus metrics registry, if available.
193	pub fn prometheus_registry(&self) -> Option<&Registry> {
194		self.prometheus_config.as_ref().map(|config| &config.registry)
195	}
196
197	/// Returns the network protocol id from the chain spec, or the default.
198	pub fn protocol_id(&self) -> ProtocolId {
199		let protocol_id_full = match self.chain_spec.protocol_id() {
200			Some(pid) => pid,
201			None => {
202				log::warn!(
203					"Using default protocol ID {:?} because none is configured in the \
204					chain specs",
205					crate::DEFAULT_PROTOCOL_ID
206				);
207				crate::DEFAULT_PROTOCOL_ID
208			},
209		};
210		ProtocolId::from(protocol_id_full)
211	}
212
213	/// Returns true if the genesis state writing will be skipped while initializing the genesis
214	/// block.
215	pub fn no_genesis(&self) -> bool {
216		matches!(self.network.sync_mode, SyncMode::LightState { .. } | SyncMode::Warp { .. })
217	}
218
219	/// Returns the database config for creating the backend.
220	pub fn db_config(&self) -> soil_client::db::DatabaseSettings {
221		soil_client::db::DatabaseSettings {
222			trie_cache_maximum_size: self.trie_cache_maximum_size,
223			state_pruning: self.state_pruning.clone(),
224			source: self.database.clone(),
225			blocks_pruning: self.blocks_pruning,
226			pruning_filters: Default::default(),
227			metrics_registry: self.prometheus_registry().cloned(),
228		}
229	}
230}
231
232#[static_init::dynamic(drop, lazy)]
233static mut BASE_PATH_TEMP: Option<TempDir> = None;
234
235/// The base path that is used for everything that needs to be written on disk to run a node.
236#[derive(Clone, Debug)]
237pub struct BasePath {
238	path: PathBuf,
239}
240
241impl BasePath {
242	/// Create a `BasePath` instance using a temporary directory prefixed with "substrate" and use
243	/// it as base path.
244	///
245	/// Note: The temporary directory will be created automatically and deleted when the program
246	/// exits. Every call to this function will return the same path for the lifetime of the
247	/// program.
248	pub fn new_temp_dir() -> io::Result<BasePath> {
249		let mut temp = BASE_PATH_TEMP.write();
250
251		match &*temp {
252			Some(p) => Ok(Self::new(p.path())),
253			None => {
254				let temp_dir = tempfile::Builder::new().prefix("substrate").tempdir()?;
255				let path = PathBuf::from(temp_dir.path());
256
257				*temp = Some(temp_dir);
258				Ok(Self::new(path))
259			},
260		}
261	}
262
263	/// Create a `BasePath` instance based on an existing path on disk.
264	///
265	/// Note: this function will not ensure that the directory exist nor create the directory. It
266	/// will also not delete the directory when the instance is dropped.
267	pub fn new<P: Into<PathBuf>>(path: P) -> BasePath {
268		Self { path: path.into() }
269	}
270
271	/// Create a base path from values describing the project.
272	pub fn from_project(qualifier: &str, organization: &str, application: &str) -> BasePath {
273		BasePath::new(
274			directories::ProjectDirs::from(qualifier, organization, application)
275				.expect("app directories exist on all supported platforms; qed")
276				.data_local_dir(),
277		)
278	}
279
280	/// Retrieve the base path.
281	pub fn path(&self) -> &Path {
282		&self.path
283	}
284
285	/// Returns the configuration directory inside this base path.
286	///
287	/// The path looks like `$base_path/chains/$chain_id`
288	pub fn config_dir(&self, chain_id: &str) -> PathBuf {
289		self.path().join("chains").join(chain_id)
290	}
291}
292
293impl From<PathBuf> for BasePath {
294	fn from(path: PathBuf) -> Self {
295		BasePath::new(path)
296	}
297}
298
299/// RPC configuration.
300#[derive(Debug)]
301pub struct RpcConfiguration {
302	/// JSON-RPC server endpoints.
303	pub addr: Option<Vec<RpcEndpoint>>,
304	/// Maximum number of connections for JSON-RPC server.
305	pub max_connections: u32,
306	/// CORS settings for HTTP & WS servers. `None` if all origins are allowed.
307	pub cors: Option<Vec<String>>,
308	/// RPC methods to expose (by default only a safe subset or all of them).
309	pub methods: RpcMethods,
310	/// Maximum payload of a rpc request
311	pub max_request_size: u32,
312	/// Maximum payload of a rpc response.
313	pub max_response_size: u32,
314	/// Custom JSON-RPC subscription ID provider.
315	///
316	/// Default: [`crate::RandomStringSubscriptionId`].
317	pub id_provider: Option<Box<dyn RpcSubscriptionIdProvider>>,
318	/// Maximum allowed subscriptions per rpc connection
319	pub max_subs_per_conn: u32,
320	/// JSON-RPC server default port.
321	pub port: u16,
322	/// The number of messages the JSON-RPC server is allowed to keep in memory.
323	pub message_buffer_capacity: u32,
324	/// JSON-RPC server batch config.
325	pub batch_config: RpcBatchRequestConfig,
326	/// RPC rate limit per minute.
327	pub rate_limit: Option<NonZeroU32>,
328	/// RPC rate limit whitelisted ip addresses.
329	pub rate_limit_whitelisted_ips: Vec<IpNetwork>,
330	/// RPC rate limit trust proxy headers.
331	pub rate_limit_trust_proxy_headers: bool,
332	/// RPC logger capacity (default: 1024).
333	pub request_logger_limit: u32,
334}
335
336/// Runtime executor configuration.
337#[derive(Debug, Clone)]
338pub struct ExecutorConfiguration {
339	/// Wasm execution method.
340	pub wasm_method: WasmExecutionMethod,
341	/// The size of the instances cache.
342	///
343	/// The default value is 8.
344	pub max_runtime_instances: usize,
345	/// The default number of 64KB pages to allocate for Wasm execution
346	pub default_heap_pages: Option<u64>,
347	/// Maximum number of different runtime versions that can be cached.
348	pub runtime_cache_size: u8,
349}
350
351impl Default for ExecutorConfiguration {
352	fn default() -> Self {
353		Self {
354			wasm_method: WasmExecutionMethod::default(),
355			max_runtime_instances: 8,
356			default_heap_pages: None,
357			runtime_cache_size: 2,
358		}
359	}
360}