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!()
}
主要功能
- 链规范构建:提供了
ChainSpec::builder
方法来构建链规范 - 自定义属性:可以通过
Properties
添加自定义链属性 - 多种链类型支持:支持
Development
、Local
和Live
等不同链类型 - 创世配置:灵活配置初始状态和创世块参数
- 扩展支持:可以通过
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("写入链规范文件失败");
注意事项
- 链规范文件通常包含敏感信息,如私钥种子,应妥善保管
- 生产环境应使用
ChainType::Live
类型 - 可以通过实现
ChainSpecGroup
和ChainSpecExtension
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 回复
Rust区块链节点配置库sc-chain-spec的使用:高效生成与自定义Substrate链规范文件
介绍
sc-chain-spec
是Substrate框架中的一个核心库,用于生成和管理区块链的链规范(chain specification)文件。链规范文件定义了区块链网络的初始配置参数,包括创世状态、共识机制、初始账户和余额等关键信息。
这个库特别适合需要创建自定义Substrate链的开发人员,提供了高效生成和自定义链规范的能力,同时支持JSON和原始格式的输出。
主要功能
- 定义和生成链规范文件
- 支持创世配置的自定义
- 提供链规范的序列化和反序列化功能
- 支持多种输出格式(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("加载链规范失败");
}
最佳实践
- 生产环境使用
ChainType::Live
,测试网络使用ChainType::Development
或ChainType::Local
- 确保创世配置中包含所有必要的pallet配置
- 使用
as_json(true)
生成可读性更好的JSON文件,便于调试 - 对于大型配置,考虑将链规范生成逻辑拆分为多个模块
注意事项
- 修改链规范会影响网络的创世状态,已运行的网络无法更改
- 确保所有节点的链规范文件一致
- 链规范中的WASM运行时必须与节点代码兼容
- 自定义pallet需要在创世配置中正确初始化