RChain运行原理[5] - Casper共识之估值函数

在上一篇《区块结构与DAG》中讲到了一个名字空间对应一条DAG链,那么它具体是如何生成的?

要回答这个问题,首先需要弄清楚两个子问题:

  1. 验证者(validator)在打包区块时是如何选择父级区块?
  2. 区块(block)在加入到DAG链后如何被认可?

这两个问题相辅相成。其中第二个问题是第一个问题的目标。
一个区块被认可也就是说这个区块内包含的状态变化进入到了终结(Finalized)状态,不能再次发生改变,全网对该区块达成了共识(consensus)。
验证者(validator)都希望自己打包的区块能够进入到终结(Finalized)状态而被其它的大多数认可,不然做的就是无用功,因此第一个问题(选择父级区块)至关重要。

本篇尝试解答第一个问题。

一、消息状态树 与 依据(justifications)

对于一个名字空间(namespace)而言,它具有N个有担保的验证者(bounded validator)。
这些验证者之间彼此知悉,也就是说,其中任何一个验证者知悉其它N-1个验证者的名字(名字在这里只是个ID、标识符),也知悉彼此的担保金额(stake)。
当某个验证者打包完一个新区块,会发送给其它N-1个验证者;而一个验证者收到来自其它验证者的区块时,需要进行验算(检查执行过程与结果是否匹配)。

同一个名字空间中的每一个验证者都维护了该名字空间的元组空间(tuplespace)。 在前面《元组空间》一篇中已经解释了,rholang代码的执行的结果即是tuplespace状态的变迁。
虽然这些验证者维护的是同一个名字空间的tuplespace,但这并不能表示它们各自看到的tuplespace状态就一致。
由于tuplespace中的状态是不断变化的,特别是由于rholang并行执行特性–每个验证者可以自由选择执行不同的rholang代码,从而导致各自得到的tuplespace状态与其它验证者不尽相同甚至矛盾。
在这样一种并行执行的环境下,如果一个验证者只是简单的将接收到的区块在自己想当然的tuplespace状态下验算,十有八九无法得出同样的化简结果,这会导致验证者之间彼此无法认可,更别说共识(consensus)了。

所以,为了保证一个区块能够被来自同一个名字空间的其它验证者验算,区块内仅包含执行日志(reduction log)是不够的,还必须要有该区块打包时所对应的tuplespace状态。

当然,tuplespace的大小是没有任何限制的,如果验证者将整个tuplespace状态都写到区块中,那本系列就到此为止。

这里,RChain采用了消息状态树数据结构巧妙地解决这个问题。

例1 : 某名字空间有两个验证者,其中一个验证者(Validator I)有的本地的消息状态树如下图所示。

RChain运行原理[5] - Casper共识之估值函数_第1张图片

  • 每个打包的区块称之为消息(message), 其中的Genesis是创世区块;
  • 该名字空间一共有两个验证者,因此分别有两列对应两个验证者。每列中的一个圆圈表示该验证者打包的一个区块(消息);
  • 左边那列即对应当前验证者,当前验证者Validator I在生成区块后会将自己生成的区块记入左侧那列中并广播给其它的验证者(也就是Validator II);
  • 右边那列对应的是该名字空间中另一个验证者Validator II。当Validator I接收到它发来的消息时,收到的消息记录记录到右侧这列中。
  • 越靠近上方的消息生成时间离现在时间越近,每列中最上方的消息称为最新的消息(latest message)。
  • 如前文所述,每个区块都有一个parents hash ordered list结构。图中的箭头即为区块的父子引用关系。

消息状态树是一个维护于各验证者本地的数据结构。上图中是验证者Validator I维护的消息状态树;
而另一个验证者Validator II也按照这套逻辑维护了一个类似的消息状态树,唯一不同的是,右侧那列对应的是Validator II自己。

由于每个区块(消息)都包含有状态变化(post state), 因此只需要知道验证者打包时看到的(seen)每列的最新消息(lastest message),就必然知道该验证者当时看到的tuplespace的状态,称之为view。
那么,区块结构中有justifications的字段,它是打包该区块时验证者所看到的消息状态树中所有最新消息的集合。通过这个字段,其它验证者就可以在自己的消息状态树中重建该区块打包时的view。

二、估值函数

上面说到的消息状态树包含了某个验证者看到的全网的状态。每一列对应它看到的(seen)该验证者生成的消息(区块)。实际上在没有终结的(finalized)兄弟(siblings)区块间,可能存在着状态变迁的冲突。
验证者在打包一个新区块前必须选取出一个tuplespace基础状态。这个基础状态必须是无冲突的,而且必须是大多数验证者看到的(seen)状态。
只有在这个基础状态下打包的新区块才有可能进入终结状态并被大多数验证者认可。这个基础状态的选择本质上就是为新区块选择父级区块,也就是区块结构中parents hash ordered list字段的值。

那么,这里我们将消息状态树的状态记为σ; 将选择的结果称为估值(estimate),记为 e。而选择的过程称为估值函数(estimator),记为 ε
它们之间有如下关系:e = ε(σ)。 意即”根据消息状态树的当前状态选择新区块的父级区块”,也叫分支选择(fork choice)

实际上,新区块选取的父级区块一定是消息状态树中的一个或者多个最新消息(latest message)。而前面又说到了justifications对于打包的验证者来说就是打包区块时最新消息的集合。
因此ε(σ)函数也可解读为: justifications(消息状态树的最新区块)中选取一个或者多个区块作为父级区块。

接受到新区块的验证者会先进行验证,其中就会使用到同样的函数ε(σ)来验证父级区块是否设置正确。只有在验证通过后接受方才会将新区块加入到本地的消息状态树。
所以估值函数(estimator)的逻辑在全网是统一的,打包的验证者不能随心所欲地选择父级区块。

三、Casper 共识协议

上文中估值函数(estimator)内部的工作逻辑就来自于Casper共识了, 这里先插进来介绍一些有关共识的背景。

共识协议

首先澄清一个误区:一般习惯称呼PoW、PoS之类的为共识协议,笔者也不能免俗,但实际上这是不准确的。
共识协议是在分布式环境中对某个命题在拜占庭容错度内(Byzantine Fault Tolerance)达成一致的算法。
例如,比特币的共识协议是最长链机制。而PoW是为了保障这种机制能够持续运行下去不会分叉,防止出现拜占庭错误(Byzantine Fault)的手段。
换句话说,PoW或PoS都是防止女巫攻击(sybil attack)的手段,说它们是共识协议以偏概全了。
因此,Casper协议没有也不会去定义具体的PoW或者PoS的细节。它只专注于如何在拜占庭容错环境中达成一致。

同步与异步

共识协议有很多,但是大多都不适用于RChain。
比如常见的一些同步(synchronous)共识协议,实现起来简单有效。
但同步共识协议一般都有纪元、轮数、阶段之类的周期概念,后一个周期必须在前一个周期的基础上演化,这就表示矿工间必须协调同步。
而RChain采用的高度并行的演算模型,从本质上来说它没有周期的概念。或者说每个验证者都是独自执行且具有独立的周期,如果采用同步共识协议必将限制并行度从而失去RhoCalculus的优势。
这就是RChain采用Casper这种异步(asynchronous)共识的一个主要原因。
在绝大多数情况下验证者之间并不需要同步交互,验证者打包发送一个消息后并不需要等待接受确认,即使消息因为网络延迟或者丢失也不会出现灾难性的后果。
每个验证者都各自为政并不需要与其它验证者保持同步,大大加快了打包效率。从这点上来说它非常利于RChain高并行度优点的发挥。

Correct-by-Construction

传统的共识协议都是先协议后证明的设计方式。而Casper协议的设计方式不同。
Casper的设计方法遵循CBC(Correct-By-Contruction)原则,即设立数学模型并证明。

首先Casper CBC提出了一个框架并证明了在拜占庭容错度内,估值安全(estimate safety)必将有共识安全(consensus safety);然后在这个框架下派生(derive)了一系列的协议。

  1. Casper the Friendly Binary Consensus Protocol: 二元共识
  2. Casper the Friendly Ordinal Consensus Protocol: 基数共识
  3. Casper the Friendly List Ordering Protocol: 有序列表共识
  4. Casper the Friendly GHOST Protocol: GHOST共识
  5. Casper the Friendly Concurrent Schedule Replication Protocol: 并行计划共识
  6. Casper the Friendly Sharded Blockchain Protocol: 分区区块链共识

这样一种设计方式就保证了:在数学模型证明框架下设计的协议一定是正确的。
这对于在大规模分布式网络中使用的区块链共识协议至关重要,先协议后证明的方式可能因为后续证明的纰漏而导致灾难性的后果。
而派生自Casper CBC框架下的协议只需在框架内保证估值安全即可获得共识安全,无须重新证明就有了充分的安全性保障。

关于Casper CBC的安全性证明详见论文。

四、Casper TFG

RChain共识基于Casper TFG(the Friendly GHOST)协议,其中的GHOST(Greedy Heaviest Observed Subtree)直译为最重贪婪观察子树。
它被用于从消息状态树中筛选出那条能够达成共识的子树。

前文已经提到,同一个名字空间内的验证者相互知悉,也包括它们各自的stake。在消息状态树中,每个验证者都有一个权重值(weight)受stake影响,权重值与Stake成正比。

例2 :在例1的基础上,假设Validator I权重值是5; Validator II权重值是1。现在Validator I需要打包一个新区块,新区块可应该选择那个区块作为parent呢?

RChain运行原理[5] - Casper共识之估值函数_第2张图片

验证者首先按照如下规则对区块进行打分。

RChain运行原理[5] - Casper共识之估值函数_第3张图片

  • 第一步,最新消息(latest message)的分数等于对应验证者的权重。为左图。
  • 第二步,只上而下地,每个区块的分数等于使用此区块作为父区块分数的和。为右图。

在上面右图的基础上,就可以选出父级区块了。

RChain运行原理[5] - Casper共识之估值函数_第4张图片

  1. 首先找到最新终结区块(lastest finalized blocked),如何判断一个区块是否终结将在下一篇中解释,这里假定创世(Genesis)区块是最新终结区块。
  2. 从最新的终结区块开始,依次向上回溯,比较所有依赖于它的后续区块,选择分数更高的那个。这里先比较A和B,选择B; 然后比较C和D,选择C。
  3. 重复第二部直到到达某个最新区块即为父区块。在这里区块C即为新区块的父区块。

此例中的 Genesis->B->C 这条路径即为 GHOST子树,此子树上的区块会随着后续区块的叠加会不断地向上转换为终结状态。关于终结状态的判定在下一篇中介绍。

五、Inclusive GHOST

在例2中演示了从消息状态树中选取出GHOST的过程。消息状态树是一个DAG结构,选取出来的GHSOT就是上一篇中提到的每个名字空间对应的区块链,
它表示这个名字空间中tuplespace在共识协议下的状态变化。

上一篇提到了名字空间内的验证者能够并行无冲突地运行,那么选取出来的GHOST在某些情况下不应该是条单链,而应该也是条DAG, 具体应该怎么做呢?

例3 : 假设某名字空间内有3个验证者,其中的Validator II有消息状态树如下图。

RChain运行原理[5] - Casper共识之估值函数_第5张图片

  • 假定最新终结块区块是创世块
  • 假定区块C的状态变化与D->E或D->F不冲突
  • 假定区块E的状态变化与区块F冲突

首先第一步选取 Genesis->B->C, 此过程与上一节无异。
然后回过头来又从最新终结区块(lastest finalized blocked)重复这套规则,加了两个限制条件:不能选择分数为零的分支;不能选择和已有选择有任何状态变化重叠的分支。
按照这个规则可以选择出 Genesis->B->D->E。 C和E都是新区块的父级节点,其中E称为继父(stepparent),因为它的分数不是最大的那个。

本文地址 https://blog.csdn.net/wangjia184/article/details/80813671
转载须注明出处

下一篇《Casper共识之安全性保证》

你可能感兴趣的:(rchain,RChain区块链研究)