从 SIMD 提案到特性门控激活:Solana 协议升级全流程解析

文章作者:@readylayerone
协议只有在所有用户达成一致时才能正常运作。如果你的协议是静态的或很少变动,这很容易做到;而当你的协议不断变化时,就难得多。即使你让所有人都达成了一致,你又如何在一个支撑整个金融体系的分布式系统上安全地部署这些变更呢?
Solana 有一套多阶段的协议变更流程。参与者通过 Solana Improvement Documents(SIMD)和 Solana Governance Proposals(SGP)提出重大变更。这是对设计、权衡取舍、安全性和向后兼容性进行审查和讨论的场所。一旦提案被接受,主要的验证者客户端(Solana 现在有多个)就会实现该提案,并将其纳入未来的发布版本中。准备就绪后,Solana Foundation 会为每个集群提议最低兼容发布版本,首先在 Testnet 上运行,然后在 Devnet 上运行,最后才落地到 Mainnet。验证者需要在第一个 feature gate 激活截止时间之前升级到至少最低版本。在每个集群内,需要所有验证者同时执行新协议行为的变更,通过通常在预定 epoch 边界激活的 feature gate 在链上生效。
我们将在本文中详细介绍该流程的每个阶段。
SIMD
提出 SIMD 是为了呈现并记录对 Solana 及其开发流程的重大变更。第一份记录 SIMD 流程本身的 SIMD 创建于 2022 年 10 月 18 日。该流程于 2022 年 12 月 16 日在第一次核心开发者会议上向 Solana 核心开发者做了介绍。SIMD 保存了提案变更的记录,允许开发者提供反馈并发现问题,并为实现阶段提供设计规范。变更的范围被有意设定得很宽泛,但一般来说,当变更影响到运行时或虚拟机、共识、SPL 和 Core 程序接口、网络和 RPC 接口、验证者经济模型以及 SIMD 流程本身时,就会提出 SIMD。当相关核心贡献者对提案达成大致共识时,SIMD 即获得批准。截至撰写本文时,这一切都在一个 GitHub 仓库中进行。你可以在 proposals/ 目录下以 Markdown 文件的形式查看所有 SIMD。
SIMD 有以下生命周期:

Idea(想法)
SIMD 作者通常会在想法阶段先发起一个 GitHub discussion。目标是就问题本身、提案的目标以及可能的解决方法达成共同理解。具体来说,参与者想知道该变更是否真的需要一份 SIMD、哪些解决方案是可行的,以及这个想法是否已经准备好形成正式提案。因此,并非所有最初的想法都会发展为正式的 SIMD,最终的提案也可能看起来大不相同。
Draft(草案)
当一个想法发展得足够成熟后,其作者可以在草案阶段撰写正式提案。作者通过仓库上的 pull request(PR)提交书面文档。草案不仅要说明会改变什么,还要说明为什么需要这一变更、它如何融入 Solana 的架构、如何与其他功能交互、考虑过哪些替代方案,以及不同的验证者客户端如何验证它们一致地实现了该变更。具体来说,SIMD 文档通常包含以下章节:
- 摘要
- 动机
- 依赖关系(如适用)
- 新术语
- 详细设计(边界情况、受影响的验证者组件)
- 已考虑的替代方案
- 影响
- 安全性考量
- 缺点(如适用)
- 向后兼容性(如适用)
- 一致性
Review(审查)
pull request 发起后,SIMD 进入审查阶段。相关核心贡献者直接在 PR 本身上发表评论,以便评论和设计决策保持公开记录。审查者可能会要求修改措辞、范围、设计、安全假设、边界情况处理、兼容性要求,以及跨实现测试一致性的拟定方法。
作者负责收集反馈、回应异议,并在适当之处更新提案。不过,并不要求接受每一条建议的修改。
在审查过程中,核心开发者可能意识到建议的变更依赖于另一个 SIMD,因此在继续推进之前,需要等待该依赖被接受、实现或激活。审查将持续进行,直到出现以下情况之一:
- 已接受 – 相关核心贡献者已就该设计方向达成大致共识;Anza 和 Firedancer 团队都必须对 SIMD 表示认可,作者才被允许合并 pull request
- 停滞/搁置 – pull request 连续 6 个月没有新的活动,将被自动关闭
- 撤回 – 作者不再希望推动该提案的采纳,自行关闭提案
SGP
验证者参与另一个独立的提案流程,称为 Solana Governance Proposals(SGP)。SIMD 定义协议设计层面的变更,而 SGP 由验证者发起,这意味着它们更可能涉及验证者经济模型,或者需要从验证者集合那里获得推进信号的广泛协议变更。关于将去通胀率翻倍的 SGP-0002 和关于资源费与包含费的 SGP-0003 都是经济类变更的例子,而像 Alpenglow 这样的提案,如果在相关工作开始之前这套机制就已到位,本来也会先作为 SGP 提出。
该流程由以下阶段组成:
- 提案
- 支持
- 讨论
- 快照
- 投票与覆盖
提案与支持
提案的生命周期由 svmgov 程序管理。只有在其 Vote 账户中质押了至少 100,000 SOL 的验证者才能发起提案。提案一经发起,必须在支持阶段获得链上 15% 质押量的支持。如果未能在 7 个 epoch 内获得所需的支持,该提案将不会进入投票环节。
讨论
在讨论阶段,验证者可以相互辩论那些成功通过的提案,该阶段再持续 7 个 epoch。
快照
讨论阶段结束后,将通过 Node Consensus Network(NCN)程序对验证者集合中的质押分布进行快照。被称为 NCN operator 的特殊验证者由 Solana Turbine 团队挑选,以确保他们满足生成 NCN 快照所需的软硬件要求。一旦至少 66.66% 的 operator 对某个快照投出赞成票,治理程序将从这里获取 vote account 的质押权重。截至撰写本文时,共有 11 个 NCN operator。在绝大多数情况下,他们的状态应当完全相同,除非他们不诚实,或因某种原因与集群产生了分歧。这个快照阶段持续 1 个 epoch。
投票与覆盖
验证者可以在投票阶段的 3 个 epoch 内投出赞成、反对或弃权票。获得至少三分之二质押投票赞成的提案即为通过。要达到法定人数,至少应有总验证者质押量的三分之一参与了对提案的投票。同样在这个阶段,委托质押者(在 DeFi 领域更广泛地被称为 “stakers”)可以覆盖验证者已投出的区块投票中属于其质押份额的部分。
实现
SIMD 被接受后,相关团队将开始实现该变更。对于涉及共识、运行时或验证者行为的变更,将由 Anza 和 Jump 团队分别负责 Agave 和 Firedancer 的实现工作。其他提案则可能需要修改核心程序、RPC 服务、SDK、工具链或生态系统的其他部分。然而,提案被接受并不意味着某个特定团队一定会去实现它;作者或其他有兴趣的贡献者可能需要推动实现工作。
实现工作甚至可能在 SIMD 被接受之前就开始。对于复杂或在技术上存在不确定性的提案,贡献者会在起草和审查期间构建原型,以证明可行性、测量性能或发现设计中的问题。
由于每个验证者客户端的内部架构不同,它们的实现并不会使用相同的代码。但协议行为必须在不同客户端之间保持兼容。因此,团队会使用测试、基准测试、账本重放、跨客户端对比、模糊测试以及其他适合该变更的一致性检查手段。实现工作可能会暴露 SIMD 中的歧义或缺失的边界情况,这就需要对规范进行修订,或通过另一份提案加以补充。
当该功能所需的所有实现都完成开发后,SIMD 将被标记为 Implemented。这一状态意味着必要的代码已经编写并通过测试,准备好在后续的发布版本中加入。
发布与集群采用
验证者客户端通过发布版本管理新版本软件的部署。Agave 和 Firedancer 都会发布 release,供各验证者组织采用。随后,Solana Foundation 会推荐在 Testnet 上使用的版本,验证者可以将软件升级到推荐的版本。Testnet 是一个预发布环境,用于观察协议行为,让所有人都有机会在新版本被推荐用于 Devnet 和 Mainnet 之前发现 bug、边界情况等问题。之后,修复和补丁可能会在未来发布的版本中加入。

只有在低于 10% 的质押处于 delinquent 状态时,才会要求验证者升级软件版本。当验证者至少 128 个 epoch 没有投票时,即被视为 delinquent。如果有 10% 或更多的质押不同步,产生分叉的风险是非常真实的。虽然这种情况可以通过让 delinquent 的验证者重启来轻松解决,但代价高昂,因为他们得不到任何奖励。
一旦发现 Agave 和 Firedancer 版本在 Testnet 上运行稳定(即没有停机),就会以同样的方式为 Devnet 推荐相应版本。但当版本即将部署到 Mainnet 时,发布过程会更加谨慎。

新版本首先会作为 Mainnet Upgrade Candidate 被提出。需要有验证者自愿先行升级,然后网络的其余部分才有信心升级集群的其余部分。这确保了在大规模部署期间不会出现重大故障,尤其是在 feature gate 激活期间。在类似的于多个区域全球部署软件的系统中,这被称为金丝雀发布。但由于 Solana 是去中心化的,何时采用新版本最终由验证者说了算。
Anza 在 Agave GitHub 仓库的一个 Wiki 页面上跟踪后续版本中将包含的变更。你可以看到每个集群中哪些变更包含在哪个最低版本中。
激活
加入发布版本的变更在被集群激活之前不会生效。新版本中会包含该变更的代码,但只有当 feature gate 被标记为激活状态时,软件才会运行它。作为一个模拟示例,Agave 和 Firedancer 中会有类似下面这样的代码:
if feature.is_active() {
new_code()
} else {
old_code()
}
任何单个验证者都不能抢在集群其余部分之前激活某个功能。所有验证者必须在同一个 slot 上一起执行。为了利用链作为协调机制,feature gate 与一个 Solana 账户绑定。其地址是预先生成的,然后提交一笔交易,创建该 Solana 账户。
Feature 账户不会显式指定激活的 slot 编号。账户中包含以下数据,用 Rust 表示如下:
Feature { activated_at: None, }
这会将该功能标记出来,验证者会将其读取为待激活状态。功能将在下一个 epoch 边界之后的第一个 slot 自动激活。例如,如果该 feature 账户是在 Epoch 999 创建的,验证者将在 Epoch 1000 的第一个 slot 激活该变更。
在 epoch 边界处,验证者节点会查找任何拥有上述数据的待激活 feature gate 账户,并激活相应的功能。一旦找到某个待激活的地址,验证者就会将账户数据更改为如下内容:
Feature { activated_at: Some(Slot), }
这将该功能标记为已在集群上激活并生效。这使得我们的 new_code() 代码块得以运行,最终,该变更正式上线。
功能激活从 Testnet 开始,连同支持它们的新版本一起进行。这一过程同样适用于 Devnet 和 Mainnet。
结论
Solana 必须付出这样的努力,才能在整个网络中传播变更,同时不破坏共识或造成网络停机。这一流程确保提案对所有参与者清晰明了、重大变更得到彻底审查、发布信息有效传达给验证者,并且新变更只在正确的时机生效。随着链的不断改进,这一流程解决了协调一个去中心化网络的难题。
- 原文链接: x.com/solana_devs/status...
- 鸿途知科网 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
鸿途知科网
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。