更新日志
- 2021-09-07 改成使用 v0.100.0 正式版来适配升级。之后的版本中再激活 Testnet 和 Mainnet。
- 2021-09-08 增加了通过
get_consensus
获取是否已经激活 ckb2021 的说明。
升级概览
升级可以分为两块:
- 因为长期没有升级 ckb 节点积累的不兼容更新,主要集中在 RPC 中。
- 共识版本的更新,这次硬分叉带来了新的共识规则版本 ckb2021,而现行的共识规则版本会被称为 ckb2019。
对应的升级策略分为三步:
- 升级到 v0.100.0。
- 确定 Testnet 和 Mainnet 激活时间后会分别发布新版本,预计是 v0.101.0 和 v0.102.0。发布后直接替换之前的 v0.100.0 即可。这些版本不会引入不兼容的修改。
- 在 ckb2021 激活之后项目也需要对应的切换到新的共识规则。
使用 v0.100.0 连接测试网 Aggron 和主网 Lina 时不会激活 ckb2021,所以第 1 步主要的目的就是适配 RPC 等不兼容性更新。在 v0.100.0 发布之前会有多个 RC 版本供预览,这些 RC 版本和正式的 v0.100.0 对于兼容性测试效果是相同的,不必一一测试。
使用 v0.100.0 版本启动新的 dev 链时,默认是从创世块就激活了 ckb2021,可以用来提前为第 3 步测试。
后文会分别说明如何完成这三步升级。
升级 v0.100.0 或其 RC 版本
CKB 正式上线的最早版本是 0.25.0,其中不兼容性升级只会在中间数字变化时引入。因为 0.43.0 之后跳到了 0.100.0,所以已经经历了 19 次的版本迭代。
不兼容性升级主要包括:
- RPC 修改
- 配置文件修改
- 命令行参数修改
- 数据库迁移
因为历时两年,记录难免会有所缺失,最终还是需要多测试来保证。
RPC 修改
这里按照版本收录了 0.25.0 以来的 RPC 不兼容性修改,可以从当前项目使用的版本开始查阅。跳过的版本说明没有需要关心的 RPC 修改。
0.30
因为发现了一些和 RISC-V 不兼容的地方,从 0.30 起,send_transaction
会检查疑似保存着 RISC-V 二进制的 output cells。如果发现有引起不兼容的指令,交易会被拒绝。
在 ckb2021 激活之后,将会启用新版本的 VM (vm1),原来版本的 VM (vm0) 也会共存。因为在 vm1 中,这些不兼容的地方已经修复,同时也推荐开发者只使用 vm1 来运行合约,所以该项兼容性检查会在 ckb2021 激活之后停用。关于 VM 版本选择详见 0.100 的说明。
0.34
RPC estimate_fee_rate
被移除。如果想通过网络拥堵情况自动调整费率,可以使用 subscription RPC 订阅相关的事件并计算费率,也可以使用最近 N 个块的费率的中位数。
0.35
在 0.35 之前,RPC 出错后的 error code 都是一样的 -3。这个版本开始,不同的错误都有自己的 error code。并且 error message 更方便人来阅读。而像 backtrace 会放到 data 中。
如果之前有根据 error message 来决定程序逻辑的地方,可以参考最新的 RPC 文档,改成使用 error code 来判断。
0.35 同时也为 tx_pool_info
, get_peers
, 和 local_node_info
这几个方法增加了新的返回结果字段。如果有使用到这些方法请参考最新版本的 RPC 文档。
0.36
0.36 废弃了 get_cells_by_lock_hash
和所有 Indexer
模块中的 RPC 方法。这些方法在 0.100 中都已经被移除了。请使用外置的 ckb-indexer 代替。
注意 ckb-indexer 本身也在迭代新版本,兼容 CKB v0.100 的版本是 ckb-indexer 0.3.0.
0.40
RPC get_cellbase_output_capacity_details
被移除,请使用 get_block_economic_state
代替。注意这两个 RPC 传参的区别。CKB 中,块 N 中 cellbase 的 outputs 是发给挖出 N - 11 这个块的矿工的。如果想查询 N - 11 这个块的奖励分布情况,get_block_economic_state
需要传 N - 11 的 hash,而老的 RPC get_cellbase_output_capacity_details
传的是 N 的 hash。
0.42
移除了 RPC get_peers_state
。
0.100
0.100 中主要有三项不兼容的修改,而更重要的是在这三个修改背后的共识的变化。
首先,block header 中的字段 uncles_hash
被移除,它的位置被新字段 extra_hash
取代。同时 block 中会新加一个 extension
字段。字段 uncles_hash
虽然被移除,但是构建 block header 的时候还是要计算的,而 extra_hash
是根据 uncles_hash
和 extension
计算出来的。
- 当
extension
字段缺省时,extra_hash
即为uncles_hash
。 - 当
extension
存在时,extra_hash
等于ckbhash( uncles_hash || ckbhash(extension))
。
在 ckb2021 启用之后 extension
字段是没有任何意义的,但是为了之后的分叉升级,如果有块设置了 extension
是能通过共识的。所以应用有使用到 uncles_hash
的话,需要适应新规则的修改。比如要验证某个 hash 是打包在某个块中的 uncle block,需要在证明中同时包括这个块的 ckbhash(extension)
。
第二,send_transaction
默认开启了白名单。白名单是种预防机制,避免一些常见的错误。在开发者对 CKB 熟悉之后,可以通过 send_transaction
的第二项参数来关闭白名单检查。
第三,Script 结构中的 hash_type
多了一个值 data1
。如果有代码直接处理 molecule 二进制,data1
对应的值是 2.
上文提到了 ckb2021 激活之后,会有两个版本的 VM,vm0 和 vm1。而 hash_type
的取值决定了使用哪个版本的 VM。
hash_type |
before ckb2021 | after ckb2021 |
---|---|---|
data | vm0 | vm0 |
type | vm0 | vm1 |
data1 | invalid | vm1 |
简单来说,使用 type
引用代码,总是使用最新版本的 VM。而使用 data
则是在创建 script 的时候就决定了 VM 版本,不会受升级的影响。比如之后 ckb20xx 带来了 vm2,对应的表格如下
hash_type |
before ckb2021 | after ckb2021 | after ckb20xx |
---|---|---|---|
data | vm0 | vm0 | vm0 |
type | vm0 | vm1 | vm2 |
data1 | invalid | vm1 | vm1 |
data2 | invalid | invalid | vm2 |
如果项目中部署了合约并且使用 type 来引用,因为会自动升级到新版 VM,务必在 ckb2021 激活前测试新版 VM 的兼容性。推荐使用 ckb-standalone-debugger 测试。
如果项目中部署了合约并且使用的 data 来引用,也可以使用 ckb-standalone-debugger
测试看看新版 VM 是否有大幅的 cycles 下降。
- 如果有大幅的下降并且没有兼容性问题,应用中可以在 ckb2021 启用后使用 “data1” 来引用合约。
- 如果有大幅的下降并且有兼容性问题,可以部署新的合约,在 ckb2021 启用后使用 “data1” 来引用新合约代替老合约。
- 如果没有大幅下降的话就没有太大的升级价值,可以继续使用 “data” 来引用老合约。
配置文件修改
运行 ckb run 会提示 deprecated options,主要有两种情况:
- 选项已经被移除了
- 被其它类似的选项代替了
建议新建一个目录生成一份默认的配置文件,使用 diff 来对比升级。或者把 deprecated options 列表发出来,这里就不一一说明了。
在 0.37 引入了 db options file 来调整 RocksDB 的参数。如果通过监控怀疑磁盘 IO 有性能问题,可以使用 db options file 来调整。具体步骤为
- 在
ckb.toml
的[db]
下增加选项options_file = "default.db-options"
。 - 和
ckb.toml
同目录下新建文件default.db-options
,基于 ckb 推荐配置进行修改。
命令行参数修改
0.25.0 之后只有新加的命令和参数。如果出现调用 ckb 失败可以把错误发出来。
数据库迁移
0.35,0.40,0.43 分别引入了需要遍历数据库的迁移。在历史数据已经很多的情况下,建议使用一台新版本的节点同步,然后停机复制 db 目录后再升级节点来避免数据迁移。
升级 v0.101.0 和 v0.102.0
相比 v0.100.0,v0.101.0 和 v0.102.0 不会引入不兼容性更新,唯一区别就是在指定的 epoch 高度激活 ckb2021。在做好适配 ckb2021 的工作后,这一步升级只需要替换 ckb 可执行程序后重启即可。
适配 ckb2021
对于大部分应用来说,最直观的变化就是 VM 新版本的引入。这个已经在升级 RC 版本中的 RPC 修改指南中说明过了。
另一个变化是 ckb2021 中去除了使用 header dep 的 immature 规则,只要是之前链上的块都可以做为 header dep。不过因为使用最近的 header dep 的交易很容易被无效化,对于收款方,应该等待足够的确认数来保证资产安全。而应用应该根据场景来权衡使用多久之前的块作为 header dep。
最后是 since
的一些修改。格式上 ckb2021 更严格。如果是使用 epoch 作为单位,ckb2021 中要求 index 不得大于 length,并且只有 length 为 0 时才能等于 length。对于使用 block header timestamp 相对值的场景,ckb2021 中的开始时间是 cell 被创建出来的那个块的 timestamp,而不是那个块之前 37 个块的中位数。这个修改大大简化了交易构造。
因为 ckb2021 会在 testnet 和 mainnet 某个 epoch 高度激活,应用可以选取一种策略来应对:
- 在激活前提前暂停应用。激活之后再重新上线新版本应用。适合还没有在主网上线的应用。如果已有的 cells 需要迁移的可以在重新上线前留出时间集中处理。
- 根据当前链的 epoch 高度自动切换,比如在应用中通过 Feature Switch 来开启 ckb2021 对应的修改。对于已有的 cells 如果不会引起安全问题建议采取 Lazy Update 的策略,使用到的时候再进行迁移。如果可能有安全问题请及时联系 [email protected] 。在
get_consensus
RPC 中会返回当前网络的激活时间,ckb2021 对应的是 0028, 0029 等 7 个开关的合集。通过和get_tip_header
中的epoch
对比即可知道是否已经激活。如果get_consensus
中开关返回的是null
,表示激活时间还没有确定。