发布版本与更新
ZooBC 更换软件而不更换链。新版本在链上本身公布,每个节点通过其所有者控制的更新程序安装新版本,而新的共识规则只有在三分之二的出块者已经运行它们之后才会启用。没有人能向节点推送软件,新版本也永远不需要新的链。
发布注册表
发布机构是链的创世中指定的一把密钥,它用 RegisterRelease(类型 32)注册每个发布版本:一个版本字符串、一个 32 字节的清单哈希(发布版本文件的指纹)和一个发布地址。发布版本按架构和链分别注册,其版本字符串同时写明两者。一个版本字符串只能注册一次,因此修复需要新的版本,被撤销的版本也永远不能恢复。发布机构还可以撤销发布版本(类型 35),并把自己的角色交给另一把密钥,这需要两步:提议(类型 33)和接受(类型 34)。
已注册的席位对这把密钥拥有制衡权:
- 否决。 当三分之二的已注册席位对某个版本见证“否决”时,该版本即被撤销,效果与发布机构亲自撤销完全相同:自动更新的节点会跳过它,安装程序也会拒绝它。被暂停的席位不计入,因此在有 11 个活跃席位时,否决需要 8 个。每一票都是一条用节点密钥签名的免手续费见证,由运营者亲自投出;没有任何东西会自动投票。
- 更换。 提名新发布机构的投票,只有在其中最早的一票满一周(40,320 个区块)后才会被计数,因此当前持有者能够预见。达到三分之二时,这一角色转移给所投的地址。
注册或撤销都只是建议性的。它引导那些所有者选择了自动更新的节点;运行自己所选二进制文件的运营者不受其影响。任何人都可以对照注册表检查下载的发布版本(见 校验下载的文件)。
更新程序
ZooBC 安装程序会添加一个小型更新程序,它在节点旁边运行,而不是在节点内部运行。它在机器启动 15 分钟后首次运行,之后大约每 10 分钟运行一次(上下浮动 2 分钟)。每次运行时,它向本地节点请求 /api/v1/release/list,寻找适用于其链和机器类型(amd64 或 arm64)、已注册且未撤销、比正在运行的版本更新的最新发布版本。
更新程序只在到期时安装该发布版本:即该发布版本的注册高度,加上更新延迟,再加上本节点自己的时间槽。然后它下载该发布版本,对照链检查其签名和清单哈希,将其安装在正在运行的版本旁边,重启节点并进行健康检查。如果检查失败,它会回滚到旧版本,并在 12 小时后重试失败的更新。
- 延迟在 mainnet 上默认为 2 天(11,520 个区块)。每个节点自行设定,发布机构无法缩短它。它为在有问题的发布版本扩散之前将其撤销留出了时间。
- 时间槽按密钥为节点排序,并分散它们的开始时间,使得默认情况下任何一个区块中最多有 2 个节点开始更新。链永远不会同时失去许多出块者。
- 所有者的开关
auto_update可以是on(默认)、off或chain。设为chain时,更新程序遵循所有者从钱包在链上签署的设置,因此所有者无需登录服务器就能开启或关闭更新。
每个运营者都会在有更新的发布版本时得到通知:更新程序即使处于关闭状态,也会指出该版本及其就绪门槛的状态;节点每天在日志中写入一条警告;节点的 /node/info 路由会报告它;网页钱包会显示横幅;区块浏览器会显示每个节点的版本。
就绪门槛
新的共识规则以规则包的形式随发布版本提供,规则包 id 大于 0。每个区块都带有其出块者的软件版本,就绪门槛会读取它。规则包中的规则在满足以下所有条件的第一个高度上,在每个节点上同时启用:
- 该高度等于或晚于规则包的预定高度,并且在该发布版本注册之后至少 5,760 个区块(一天);
- 至少三分之二的已注册席位(向上取整,不含被暂停的席位)各自在信号窗口内用不低于规则包 id 的版本产出过区块,信号窗口取 720 个区块与每节点 5 个区块中的较大者;
- 该发布版本未被撤销;撤销会中止待启用的规则包。
从该高度起,带有旧版本的区块会被拒绝。未更新的节点没有任何宽限:从第一个被拒绝的轮次起,它就会错过轮次、什么也赚不到并失去分数(见 错过轮次、暂停与除名)。这就是为什么每个新发布版本都会提醒运营者。
由于统计的是出块者而不是区块,与其余部分隔绝的少数派无法单独达到三分之二。任何密钥也无法强制启用:发布机构不签署任何启用消息,而在出块者尚未行动时,单凭高度也绝不会做出决定。这道门槛有已知的局限:它没有截止期限,因此略多于三分之一的席位就能拖住一次升级;它也发现不了有缺陷的发布版本,而这正是延迟和否决的用途。
以 0.5.8 版本启动的链从区块 0 起就启用了全部 121 条共识规则,且没有任何规则被打包,因此这道门槛要到之后的发布版本才首次起作用。如果节点的二进制文件对某条规则启用位置的设定与链上记录不同,节点也会拒绝启动;发布版本还可以附带一个版本锚点,将其与一个已知的脊链区块绑定。