900-383.png

作者:Nic Lin,imToken Labs 资深区块链工程师

本文受众:区块链开发者

如果想复习以太坊 The Merge 的其他改动,可以参考这篇:

https://medium.com/taipei-ethereum-meetup/eth-2-0-cl-el-separation-and-impact-of-the-merge-dbeb6828c907

读者会需要对以太坊 PoS 的术语和机制有基本的了解。

Safe Head 做什么用?

在 PoW 中,如果没有指定你要哪个区块的状态,节点预设就会回传给你 latest 区块的状态,也就是最新的状态。但是进到 PoS 后,PoS 的区块比 PoW 区块更不可靠,因为 PoS 产生区块不需要任何「work」,而是只要是被指派的 proposer 都可以产生一个合法区块。这表示在 PoS 里取 latest 区块的状态会更容易发生区块、状态被回滚(revert),也因此才会出现 Safe Head 这个 Block Tag(safe):一个比 latest 区块还旧一些些但是可靠许多的区块,让 DApp 呈现数据给使用者看的时候,不会因为区块不可靠、经常因为 reorg 而被 revert 导致使用体验变很差。

  • 正常情况下对新区块而言,在出块后约四秒,即会被标为 safe,成为 safe 区块,使该区块更可靠
  • 不过当网络出现问题或有攻击发生时,safe 区块还是有可能 revert 回旧的区块

Proof of Stake

在介绍 Safe Head 之前,先快速复习一下以太坊的 PoS 共识机制。

在 PoS 中,时间被划分为每 12 秒为一个 slot,每 32 个 slot 为一个 epoch。PoS 的 Validator 当前约有接近 43.8 万个,在每个 epoch 全部的 Validator 会被分配到不同的 slot(所以每个 slot 约有 13700 个 Validator),并负责在该 slot 产生 Attestation,产生 Attestation 可以视为投票的动作。此外,每个 slot 的 Validator 还会细分为 64 个不同的 committee(所以每个 committee 约有 214 个 Validator),这是为了支援 Eth2 计划中会有 64 个 Shard Chain 的设计:每个 committee 分别投给不同 Shard Chain 的区块,但在 Sharding 推出前这些 committee 可以先视为同一个 committee。

每一个 Validator 在其 Attestation 中主要要填入两个投票的对象:他支持的区块及 epoch。一个 slot 有 13700 个 Validator,所以一个区块最多会有 13700 张选票投给它;一个 epoch 有 43.8 万个 Validator,所以一个 epoch 最多会有 43.8 万张选票投给它。

针对区块及 epoch 的投票其实分别就是以太坊 PoS 中 Fork Choice Rule 及 Casper FFG 两层共识机制的核心,下面一层是持续不断在增长的区块,共识是靠 Fork Choice Rule 决定,以区块为单位,看的是每个区块的得票数及其子孙区块的得票数;搭建在上面的是运作比较缓慢的 Casper FFG,以 epoch 为单位,看的是每个 epoch 的得票数。

image6.png不断增长的区块,使用的共识是 Fork Choice Rule

image5.pngCasper FFG 是以 epoch 为单位的共识

image7.png两层共识是并行运作的

这篇分析五月 PoS reorg 的文章也有简短但是更细节的共识机制介绍。

Fork Choice Rule

你可能会好奇已经有 Fork Choice Rule 帮忙从多条分叉链中算出目前哪条才是最长链,为什么还会需要再算一个 Safe Head?或是反过来,为什么不干脆用 Safe Head 算法取代 Fork Choice Rule?

其实 Fork Choice Rule 和 Safe Head 可以视为两个不一样的机制。节点需要 Fork Choice Rule 来决定目前最长链是哪一条,proposer 才能将区块建立在最长链之上,即便最新的区块获得的得票数不高,但节点算出的最长链就是这条,所以还是得接在这个最新区块后面。而 Safe Head 是给 DApp、给使用者看的,是节点替他们找出的一个比较旧但是可靠许多的区块。

针对 Fork Choice Rule 其实有不少攻击,例如 Balancing Attack让节点不断在两条分叉链之间切换。其他攻击可以参考最下方 Safe Head 投影片里的第 3 页到第 7 页。这些攻击都有可能造成 reorg,而 Safe Head 其实不是要算出一个区块是可以在攻击发生时还能不被影响,因为 reorg 是没办法避免的。

Casper FFG

因为接下来会提到 Casper FFG 的相关名词,所以在这里先做一个重点提要,在文章末段会有更深入的 Casper FFG 介绍。

  • Casper FFG 有两个产物:Justified Checkpoint 及 Finalized Checkpoint
  • 当 Checkpoint 获得超过 2/3 Validator 投票会变成 Justified Checkpoint,是很安全的区块
  • 当区块连续两个 epoch 都获得超过 2/3 Validator 投票则会变成 Finalized Checkpoint,具有 Finality 性质,是非常非常安全的区块

接下来将会进入今天的正题:Safe Head

Safe Head

在网络正常且没有攻击的情况下,在新区块出块后约四秒,即会被标为 safe,成为 safe 区块,使该区块更可靠。这是因为 Safe Head 是基于每个区块的得票率去做计算,当网络出现问题或攻击正在进行时,一个正常节点所观察到的区块得票率会开始下降,因为那些消失的票数可能投给另一条分叉链上的区块。在这种情况出现时,Safe Head 会停住(而 latest 区块会持续更新)或甚至 revert 回旧的区块。

PoS 节点可以由观察到的得票率变化来做应对,相反的在 PoW 里攻击者暗中建造的链一但成为最长链,正常节点手上的区块就会直接被 reorg 掉,节点没有办法提前观察出异状。

使用范例

  • 读取 Vitalik 最新的余额:await provider.getBalance("vitalik.eth")
  • 读取 Vitalik (在 Safe Head 区块时间点)的余额:await provider.getBalance("vitalik.eth", "safe")

要找出 Safe Head 主要分成两步骤:先算出区块得票率,再算出一个区块包含其所有子孙区块的得票率平均。

先算出区块得票率

要能算出 Safe Head,首先第一步是算出每个区块的得票率。一开始有提到目前每个 slot(也就是每个区块)最多可以获得 13700 张选票,所以得票数除上 13700 就可以算出得票率。

注:如果某个 slot 被指派的 proposer 没有 propose 区块,则被分配到该 slot 的 Validator 就会投给前一个区块。所以其实一个区块的得票数是有可能会高于该 slot 所被分配到的 Validator 数量的。

每个 Attestation 里要填入的值会包含 slot、index 及 beaconBlockRoot 这三个。slot 就是该 Validator 被分配到的 slot,index 是他被分到的 committee 编号,beaconBlockRoot 是它投的区块的 block root。有了这些资料我们就可以为每个区块算出得票数及得票率:针对每个区块找出所有 beaconBlockRoot 和它的 block root 一样的 Attestation,接着要去掉重复的 Validator,这是因为 Validator 签完 Attestation 后会广播到 p2p 网络中,然后这些 Attestation 会被合并(aggregate)起来,而因为负责合并的人可能有多个,所以同一个 Attestation 可能会出现在不同合并者合并后的 Attestation 中。去掉这些重复后的 Attestation 数量就是得票数。

接着算出一个区块包含其所有子孙区块的得票率平均

这里比较难解释,因此直接搭配图示解释比较清楚:

  • 从 Justified Checkpoint 往后的区块开始计算
  • 一个区块本身得票率加上所有子孙区块的得票率平均就是一个区块的 Safe Head 分数
  • 当一个区块的 Safe Head 分数超过 50(即平均得票率超过 50%)则可视为 Safe Head

image4.png场景一

Block 2 的分数为其本身得票率(95%)加上每个子孙区块的得票率(Block 3: 95%、Block 4: 95%、Block 5: 90%)的平均:(95 + 95 + 95 + 90) / 400 = 94% 。以此类推,Block 6 是最新区块,没有得票率,所以 Block 5 分数即为本身得票率。

image2.png场景二:Block 4 平均得票率为 45%,没办法被视为 Safe Head

  • 即便子孙区块出现分叉也算,因为投给这些子孙区块都隐含投给这个区块本身
  • 没出块的 slot 的得票率只能打五折(示例如场景四)

image8.png场景三:如果出现分叉,得票率(Block 5 及 Block 5')可以相加,因为都隐含投给 Block 4 及其祖先区块

image1.png场景四:Slot 4 没出块,在算它自身得票率时需打五折:55/2 = 27.5

image9.png场景五

以上是 Safe Head 的算法,看起来还算能理解,但每个新的区块的得票率都会影响所有祖先区块,且每个区块都要考虑所有(包含分叉)的子孙区块的得票率,所以实践上其实不是这么简单。

还没实践的 Safe Head 算法

但目前这个 Safe Head 算法还没被实践,DApp 如果现在使用 safe 这个 Block Tag 去查询链的状态,都会得到 Justified Checkpoint 那个时间点的状态,也就是目前的 Safe Head 等于 Justified Checkpoint。

Justified Checkpoint 太久了,如果使用 Justified Checkpoint 则 DApp 前端显示的是至少 6.4 分钟以前的信息,或者是使用者送出交易要 6.4 分钟才会显示出来,这都是非常糟糕的使用体验。所以现在还不适合用 safe 这个 Block Tag,但只能用 latest 区块吗?其实到目前为止网络一直都正常且 PoS 运作也都非常顺利,每个区块得票率几乎都是九成以上,所以在过渡期内先用 latest 区块或 Block Confirmation Rule 也不需要担心会常常碰到 reorg(只要没被攻击或是网络没出问题)。

注:只单纯看区块数而不看区块「得票数」的方式都不可靠,例如 PoS 里用 Block Confirmation Rule 就不可靠。不过如同上述,PoS 到现在都运作得非常好,所以不需太担心。

下一篇将介绍 imToken 尝试实践的 Safe Head 版本、除了 Safe Head 之外能做的事、Casper FFG 以及该怎么使用 Checkpoint 和 Safe Head。

参考资料

介绍 Safe Head 算法的投影片:

High confidence block confirmations

特别感谢 Chih-Cheng LiangChang-Wu Chen,Steven Wu 和doublespending 校对本文并提供改进建议。

风险提示:本文内容均不构成任何形式的投资意见或建议。 imToken 对本文所提及的第三方服务和产品不做任何保证和承诺,亦不承担任何责任。数字资产投资有风险,请谨慎评估该等投资风险,咨询相关专业人士后自行作出决定。