Rust区块链开发框架polkadot-sdk-frame的使用,构建高性能Substrate链和Polkadot平行链的核心工具库
FRAME
FRAME开发环境提供了模块(称为"pallets")和支持库,您可以使用、修改和扩展这些模块来构建适合您区块链需求的运行时逻辑。
Metadata
- 版本: 0.11.0
- 发布时间: 7天前
- 版本年份: 2021 edition
- 许可证: Apache-2.0
- 大小: 35.3 KiB
安装
在项目目录中运行以下Cargo命令:
cargo add polkadot-sdk-frame
或添加以下内容到您的Cargo.toml:
polkadot-sdk-frame = "0.11.0"
完整示例代码
以下是一个使用polkadot-sdk-frame构建Substrate链的完整示例:
//! 使用FRAME构建Substrate链的示例
use frame::{prelude::*, runtime::prelude::*};
// 定义我们的运行时配置
#[derive(Default)]
pub struct Runtime;
// 实现Runtime的配置
impl Config for Runtime {
type Index = u32;
type BlockNumber = u32;
type Hash = sp_core::H256;
type Hashing = sp_runtime::traits::BlakeTwo256;
type AccountId = u64;
type Event = ();
}
// 定义我们的pallet
pub mod pallet_example {
use super::*;
// 定义pallet的配置trait
pub trait Config: frame::Config {
type Event: From<Event<Self>> + Into<<Self as frame::Config>::Event>;
}
// 定义pallet
pub struct Pallet<T>(sp_std::marker::PhantomData<T>);
// 定义pallet的事件
#[derive(Debug, Clone, Eq, PartialEq, codec::Enencode, codec::Decode)]
pub enum Event<T: Config> {
SomethingHappened(u32),
}
// 实现pallet
impl<T: Config> Pallet<T> {
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
ensure_signed(origin)?;
Self::deposit_event(Event::SomethingHappened(something));
Ok(())
}
}
}
// 构建我们的运行时
construct_runtime!(
pub struct Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system,
ExamplePallet: pallet_example,
}
);
fn main() {
println!("Substrate链运行时构建示例");
}
这个示例展示了如何使用FRAME框架:
- 定义了一个基本的Runtime配置
- 创建了一个自定义pallet
- 使用construct_runtime!宏构建运行时
要构建平行链,您还需要实现平行链特定的逻辑,如跨链消息传递和共识机制。
扩展完整示例
以下是一个更完整的FRAME开发示例,包含存储、事件和调用:
//! 更完整的FRAME开发示例
use frame::{prelude::*, runtime::prelude::*};
use sp_std::prelude::*;
// 运行时配置
#[derive(Default)]
pub struct Runtime;
impl Config for Runtime {
type Index = u32;
type BlockNumber = u32;
type Hash = sp_core::H256;
type Hashing = sp_runtime::traits::BlakeTwo256;
type AccountId = u64;
type Event = Event;
}
// 自定义pallet
pub mod pallet_template {
use super::*;
// 配置trait
pub trait Config: frame::Config {
type Event: From<Event<Self>> + Into<<Self as frame::Config>::Event>;
}
// pallet存储定义
#[pallet::storage]
pub type Value<T: Config> = StorageValue<_, u32, ValueQuery>;
// pallet事件
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
ValueStored(u32, T::AccountId),
}
// pallet错误
#[pallet::error]
pub enum Error<T> {
/// 值已经存在
AlreadySet,
/// 值溢出
Overflow,
}
// pallet实现
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {
// 设置值的函数
#[pallet::weight(10_000)]
pub fn set_value(
origin: OriginFor<T>,
value: u32,
) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
// 检查值是否已设置
if <Value<T>>::exists() {
return Err(Error::<T>::AlreadySet.into());
}
// 存储新值
<Value<T>>::put(value);
// 触发事件
Self::deposit_event(Event::ValueStored(value, who));
Ok(().into())
}
}
}
// 构建运行时
construct_runtime!(
pub struct Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system,
TemplateModule: pallet_template,
}
);
fn main() {
println!("完整的FRAME开发示例");
}
这个扩展示例包含:
- 存储定义(StorageValue)
- 事件定义和触发
- 错误处理
- 调用函数和权重
- 更完整的pallet结构
您可以根据实际需求扩展这个模板,添加更多功能和逻辑。
1 回复
Rust区块链开发框架polkadot-sdk-frame使用指南
简介
polkadot-sdk-frame是构建Substrate区块链和Polkadot平行链的核心框架,提供了一套模块化组件来简化区块链开发。它是Polkadot生态系统中最重要的发展工具之一,使开发者能够快速构建高性能、可定制的区块链。
主要特性
- 模块化设计,可组合各种区块链组件
- 支持Substrate和Polkadot生态系统
- 高性能运行时执行环境
- 内置共识机制、网络层和RPC接口
- 支持Wasm智能合约
- 丰富的预构建模块(pallets)
安装与设置
首先确保已安装Rust工具链:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update nightly
rustup target add wasm32-unknown-unknown --toolchain nightly
然后创建一个新的Substrate项目:
cargo install --git https://github.com/paritytech/substrate.git --branch polkadot-v1.0.0 substrate-node-template
cargo install --git https://github.com/paritytech/substrate.git --branch polkadot-v1.0.0 substrate-front-end-template
基本使用
1. 创建自定义pallet
// 在pallets/template/src/lib.rs中
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame system::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::storage]
#[pallet::getter(fn something)]
pub type Something<T> = StorageValue<_, u32>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
SomethingStored(u32, T::AccountId),
}
#[pallet::call]
impl<T: Config] Pallet<T> {
#[pallet::weight(10_000)]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
let who = ensure_signed(origin)?;
<Something<T>>::put(something);
Self::deposit_event(Event::SomethingStored(something, who));
Ok(())
}
}
}
2. 将pallet集成到运行时
// 在runtime/src/lib.rs中
impl pallet_template::Config for Runtime {
type Event = Event;
}
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// 其他pallet...
TemplateModule: pallet_template::{Pallet, Call, Storage, Event<T>},
}
);
3. 构建和运行链
# 以开发模式运行
cargo run --release -- --dev
# 生产模式构建
cargo build --release
构建平行链
1. 配置平行链
// 在runtime/src/lib.rs中
impl cumulus_pallet_parachain_system::Config for Runtime {
type Event = Event;
type OnSystemEvent = ();
type SelfParaId = parachain_info::Pallet<Runtime>;
type OutboundXcmpMessageSource = XcmpQueue;
type DmpMessageHandler = DmpQueue;
type ReservedDmpWeight = ReservedDmpWeight;
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
}
2. 注册平行链
// 在node/src/chain_spec.rs中
pub fn local_testnet_config() -> ChainSpec {
ChainSpec::from_genesis(
// ...其他配置
polkadot_runtime_parachains::configuration::HostConfiguration {
max_code_size: MAX_CODE_SIZE,
max_head_data_size: MAX_HEAD_DATA_SIZE,
// ...其他平行链特定配置
},
)
}
高级功能
1. 自定义共识
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
sp_consensus_aura::SlotDuration::from_millis(AURA.slot_duration)
}
fn authorities() -> Vec<AuraId> {
Aura::authorities().into_inner()
}
}
2. 跨链通信(XCM)
impl xcm_config::Config for Runtime {
type Call = Call;
type XcmSender = XcmRouter;
type AssetTransactor = LocalAssetTransactor;
type OriginConverter = xcm_config::OriginConverter;
type IsReserve = NativeAsset;
type IsTeleporter = ();
type LocationInverter = xcm_config::LocationInverter<Ancestry>;
type Barrier = xcm_config::Barrier;
type Weigher = xcm_config::Weigher;
type Trader = xcm_config::Trader;
type ResponseHandler = ();
type AssetTrap = ();
type AssetClaims = ();
type SubscriptionService = ();
}
最佳实践
- 模块化设计:将业务逻辑拆分为独立的pallets
- 最小化运行时:只包含必要的功能以减少Wasm二进制大小
- 安全审计:特别注意存储操作和权重计算
- 测试覆盖:编写全面的单元测试和集成测试
- 链上升级:设计支持无分叉升级的运行时
通过polkadot-sdk-frame,开发者可以充分利用Substrate和Polkadot生态系统的优势,构建高性能、可互操作的区块链解决方案。
完整示例
下面是一个完整的自定义pallet示例,实现了一个简单的存证功能:
// 在pallets/evidence/src/lib.rs中
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use frame_support::{pallet_prelude::*, Blake2_128Concat};
use frame_system::pallet_prelude::*;
use sp_std::vec::Vec;
/// 存证数据结构
#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Evidence<T: Config> {
/// 存证内容哈希
pub hash: [u8; 32],
/// 存证创建者
pub creator: T::AccountId,
/// 创建时间
pub timestamp: u64,
}
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
/// 存储所有存证的哈希值
#[pallet::storage]
#[pallet::getter(fn evidence_hashes)]
pub type EvidenceHashes<T: Config> = StorageValue<_, Vec<[u8; 32]>>;
/// 存储具体的存证内容
#[pallet::storage]
#[pallet::getter(fn evidences)]
pub type Evidences<T: Config> = StorageMap<
_,
Blake2_128Concat,
[u8; 32],
Evidence<T>,
>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// 存证已创建
EvidenceCreated([u8; 32], T::AccountId),
}
#[pallet::error]
pub enum Error<T> {
/// 存证已存在
EvidenceAlreadyExists,
}
#[pallet::call]
impl<T: Config> Pallet<T> {
/// 创建新存证
#[pallet::weight(10_000)]
pub fn create_evidence(
origin: OriginFor<T>,
hash: [u8; 32],
timestamp: u64,
) -> DispatchResult {
let creator = ensure_signed(origin)?;
// 检查存证是否已存在
ensure!(!<Evidences<T>>::contains_key(&hash), Error::<T>::EvidenceAlreadyExists);
let evidence = Evidence {
hash,
creator: creator.clone(),
timestamp,
};
// 更新存储
<Evidences<T>>::insert(&hash, evidence);
<EvidenceHashes<T>>::mutate(|hashes| hashes.push(hash));
// 触发事件
Self::deposit_event(Event::EvidenceCreated(hash, creator));
Ok(())
}
}
}
将此pallet集成到运行时的完整示例:
// 在runtime/src/lib.rs中
// 引入自定义pallet
pub use pallet_evidence;
// 实现pallet配置
impl pallet_evidence::Config for Runtime {
type Event = Event;
}
// 构造运行时
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system,
// 其他pallet...
EvidenceModule: pallet_evidence::{Pallet, Call, Storage, Event<T>},
}
);
这个完整示例展示了一个简单的存证系统,包含了存储定义、事件处理、错误处理和基本业务逻辑。开发者可以基于此模板扩展更复杂的功能。