CKB v0.100.0 升级指南

[English Version]

更新日志

  • 2021-09-07 改成使用 v0.100.0 正式版来适配升级。之后的版本中再激活 Testnet 和 Mainnet。
  • 2021-09-08 增加了通过 get_consensus 获取是否已经激活 ckb2021 的说明。

升级概览

升级可以分为两块:

  1. 因为长期没有升级 ckb 节点积累的不兼容更新,主要集中在 RPC 中。
  2. 共识版本的更新,这次硬分叉带来了新的共识规则版本 ckb2021,而现行的共识规则版本会被称为 ckb2019。

对应的升级策略分为三步:

  1. 升级到 v0.100.0
  2. 确定 Testnet 和 Mainnet 激活时间后会分别发布新版本,预计是 v0.101.0 和 v0.102.0。发布后直接替换之前的 v0.100.0 即可。这些版本不会引入不兼容的修改。
  3. 在 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_hashextension 计算出来的。

  • 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 高度激活,应用可以选取一种策略来应对:

  1. 在激活前提前暂停应用。激活之后再重新上线新版本应用。适合还没有在主网上线的应用。如果已有的 cells 需要迁移的可以在重新上线前留出时间集中处理。
  2. 根据当前链的 epoch 高度自动切换,比如在应用中通过 Feature Switch 来开启 ckb2021 对应的修改。对于已有的 cells 如果不会引起安全问题建议采取 Lazy Update 的策略,使用到的时候再进行迁移。如果可能有安全问题请及时联系 [email protected] 。在 get_consensus RPC 中会返回当前网络的激活时间,ckb2021 对应的是 0028, 0029 等 7 个开关的合集。通过和 get_tip_header 中的 epoch 对比即可知道是否已经激活。如果 get_consensus 中开关返回的是 null,表示激活时间还没有确定。
4 Likes