subxt_lightclient/
chain_config.rs

1// Copyright 2019-2025 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use serde_json::Value;
6use std::borrow::Cow;
7
8/// Something went wrong building chain config.
9#[non_exhaustive]
10#[derive(thiserror::Error, Debug)]
11pub enum ChainConfigError {
12    /// The provided chain spec is the wrong shape.
13    #[error("Invalid chain spec format")]
14    InvalidSpecFormat,
15}
16
17/// Configuration to connect to a chain.
18pub struct ChainConfig<'a> {
19    // The chain spec to use.
20    chain_spec: Cow<'a, str>,
21}
22
23impl<'a> From<&'a str> for ChainConfig<'a> {
24    fn from(chain_spec: &'a str) -> Self {
25        ChainConfig::chain_spec(chain_spec)
26    }
27}
28
29impl From<String> for ChainConfig<'_> {
30    fn from(chain_spec: String) -> Self {
31        ChainConfig::chain_spec(chain_spec)
32    }
33}
34
35impl<'a> ChainConfig<'a> {
36    /// Construct a chain config from a chain spec.
37    pub fn chain_spec(chain_spec: impl Into<Cow<'a, str>>) -> Self {
38        ChainConfig {
39            chain_spec: chain_spec.into(),
40        }
41    }
42
43    /// Set the bootnodes to the given ones.
44    pub fn set_bootnodes<S: AsRef<str>>(
45        self,
46        bootnodes: impl IntoIterator<Item = S>,
47    ) -> Result<Self, ChainConfigError> {
48        let mut chain_spec_json: Value = serde_json::from_str(&self.chain_spec)
49            .map_err(|_e| ChainConfigError::InvalidSpecFormat)?;
50
51        if let Value::Object(map) = &mut chain_spec_json {
52            let bootnodes = bootnodes
53                .into_iter()
54                .map(|s| Value::String(s.as_ref().to_owned()))
55                .collect();
56
57            map.insert("bootNodes".to_string(), Value::Array(bootnodes));
58        } else {
59            return Err(ChainConfigError::InvalidSpecFormat);
60        }
61
62        Ok(ChainConfig {
63            chain_spec: Cow::Owned(chain_spec_json.to_string()),
64        })
65    }
66
67    // Used internally to fetch the chain spec back out.
68    pub(crate) fn as_chain_spec(&self) -> &str {
69        &self.chain_spec
70    }
71}