Rust区块链节点配置库sc-chain-spec的使用:高效生成与自定义Substrate链规范文件

Rust区块链节点配置库sc-chain-spec的使用:高效生成与自定义Substrate链规范文件

概述

sc-chain-spec是Substrate框架中的一个重要组件,用于声明运行时特定的配置文件(又称链规范)。这个crate提供了结构体和工具来高效生成和自定义Substrate区块链的配置规范。

许可证

GPL-3.0-or-later WITH Classpath-exception-2.0

安装

在项目目录中运行以下Cargo命令:

cargo add sc-chain-spec

或者在Cargo.toml中添加:

sc-chain-spec = "45.0.0"

使用示例

以下是使用sc-chain-spec创建自定义链规范的完整示例:

use sc_chain_spec::{ChainSpec, ChainType, Properties};
use serde_json::Value;
use sp_core::{Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};

// 定义链规范结构体
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MyChainSpec {
    #[serde(flatten)]
    base: ChainSpec,
    // 在这里添加自定义字段
    custom_property: String,
}

impl MyChainSpec {
    /// 创建新的链规范
    pub fn new(
        name: String,
        id: String,
        chain_type: ChainType,
        custom_property: String,
    ) -> Result<Self, String> {
        let mut properties = Properties::new();
        properties.insert("ss58Format".into(), 42.into());
        
        Ok(Self {
            base: ChainSpec::builder(
                wasm_binary_unwrap(),
                Extensions {
                    relay_chain: "westend".into(),
                    para_id: 2000,
                }
            )
            .with_name(name)
            .with_id(id)
            .with_chain_type(chain_type)
            .with_properties(properties)
            .build(),
            custom_property,
        })
    }

    /// 从JSON文件加载链规范
    pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
        let file = File::open(path).map_err(|e| format!("Error opening file: {}", e))?;
        let spec = serde_json::from_reader(file)
            .map_err(|e| format!("Error parsing chain spec: {}", e))?;
        Ok(spec)
    }

    /// 生成开发链规范
    pub fn development_config() -> Result<Self, String> {
        let authorities = vec![
            get_authority_keys_from_seed("Alice"),
            get_authority_keys_from_seed("Bob"),
        ];

        Self::new(
            "Development".into(),
            "dev".into(),
            ChainType::Development,
            "custom_value".into(),
        )
        .map(|mut spec| {
            spec.base.set_genesis_config(
                testnet_genesis(
                    authorities,
                    None,
                    None,
                    None,
                    None,
                    true,
                )
            );
            spec
        })
    }
}

// 辅助函数:从种子生成权威密钥
fn get_authority_keys_from_seed<TPair: Pair>(seed: &str) -> TPair::Public {
    TPair::from_string(&format!("//{}", seed), None)
        .expect("静态生成的pair值应该总是有效")
        .public()
}

// 辅助函数:创建创世配置
fn testnet_genesis(
    initial_authorities: Vec<AuraId>,
    root_key: AccountId,
    endowed_accounts: Vec<AccountId>,
    enable_println: bool,
) -> GenesisConfig {
    // 实现创世配置逻辑
    unimplemented!()
}

主要功能

  1. 链规范构建:提供了ChainSpec::builder方法来构建链规范
  2. 自定义属性:可以通过Properties添加自定义链属性
  3. 多种链类型支持:支持DevelopmentLocalLive等不同链类型
  4. 创世配置:灵活配置初始状态和创世块参数
  5. 扩展支持:可以通过Extensions添加特定实现所需的额外数据

高级用法

// 自定义创世配置
fn custom_genesis_config() -> GenesisConfig {
    GenesisConfig {
        system: SystemConfig {
            code: wasm_binary_unwrap().to_vec(),
        },
        balances: BalancesConfig {
            balances: vec![
                (alice(), 1_000_000),
                (bob(), 1_000_000),
                (charlie(), 1_000_000),
            ],
        },
        // 其他模块配置...
    }
}

// 创建自定义链规范
let chain_spec = MyChainSpec::new(
    "My Custom Chain".to_string(),
    "my_custom_chain".to_string(),
    ChainType::Live,
    "special_value".to_string(),
).unwrap();

// 将链规范写入文件
let json = serde_json::to_string_pretty(&chain_spec).unwrap();
std fs::write("custom_spec.json", json).expect("写入链规范文件失败");

注意事项

  1. 链规范文件通常包含敏感信息,如私钥种子,应妥善保管
  2. 生产环境应使用ChainType::Live类型
  3. 可以通过实现ChainSpecGroupChainSpecExtension trait来扩展功能

通过sc-chain-spec库,开发者可以高效地创建和自定义Substrate区块链的配置规范,满足各种不同的区块链应用场景需求。

完整示例代码

以下是一个更完整的示例,展示如何使用sc-chain-spec创建自定义Substrate链规范:

use sc_chain_spec::{ChainSpec, ChainType, GenericChainSpec, Properties};
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};
use std::{fs::File, path::PathBuf};

// 定义自定义链规范结构体
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MyChainSpec {
    #[serde(flatten)]
    base: GenericChainSpec,
    custom_field: String,
}

// 类型别名简化代码
type AccountId = <<sr25519::Public as Public>::Pair as Pair>::Public;
type AuraId = AccountId;

impl MyChainSpec {
    /// 创建新的自定义链规范
    pub fn new(
        name: String,
        id: String,
        chain_type: ChainType,
        custom_value: String,
    ) -> Result<Self, String> {
        // 设置链属性
        let mut properties = Properties::new();
        properties.insert("ss58Format".into(), 42.into());
        properties.insert("tokenDecimals".into(), 12.into());
        properties.insert("tokenSymbol".into(), "CUST".into());

        // 构建基础链规范
        let base = ChainSpec::builder(
            wasm_binary_unwrap(), // 获取WASM运行时二进制
            Extensions {
                relay_chain: "my-relay".into(),
                para_id: 2000,
            },
        )
        .with_name(name)
        .with_id(id)
        .with_chain_type(chain_type)
        .with_properties(properties)
        .build();

        Ok(Self {
            base,
            custom_field: custom_value,
        })
    }

    /// 设置创世配置
    pub fn set_genesis(&mut self) {
        let genesis_config = testnet_genesis(
            // 初始权威节点
            vec![
                get_authority_keys_from_seed::<AuraId>("Alice"),
                get_authority_keys_from_seed::<AuraId>("Bob"),
            ],
            // 根密钥
            get_account_id_from_seed::<AccountId>("Alice"),
            // 预注资账户
            vec![
                get_account_id_from_seed::<AccountId>("Alice"),
                get_account_id_from_seed::<AccountId>("Bob"),
                get_account_id_from_seed::<AccountId>("Charlie"),
            ],
            true,
        );

        self.base.set_genesis_config(genesis_config);
    }

    /// 保存链规范到JSON文件
    pub fn save_to_file(&self, path: PathBuf) -> Result<(), String> {
        let json = serde_json::to_string_pretty(self)
            .map_err(|e| format!("序列化链规范失败: {}", e))?;
        std::fs::write(path, json)
            .map_err(|e| format!("写入文件失败: {}", e))?;
        Ok(())
    }
}

// 从种子生成账户ID
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public
where
    <TPublic::Pair as Pair>::Public: Into<AccountId>,
{
    TPublic::Pair::from_string(&format!("//{}", seed), None)
        .expect("静态生成的密钥应该总是有效")
        .public()
}

// 从种子生成权威密钥
fn get_authority_keys_from_seed<TPublic: Public>(seed: &str) -> TPublic::Public {
    TPublic::Pair::from_string(&format!("//{}", seed), None)
        .expect("静态生成的密钥应该总是有效")
        .public()
}

// 创世配置实现
fn testnet_genesis(
    initial_authorities: Vec<AuraId>,
    root_key: AccountId,
    endowed_accounts: Vec<AccountId>,
    enable_println: bool,
) -> serde_json::Value {
    // 这里应该返回实际的创世配置JSON值
    // 为了示例,我们返回一个简单的JSON对象
    serde_json::json!({
        "system": {
            "code": wasm_binary_unwrap().to_vec(),
        },
        "balances": {
            "balances": endowed_accounts.iter().map(|a| (a, 1_000_000)).collect::<Vec<_>>(),
        },
        "aura": {
            "authorities": initial_authorities,
        },
        "sudo": {
            "key": root_key,
        }
    })
}

// 主函数演示如何使用
fn main() {
    // 创建自定义链规范
    let mut chain_spec = MyChainSpec::new(
        "MyCustomChain".to_string(),
        "my_custom".to_string(),
        ChainType::Live,
        "special_value".to_string(),
    ).expect("创建链规范失败");

    // 设置创世配置
    chain_spec.set_genesis();

    // 保存到文件
    chain_spec.save_to_file("my_custom_spec.json".into())
        .expect("保存链规范文件失败");

    println!("成功创建并保存自定义链规范");
}

这个完整示例展示了如何:

  1. 定义自定义链规范结构体
  2. 添加自定义字段
  3. 设置链属性
  4. 配置权威节点和预注资账户
  5. 生成并保存链规范文件

开发人员可以根据实际需求修改创世配置、链属性和其他参数来创建适合自己区块链项目的规范文件。


1 回复

Rust区块链节点配置库sc-chain-spec的使用:高效生成与自定义Substrate链规范文件

介绍

sc-chain-spec是Substrate框架中的一个核心库,用于生成和管理区块链的链规范(chain specification)文件。链规范文件定义了区块链网络的初始配置参数,包括创世状态、共识机制、初始账户和余额等关键信息。

这个库特别适合需要创建自定义Substrate链的开发人员,提供了高效生成和自定义链规范的能力,同时支持JSON和原始格式的输出。

主要功能

  1. 定义和生成链规范文件
  2. 支持创世配置的自定义
  3. 提供链规范的序列化和反序列化功能
  4. 支持多种输出格式(JSON、原始格式等)

完整示例代码

// 引入必要的库和模块
use sc_chain_spec::{ChainSpec, ChainType, GenericChainSpec};
use serde::{Serialize, Deserialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};
use std::path::PathBuf;

// 定义账户ID类型
type AccountId = <<sr25519::Public as Verify>::Signer as IdentifyAccount>::AccountId;

// 定义创世配置结构体
#[derive(Debug, Serialize, Deserialize)]
pub struct GenesisConfig {
    pub system: SystemConfig,
    pub balances: BalancesConfig,
    pub staking: StakingConfig,
    // 可以添加其他pallet的配置
}

// 系统配置
#[derive(Debug, Serialize, Deserialize)]
pub struct SystemConfig {
    pub code: Vec<u8>,
}

// 余额配置
#[derive(Debug, Serialize, Deserialize)]
pub struct BalancesConfig {
    pub balances: Vec<(AccountId, u128)>,
}

// 质押配置
#[derive(Debug, Serialize, Deserialize)]
pub struct StakingConfig {
    pub stakers: Vec<(AccountId, AccountId, u128)>,
    pub validator_count: u32,
    pub minimum_validator_count: u32,
}

// 从种子生成账户ID
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId 
where
    TPublic::Pair: Pair,
{
    TPublic::Pair::from_string(seed, None)
        .expect("生成配对失败")
        .public()
        .into_account()
}

// 创建自定义链规范
pub fn custom_chain_spec() -> Result<GenericChainSpec<GenesisConfig>, String> {
    // 加载WASM运行时
    let wasm_binary = include_bytes!("../target/wasm32-unknown-unknown/release/node_runtime.wasm");
    
    // 定义初始验证人
    let initial_authorities = vec![
        (
            get_account_id_from_seed::<sr25519::Public>("Alice"),
            get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
        ),
        (
            get_account_id_from_seed::<sr25519::Public>("Bob"),
            get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
        ),
    ];

    // 定义初始账户和余额
    let endowed_accounts = vec![
        (get_account_id_from_seed::<sr25519::Public>("Alice"), 1_000_000),
        (get_account_id_from_seed::<sr25519::Public>("Bob"), 1_000_000),
        (get_account_id_from_seed::<sr25519::Public>("Charlie"), 1_000_000),
    ];

    // 定义质押配置
    let stakers = initial_authorities.iter()
        .map(|(controller, stash)| (controller.clone(), stash.clone(), 1_000))
        .collect();

    // 创建链规范
    GenericChainSpec::from_genesis(
        "Custom Chain",   // 链名称
        "custom",         // 链ID
        ChainType::Live,  // 链类型(生产环境)
        move || GenesisConfig {
            system: SystemConfig {
                code: wasm_binary.to_vec(),
            },
            balances: BalancesConfig {
                balances: endowed_accounts.clone(),
            },
            staking: StakingConfig {
                stakers,
                validator_count: 2,
                minimum_validator_count: 1,
            },
        },
        vec![],           // 启动节点
        None,             // 协议ID
        None,             // 属性
        None,             // 扩展
        None,             // fork_id
    )
}

// 导出链规范为JSON文件
pub fn export_chain_spec() -> Result<(), String> {
    let chain_spec = custom_chain_spec()?;
    let json = chain_spec.as_json(true)?; // true表示美化输出
    
    std::fs::write("custom_chain_spec.json", json)
        .map_err(|e| format!("写入链规范文件失败: {}", e))?;
    
    Ok(())
}

// 从JSON文件加载链规范
pub fn load_chain_spec(path: PathBuf) -> Result<Box<dyn ChainSpec>, String> {
    let chain_spec = GenericChainSpec::<()>::from_json_file(path)?;
    Ok(Box::new(chain_spec))
}

fn main() {
    // 示例使用
    if let Err(e) = export_chain_spec() {
        eprintln!("生成链规范失败: {}", e);
    }
    
    // 加载示例
    let _chain_spec = load_chain_spec(PathBuf::from("custom_chain_spec.json"))
        .expect("加载链规范失败");
}

最佳实践

  1. 生产环境使用ChainType::Live,测试网络使用ChainType::DevelopmentChainType::Local
  2. 确保创世配置中包含所有必要的pallet配置
  3. 使用as_json(true)生成可读性更好的JSON文件,便于调试
  4. 对于大型配置,考虑将链规范生成逻辑拆分为多个模块

注意事项

  1. 修改链规范会影响网络的创世状态,已运行的网络无法更改
  2. 确保所有节点的链规范文件一致
  3. 链规范中的WASM运行时必须与节点代码兼容
  4. 自定义pallet需要在创世配置中正确初始化
回到顶部