use super::light_sync_state::LightSyncState;
use alloc::{boxed::Box, collections::BTreeMap, format, string::String, vec::Vec};
use fnv::FnvBuildHasher;
use hashbrown::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub(super) struct ClientSpec {
pub(super) name: String,
pub(super) id: String,
#[serde(default)]
pub(super) chain_type: ChainType,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub(super) code_substitutes: HashMap<u64, HexString, fnv::FnvBuildHasher>,
pub(super) boot_nodes: Vec<String>,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) telemetry_endpoints: Option<Vec<(String, u8)>>,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) protocol_id: Option<String>,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) fork_id: Option<String>,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) block_number_bytes: Option<u8>,
pub(super) properties: Option<Box<serde_json::value::RawValue>>,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) fork_blocks: Option<Vec<(u64, HashHexString)>>,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) bad_blocks: Option<HashSet<HashHexString, FnvBuildHasher>>,
#[serde(default, skip_serializing)]
#[allow(unused)]
pub(super) consensus_engine: (),
pub(super) genesis: Genesis,
#[serde(default = "Default::default", skip_serializing_if = "Option::is_none")]
pub(super) light_sync_state: Option<LightSyncState>,
#[serde(alias = "relay_chain")]
pub(super) relay_chain: Option<String>,
#[serde(alias = "para_id")]
pub(super) para_id: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub(super) enum ChainType {
Development,
Local,
Live,
Custom(String),
}
impl Default for ChainType {
fn default() -> Self {
Self::Live
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub(super) enum Genesis {
Raw(RawGenesis),
StateRootHash(HashHexString),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub(super) struct RawGenesis {
pub(super) top: BTreeMap<HexString, HexString>,
pub(super) children_default: BTreeMap<HexString, ChildRawStorage>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(super) struct HexString(pub(super) Vec<u8>);
impl core::borrow::Borrow<[u8]> for HexString {
fn borrow(&self) -> &[u8] {
&self.0
}
}
impl serde::Serialize for HexString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
format!("0x{}", hex::encode(&self.0[..])).serialize(serializer)
}
}
impl<'a> serde::Deserialize<'a> for HexString {
fn deserialize<D>(deserializer: D) -> Result<HexString, D::Error>
where
D: serde::Deserializer<'a>,
{
let string = String::deserialize(deserializer)?;
if let Some(hex) = string.strip_prefix("0x") {
let bytes = hex::decode(hex).map_err(serde::de::Error::custom)?;
return Ok(HexString(bytes));
}
Err(serde::de::Error::custom(
"hexadecimal string doesn't start with 0x",
))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub(super) struct ChildRawStorage {
pub(super) child_info: Vec<u8>,
pub(super) child_type: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(super) struct HashHexString(pub(super) [u8; 32]);
impl serde::Serialize for HashHexString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
format!("0x{}", hex::encode(&self.0[..])).serialize(serializer)
}
}
impl<'a> serde::Deserialize<'a> for HashHexString {
fn deserialize<D>(deserializer: D) -> Result<HashHexString, D::Error>
where
D: serde::Deserializer<'a>,
{
let string = String::deserialize(deserializer)?;
if !string.starts_with("0x") {
return Err(serde::de::Error::custom("hash doesn't start with 0x"));
}
let bytes = hex::decode(&string[2..]).map_err(serde::de::Error::custom)?;
if bytes.len() != 32 {
return Err(serde::de::Error::invalid_length(
bytes.len(),
&"a 32 bytes hash",
));
}
let mut out = [0; 32];
out.copy_from_slice(&bytes);
Ok(HashHexString(out))
}
}