chain-spec-generator 13.0.1-beta.196

Generates a chainspec artifact for use in genesis block creation of a Xand network.
Documentation
mod cidr_blocks;
mod limited_agent_identity_configuration;
mod member_identity_configuration;
mod trust_identity_configuration;
mod validator_emissions;
mod validator_identity_configuration;

pub use limited_agent_identity_configuration::LimitedAgentIdentityConfiguration;
pub use member_identity_configuration::MemberIdentityConfiguration;
pub use trust_identity_configuration::TrustIdentityConfiguration;
pub use validator_identity_configuration::ValidatorIdentityConfiguration;

use super::error::GenerateError;
pub use cidr_blocks::parse_cidr_block_list;

pub use crate::cli::commands::generate::config::validator_emissions::ConfigEmissionRate;
use serde_derive::Deserialize;

#[derive(Debug, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct ConfigurationFile {
    pub trust: TrustIdentityConfiguration,
    pub limited_agent: LimitedAgentIdentityConfiguration,
    pub members: Vec<MemberIdentityConfiguration>,
    pub validators: Vec<ValidatorIdentityConfiguration>,
    pub validator_emission_rate: ConfigEmissionRate,
}

impl ConfigurationFile {
    pub fn build_chain_spec_data(&self) -> Result<crate::ChainSpec, GenerateError> {
        Ok(crate::ChainSpec {
            limited_agent: self.limited_agent.build_limited_agent_identity()?,
            members: self
                .members
                .iter()
                .map(|m| m.build_member_identity())
                .collect::<Result<_, _>>()?,
            trust: self.trust.build_trust_identity()?,
            validators: self
                .validators
                .iter()
                .map(|v| v.build_validator_identity())
                .collect::<Result<_, _>>()?,
            validator_emission_rate: (&self.validator_emission_rate).into(),
        })
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        cli::commands::GenerateError,
        public_models::domain::{address::Address, encryption_pub_key::EncryptionPubKey},
    };

    use super::{
        ConfigurationFile, LimitedAgentIdentityConfiguration, MemberIdentityConfiguration,
        TrustIdentityConfiguration, ValidatorIdentityConfiguration,
    };
    use crate::cli::commands::generate::config::validator_emissions::ConfigEmissionRate;
    use assert_matches::assert_matches;
    use std::fs::File;
    use std::path::PathBuf;

    #[test]
    fn build_chain_spec_data__success_with_valid_input() {
        // Given
        let config = ConfigurationFile {
            trust: TrustIdentityConfiguration {
                address: Address("trust_addr".into()),
                encryption_pub_key: EncryptionPubKey([5; 32]),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            limited_agent: LimitedAgentIdentityConfiguration {
                address: Address("la_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            members: vec![MemberIdentityConfiguration {
                address: Address("member_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
                encryption_pub_key: EncryptionPubKey([5; 32]),
            }],
            validators: vec![ValidatorIdentityConfiguration {
                address: "val_addr".into(),
                ip_address_ranges: vec!["127.0.0.1".into()],
                aura_session_key: "aura_key".into(),
                grandpa_session_key: "grandpa_key".into(),
                encryption_pub_key: EncryptionPubKey([6; 32]),
            }],
            validator_emission_rate: ConfigEmissionRate {
                minor_units_per_validator_emission: 100,
                block_quota: 1.try_into().unwrap(),
            },
        };

        // When
        let chain_spec = config.build_chain_spec_data().unwrap();

        // Then
        assert_eq!(chain_spec.trust.address, Address("trust_addr".into()));
        assert_eq!(chain_spec.limited_agent.address, Address("la_addr".into()));
        assert_eq!(chain_spec.members[0].address, Address("member_addr".into()));
        assert_eq!(
            chain_spec.validators[0].key_gen_summary.val_kp_pub,
            "val_addr".into()
        );
        assert_eq!(
            chain_spec
                .validator_emission_rate
                .minor_units_per_validator_emission,
            100
        );
        assert_eq!(
            chain_spec.validator_emission_rate.block_quota,
            1.try_into().unwrap()
        );
    }

    #[test]
    fn build_chain_spec_data__error_with_invalid_trust_ip_address() {
        // Given
        let config = ConfigurationFile {
            trust: TrustIdentityConfiguration {
                address: Address("trust_addr".into()),
                encryption_pub_key: EncryptionPubKey([5; 32]),
                ip_address_ranges: vec!["thisiswrong".into()],
            },
            limited_agent: LimitedAgentIdentityConfiguration {
                address: Address("la_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            members: vec![MemberIdentityConfiguration {
                address: Address("member_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
                encryption_pub_key: EncryptionPubKey([5; 32]),
            }],
            validators: vec![ValidatorIdentityConfiguration {
                address: "val_addr".into(),
                ip_address_ranges: vec!["127.0.0.1".into()],
                aura_session_key: "aura_key".into(),
                grandpa_session_key: "grandpa_key".into(),
                encryption_pub_key: EncryptionPubKey([6; 32]),
            }],
            validator_emission_rate: ConfigEmissionRate {
                minor_units_per_validator_emission: 0,
                block_quota: 1.try_into().unwrap(),
            },
        };

        // When
        let error = config.build_chain_spec_data().unwrap_err();

        // Then
        assert_matches!(error, GenerateError::AddressParse(..));
    }

    #[test]
    fn build_chain_spec_data__error_with_invalid_limited_agent_ip_address() {
        // Given
        let config = ConfigurationFile {
            trust: TrustIdentityConfiguration {
                address: Address("trust_addr".into()),
                encryption_pub_key: EncryptionPubKey([5; 32]),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            limited_agent: LimitedAgentIdentityConfiguration {
                address: Address("la_addr".into()),
                ip_address_ranges: vec!["thisiswrong".into()],
            },
            members: vec![MemberIdentityConfiguration {
                address: Address("member_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
                encryption_pub_key: EncryptionPubKey([5; 32]),
            }],
            validators: vec![ValidatorIdentityConfiguration {
                address: "val_addr".into(),
                ip_address_ranges: vec!["127.0.0.1".into()],
                aura_session_key: "aura_key".into(),
                grandpa_session_key: "grandpa_key".into(),
                encryption_pub_key: EncryptionPubKey([6; 32]),
            }],
            validator_emission_rate: ConfigEmissionRate::default(),
        };

        // When
        let error = config.build_chain_spec_data().unwrap_err();

        // Then
        assert_matches!(error, GenerateError::AddressParse(..));
    }

    #[test]
    fn build_chain_spec_data__error_with_invalid_member_ip_address() {
        // Given
        let config = ConfigurationFile {
            trust: TrustIdentityConfiguration {
                address: Address("trust_addr".into()),
                encryption_pub_key: EncryptionPubKey([5; 32]),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            limited_agent: LimitedAgentIdentityConfiguration {
                address: Address("la_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            members: vec![MemberIdentityConfiguration {
                address: Address("member_addr".into()),
                ip_address_ranges: vec!["thisiswrong".into()],
                encryption_pub_key: EncryptionPubKey([5; 32]),
            }],
            validators: vec![ValidatorIdentityConfiguration {
                address: "val_addr".into(),
                ip_address_ranges: vec!["127.0.0.1".into()],
                aura_session_key: "aura_key".into(),
                grandpa_session_key: "grandpa_key".into(),
                encryption_pub_key: EncryptionPubKey([6; 32]),
            }],
            validator_emission_rate: ConfigEmissionRate::default(),
        };

        // When
        let error = config.build_chain_spec_data().unwrap_err();

        // Then
        assert_matches!(error, GenerateError::AddressParse(..));
    }

    #[test]
    fn build_chain_spec_data__error_with_invalid_validator_ip_address() {
        // Given
        let config = ConfigurationFile {
            trust: TrustIdentityConfiguration {
                address: Address("trust_addr".into()),
                encryption_pub_key: EncryptionPubKey([5; 32]),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            limited_agent: LimitedAgentIdentityConfiguration {
                address: Address("la_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
            },
            members: vec![MemberIdentityConfiguration {
                address: Address("member_addr".into()),
                ip_address_ranges: vec!["127.0.0.1".into()],
                encryption_pub_key: EncryptionPubKey([5; 32]),
            }],
            validators: vec![ValidatorIdentityConfiguration {
                address: "val_addr".into(),
                ip_address_ranges: vec!["thisiswrong".into()],
                aura_session_key: "aura_key".into(),
                grandpa_session_key: "grandpa_key".into(),
                encryption_pub_key: EncryptionPubKey([6; 32]),
            }],
            validator_emission_rate: ConfigEmissionRate::default(),
        };

        // When
        let error = config.build_chain_spec_data().unwrap_err();

        // Then
        assert_matches!(error, GenerateError::AddressParse(..));
    }

    #[test]
    fn serde_yaml__can_parse_reference_yaml_config() {
        // Given
        let repo_root = env!("CARGO_MANIFEST_DIR");
        let filepath = PathBuf::from(repo_root).join("sample_config.yaml");
        let file = File::open(&filepath).unwrap();

        // When
        let res = serde_yaml::from_reader::<_, ConfigurationFile>(file);

        // Then
        res.unwrap();
    }
}