原文作者:PaperMoon团队
Polkadot SDK 提供的 Parachain Template 为自定义平行链开发奠定了坚实基础。通常情况下,一个 Pallet 在 Runtime 中只会被实例化一次。
但在某些复杂业务场景下,我们可能希望:
• 复用同一个 Pallet 的逻辑
• 运行多个配置不同的实例
• 分别承担不同职责
例如:
• 创建多个治理委员会
• 实现多套代币系统
• 区分技术委员会与社区议会
为此,Polkadot SDK 提供了 可实例化 Pallet(Instantiable Pallet)机制,允许同一个 Pallet 在 Runtime 中运行多个相互独立的实例。
本文将以 pallet-collective 为例,系统讲解如何配置和使用多个 Pallet 实例。
通过本文,你将学会:
✅ 识别可实例化 Pallet
✅ 理解实例泛型机制
✅ 为同一 Pallet 配置多个实例
✅ 注册多个实例到 Runtime
✅ 本地运行并验证
✅ 使用 Polkadot.js 测试多实例独立性
准备工作
开始前,请确保你已经具备:
• 可正常运行的 Polkadot SDK 开发环境
• 成功集成过普通 Pallet 的经验
• 熟悉 Runtime 基本结构
什么是可实例化 Pallet?
- Instantiable Pallet 设计原理
并非所有 Pallet 都支持多实例。
支持多实例的 Pallet 会在定义中包含额外的泛型参数 I:
#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
含义说明:
| 参数 | 作用 |
|---|---|
| T | Runtime 配置类型 |
| I | 实例标识类型 |
其中:
• I 用于区分不同实例
• 默认为 (),表示单实例
• 多实例时必须显式指定
- 实例泛型的作用机制
实例参数 I 会贯穿整个 Pallet 结构:
| 模块 | 表现形式 |
|---|---|
| Config | Config |
| Storage | 按实例命名空间隔离 |
| Event | Event<T, I> |
| Call | Call<T, I> |
因此:
👉 不同实例拥有完全独立的状态空间
👉 互不干扰
👉 逻辑复用,数据隔离
添加 pallet-collective 依赖
- 修改 Cargo.toml
打开:
runtime/Cargo.toml
添加 feature:
polkadot-sdk = { workspace = true, features = [
"pallet-collective",
"cumulus-pallet-aura-ext",
"cumulus-pallet-session-benchmarking",
], default-features = false }
- 启用 std 特性
在 [features] 中确认:
[features]
default = ["std"]
std = [
"codec/std",
"cumulus-pallet-parachain-system/std",
"log/std",
"polkadot-sdk/std",
"scale-info/std",
]
避免 Native 编译失败。
理解 pallet-collective 的 Config Trait
Collective 的 Config 定义如下:
pub trait Config<I: 'static = ()>: frame_system::Config {
type RuntimeOrigin;
type Proposal;
type RuntimeEvent;
type MotionDuration;
type MaxProposals;
type MaxMembers;
type DefaultVote;
type SetMembersOrigin;
type WeightInfo;
type MaxProposalWeight;
type DisapproveOrigin;
type KillOrigin;
type Consideration;
}
该配置支持:
• 成员管理
• 提案投票
• 治理执行
• 权重控制
• 押金机制
是 Polkadot 治理体系的核心模块之一。
定义公共参数
在配置实例前,先定义公共参数。
打开:
runtime/src/configs/mod.rs
添加:
parameter_types! {
pub const MotionDuration: BlockNumber = 24 * HOURS;
pub const MaxProposals: u32 = 100;
pub const MaxMembers: u32 = 100;
pub MaxProposalWeight: Weight =
Perbill::from_percent(50) *
RuntimeBlockWeights::get().max_block;
}
说明:
| 参数 | 含义 |
|---|---|
| MotionDuration | 投票时长 |
| MaxProposals | 最大提案数 |
| MaxMembers | 最大成员数 |
| MaxProposalWeight | 最大权重 |
引入实例类型
Polkadot 提供了标准实例标识:
use frame_support::instances::{Instance1, Instance2};
特点:
• 官方提供
• 自动生成唯一类型
• 推荐使用
• 避免冲突
配置第一个实例(技术委员会)
在 runtime/src/configs/mod.rs 中添加:
/// Configure the Technical Committee collective
impl pallet_collective::Config<Instance1> for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = MotionDuration;
type MaxProposals = MaxProposals;
type MaxMembers = MaxMembers;
type DefaultVote =
pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
type SetMembersOrigin = EnsureRoot<AccountId>;
type WeightInfo =
pallet_collective::weights::SubstrateWeight<Runtime>;
type MaxProposalWeight = MaxProposalWeight;
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
type KillOrigin = EnsureRoot<Self::AccountId>;
type Consideration = ();
}
配置第二个实例(理事会)
继续添加:
/// Configure the Council collective
impl pallet_collective::Config<Instance2> for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = MotionDuration;
type MaxProposals = MaxProposals;
type MaxMembers = MaxMembers;
type DefaultVote =
pallet_collective::MoreThanMajorityThenPrimeDefaultVote;
type SetMembersOrigin = EnsureRoot<AccountId>;
type WeightInfo =
pallet_collective::weights::SubstrateWeight<Runtime>;
type MaxProposalWeight = MaxProposalWeight;
type DisapproveOrigin = EnsureRoot<Self::AccountId>;
type KillOrigin = EnsureRoot<Self::AccountId>;
type Consideration = ();
}
可按需区分配置参数。
注册多个实例到 Runtime
打开:
runtime/src/lib.rs
在 runtime 宏中添加:
#[runtime::pallet_index(50)]
pub type TechnicalCommittee = pallet_collective<Instance1>;
#[runtime::pallet_index(51)]
pub type Council = pallet_collective<Instance2>;
示例结构:
#[runtime::pallet_index(0)]
pub type System = frame_system;
// ...
#[runtime::pallet_index(50)]
pub type TechnicalCommittee = pallet_collective<Instance1>;
#[runtime::pallet_index(51)]
pub type Council = pallet_collective<Instance2>;
注意:
| 项目 | 要求 |
|---|---|
| pallet_index | 唯一 |
| 实例参数 | 必须填写 |
| 命名 | 建议语义化 |
编译验证
执行:
cargo build --release
检查:
✅ Trait 实现完整
✅ Index 无冲突
✅ Feature 正确
✅ 依赖无缺失
本地运行测试
-
生成 Chain Spec
chain-spec-builder create -t development
--relay-chain paseo
--para-id 1000
--runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm
named-preset development -
启动节点
polkadot-omni-node --chain ./chain_spec.json --dev
确认正常出块。
Polkadot.js 验证多实例
-
连接节点
ws://127.0.0.1:9944
-
查看 Extrinsics
路径:
Developer → Extrinsics
应看到:
• technicalCommittee

• council

- 支持的方法
常见方法:
• propose
• vote
• close
• setMembers
两个实例完全独立。
验证实例隔离性
进入:
Developer → Chain State
分别查询:
technicalCommittee > members()
council > members()


确认:
✅ 存储隔离
✅ 投票独立
✅ 并行运行
✅ 不互相影响
典型应用场景
多实例最常见用途:
| 场景 | 实现方式 |
|---|---|
| 技术委员会 | Instance1 |
| 社区治理 | Instance2 |
| 财务委员会 | Instance3 |
| 审计委员会 | Instance4 |
一个 Pallet → 多个组织体系。
总结
本文完整演示了:
依赖 → 参数 → 实例 → Config → 注册 → 编译 → 运行 → 验证
掌握后,你可以:
✅ 构建多治理体系
✅ 实现权限分层
✅ 复用核心逻辑
✅ 提升系统可维护性
这是中高级 Runtime 设计的重要能力。
原文链接:https://docs.polkadot.com/parachains/customize-runtime/add-pallet-instances/