1pub 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#[derive(Debug)]
40pub struct Configuration {
41 pub impl_name: String,
43 pub impl_version: String,
45 pub role: Role,
47 pub tokio_handle: tokio::runtime::Handle,
49 pub transaction_pool: TransactionPoolOptions,
51 pub network: NetworkConfiguration,
53 pub keystore: KeystoreConfig,
55 pub database: DatabaseSource,
57 pub trie_cache_maximum_size: Option<usize>,
61 pub warm_up_trie_cache: Option<TrieCacheWarmUpStrategy>,
63 pub state_pruning: Option<PruningMode>,
65 pub blocks_pruning: BlocksPruning,
69 pub chain_spec: Box<dyn ChainSpec>,
71 pub executor: ExecutorConfiguration,
73 pub wasm_runtime_overrides: Option<PathBuf>,
77 pub rpc: RpcConfiguration,
79 pub prometheus_config: Option<PrometheusConfig>,
81 pub telemetry_endpoints: Option<TelemetryEndpoints>,
83 pub offchain_worker: OffchainWorkerConfig,
85 pub force_authoring: bool,
87 pub disable_grandpa: bool,
89 pub dev_key_seed: Option<String>,
96 pub tracing_targets: Option<String>,
98 pub tracing_receiver: soil_client::tracing::TracingReceiver,
100 pub announce_block: bool,
102 pub data_path: PathBuf,
104 pub base_path: BasePath,
106}
107
108#[derive(Debug, Clone, Copy)]
110pub enum TrieCacheWarmUpStrategy {
111 NonBlocking,
113 Blocking,
115}
116
117impl TrieCacheWarmUpStrategy {
118 pub(crate) fn is_blocking(&self) -> bool {
120 matches!(self, Self::Blocking)
121 }
122}
123
124#[derive(PartialEq)]
126pub enum TaskType {
127 Async,
129 Blocking,
131}
132
133#[derive(Debug, Clone)]
135pub enum KeystoreConfig {
136 Path {
138 path: PathBuf,
140 password: Option<SecretString>,
142 },
143 InMemory,
145}
146
147impl KeystoreConfig {
148 pub fn path(&self) -> Option<&Path> {
150 match self {
151 Self::Path { path, .. } => Some(path),
152 Self::InMemory => None,
153 }
154 }
155}
156#[derive(Debug, Clone, Default)]
158pub struct OffchainWorkerConfig {
159 pub enabled: bool,
161 pub indexing_enabled: bool,
163}
164
165#[derive(Debug, Clone)]
167pub struct PrometheusConfig {
168 pub port: SocketAddr,
170 pub registry: Registry,
172}
173
174impl PrometheusConfig {
175 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 pub fn display_role(&self) -> String {
189 self.role.to_string()
190 }
191
192 pub fn prometheus_registry(&self) -> Option<&Registry> {
194 self.prometheus_config.as_ref().map(|config| &config.registry)
195 }
196
197 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 pub fn no_genesis(&self) -> bool {
216 matches!(self.network.sync_mode, SyncMode::LightState { .. } | SyncMode::Warp { .. })
217 }
218
219 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#[derive(Clone, Debug)]
237pub struct BasePath {
238 path: PathBuf,
239}
240
241impl BasePath {
242 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 pub fn new<P: Into<PathBuf>>(path: P) -> BasePath {
268 Self { path: path.into() }
269 }
270
271 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 pub fn path(&self) -> &Path {
282 &self.path
283 }
284
285 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#[derive(Debug)]
301pub struct RpcConfiguration {
302 pub addr: Option<Vec<RpcEndpoint>>,
304 pub max_connections: u32,
306 pub cors: Option<Vec<String>>,
308 pub methods: RpcMethods,
310 pub max_request_size: u32,
312 pub max_response_size: u32,
314 pub id_provider: Option<Box<dyn RpcSubscriptionIdProvider>>,
318 pub max_subs_per_conn: u32,
320 pub port: u16,
322 pub message_buffer_capacity: u32,
324 pub batch_config: RpcBatchRequestConfig,
326 pub rate_limit: Option<NonZeroU32>,
328 pub rate_limit_whitelisted_ips: Vec<IpNetwork>,
330 pub rate_limit_trust_proxy_headers: bool,
332 pub request_logger_limit: u32,
334}
335
336#[derive(Debug, Clone)]
338pub struct ExecutorConfiguration {
339 pub wasm_method: WasmExecutionMethod,
341 pub max_runtime_instances: usize,
345 pub default_heap_pages: Option<u64>,
347 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}