运行时(Runtime)是什么?为什么 Polkadot 的 Runtime 可以被“像搭积木一样”定制
原文作者:PaperMoon团队
在很多人的理解里,“区块链”像一个封闭的黑盒:规则写死、功能固定、升级困难。你只能选择“用或不用”,很难像做软件产品一样不断迭代。
但在 Polkadot SDK 的世界里,Runtime(运行时)不是一个不可改动的死板规则集合,而是一个可以持续塑形的“系统内核”。它更像一台机器的控制系统:你可以通过添加模块、调整参数、替换部件来改变它的行为,而不必重造整台机器。
这就是 Polkadot SDK 的 FRAME(Framework for Runtime Aggregation of Modularized Entities)想解决的核心问题:把区块链运行规则拆成可组合的模块(pallet),让你用拼装和配置的方式构建链的能力。
Runtime 在链上做什么?
一句话:Runtime 是区块链的核心逻辑。
当一笔交易来到你的链上,链必须回答几个问题:
• 这笔交易是否合法?
• 它要修改哪些状态?
• 修改是否符合链的规则?
• 结果要向外界发出什么事件(event)通知?
这些决策与执行过程,不靠“节点程序(node)”里的任意代码做主,而是由 Runtime 来定义并执行。你可以把 Runtime 理解为:“链上世界的宪法 + 执法系统 + 状态机”。
在 FRAME 架构里,当交易进入链时,frame_executive 会像“总调度中心”一样接收交易,然后把它转交给对应的功能模块(pallet)去执行。

FRAME Runtime 的关键思想:模块化(Pallets)
如果 Runtime 是一整套系统,那么 Pallet(模块)就是系统里的功能组件。
你可以把 Pallet 类比为:
• 操作系统里的“子系统”
• 应用里的“功能模块”
• 乐高积木里的“标准件”
每个 Pallet 负责一类明确的能力。例如:
• 想要账户余额与转账:用 Balances pallet
• 想要治理能力:加入治理相关 pallets
• 想要非常独特的业务规则:写一个自定义 pallet
Pallet 的好处在于:它们是可独立开发、测试、集成的。不需要把所有功能写在一个巨大文件里,也不必从零开始写所有链上逻辑。
一个 Pallet 能做哪些事?
事实上,一个 pallet 几乎可以实现你想要的任何链上能力,包括:
• 提供用户可提交的交易(也就是可调用的链上函数)
• 在链上存储数据(storage)
• 实施业务规则与校验逻辑
• 发出事件(event),让外界知道状态变化
• 以可控方式返回错误(error),避免系统混乱
如果你把 Runtime 看作一个产品,那么 pallet 就是产品功能包。你的链能做什么,取决于你组合了哪些 pallet,以及你如何配置它们。
预置 Pallet 与自定义 Pallet
FRAME 的一个强大之处在于:它既提供了大量预置(pre-built)pallet,又允许你写自定义 pallet。
1)预置 Pallets:通用能力的现成零件
FRAME 提供了覆盖共识、质押、余额、治理等常见功能的 pallet 库。这些 pallet 的特点是:
• 经过长期验证(battle-tested)
• 性能优化
• 开箱可用
对于大多数链的基础能力,优先使用预置 pallet 往往是更稳妥、更高效的选择。
2)自定义 Pallets:为独特需求留出空间
当预置 pallet 无法覆盖你的业务需求时,你可以编写完全自定义逻辑的 pallet,并像使用官方 pallet 一样把它集成进 runtime。
标准功能用成熟FRAME模块解决,差异化功能用自定义模块实现。
你既不受限于“只有内置功能”,也不必在所有领域都从零开工。
Pallet 的结构长什么样?
FRAME 使用大量 Rust 宏(macros)来减少重复代码,让开发者把注意力放在“业务逻辑”上。一个典型 pallet 的骨架大致如下:
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet(_);
#[pallet::config] // snip
#[pallet::event] // snip
#[pallet::error] // snip
#[pallet::storage] // snip
#[pallet::call] // snip
}
FRAME 为每个 pallet 规定了“必须具备的接口区”,从而让它们能被 runtime 统一管理、组合与调用。
每个 pallet 可能包含的核心部分包括:
• #[frame_support::pallet]:声明这是一个 FRAME pallet
• #[pallet::config]:定义配置项与关联类型(可理解为“可插拔参数接口”)
• #[pallet::storage]:定义链上存储
• #[pallet::call]:定义可调度函数(即用户可发起的交易)
• #[pallet::event]:定义事件
• #[pallet::error]:定义错误类型
这种结构看似“模板化”,但它换来的好处是:模块之间可以被标准化地拼装,并且每个模块的行为还能通过 config 进行调整,而不必改源码。
Runtime 定制的几种方式
从实践角度看,runtime 定制通常落在以下几类模式:
1. 加入预置 pallet
从 FRAME 库里选功能模块,加到 runtime 配置里即可。(最常见)
2. 编写自定义 pallet
当你要做的功能不属于通用模块(比如强业务规则、独特的资产模型、特殊权限体系),就写自己的 pallet。
3. 组合多个 pallet 形成复杂行为
一个功能往往不是单一模块就能实现:多个 pallet 可以“叠加”成更复杂的系统行为,它们之间也可以互相调用,必要时共享存储。
4. 通过参数配置改变 pallet 行为
很多 pallet 并不需要你修改代码,你只要在配置 trait 里调整参数,就能改变它的运行方式。
所以,定制 runtime 并不是“重写链”,而更像“配置 + 组合 + 补充”。

为什么模板是定制的最佳起点?
如果你从空白项目开始搭 runtime,会浪费大量时间在工程初始化与基础设施配置上。Polkadot SDK 提供多个起步模板,让你从“可运行的系统”出发再做定制。
原文列出的模板与定位如下(我按“读者选型思路”重写):
• Polkadot SDK Parachain Template(推荐大多数开发者)
已预置常用能力(如 balances、出块、治理),并提供完整 runtime 设置与平行链共识支持。对于学习和开发的平衡最好。
• Polkadot SDK Minimal Template(极简)
仅保留最必要组件,适合想从干净状态构建的人,但需要更多自行补齐工作。
• Polkadot SDK Solochain Template(独立链)
面向“非中继链依赖”的主权链构建,提供适度功能与简化共识。
• OpenZeppelin Runtime Templates(安全取向)
以行业最佳实践为导向,提供偏生产化、默认更严谨的配置;如果你把安全作为首要目标,这类模板更合适。
八、你最终会遇到的几类“定制场景”
原文最后列出了常见场景,我把它们改成更像“学习路线图”的表达方式:
• 把现成 pallet 加进 runtime:最快扩展功能的路径
• 同一个 pallet 运行多实例:在多资产、多系统并行时常用
• 加入智能合约能力:通过 Contracts pallets 让链支持合约执行
• 编写自定义 pallet:实现链的差异化核心功能
• 测试 runtime:对 pallet 做单测、对整套 runtime 做 mock 测试,确保功能正确
这也对应了从“会搭模板”到“会做链”的进阶路线。
结语:把 Runtime 当作产品,而不是一次性工程
当你理解 runtime 的模块化本质之后,会发现 Polkadot 的开发体验更接近现代软件工程:
你不需要把“区块链”当成一坨难以改变的系统,而可以把它当成一个可迭代的产品内核。
• 标准能力用预置 pallet
• 差异化能力用自定义 pallet
• 通过组合与配置构建系统行为
• 通过测试确保每次迭代可控
这就是 FRAME 带来的 runtime 定制方式:不必从零开始,也不必被固定功能限制。
原文链接:https://docs.polkadot.com/parachains/customize-runtime/











