目前现有的加密货币和智能合约平台或多或少都有扩展性的问题,每秒能够处理的交易数量是有限的,一般少于每秒20次。
随着使用公共加密货币和智能合约平台的应用和用户数量的增长,需求用于每秒处理数百和数千次数量级的高交易速率正在增加。
ZILLIQA 就是问题的解决方案。它是一种旨在扩大交易速度的新的区块链平台,随着其的矿工人数的增加,其交易速度还会上升。在以太坊现有的3万名矿工的网络规模下,ZILLIQA 预计会处理以太坊交易速率的大约一千倍。
ZILLIQA白皮书一共分6层来介绍:
- 密码层
- 数据层
- 网络层
- 共识层
- 智能合约层
- 激励层
在ZILLIQA中一共有两种角色:用户和矿工。 ZILLIQA的采矿网络被进一步分成几个小网络,被称为分片。一名矿工被一组叫做DS节点分配给一个分片。这组DS节点也被称为DS委员会。每个分片和DS委员会都有一个领导者。领导者在ZILLIQA的共识协议和网络的整体运作中发挥重要作用。
1.密码层
在白皮书中,我们广泛使用SHA3哈希函数来展示我们的设计。
1.1 Schnorr 签名
简化的多重签名是如何工作的呢?
在介绍细节之前,让我们先了解一下背景:在多重签名方案中,我们有n个签名者,每个签名者都有一对密钥(公钥和私钥)、一个验证签名的验证者和一个汇总各方“签名”的聚合者(aggregator)。为了便于理解,我们现在简单假设所有节点都是诚实的,并且会配合签署消息。
验证者在检验汇总后的签名时,会检查所有签名者是否都正确地签了名。仅当验证者确认所有签名者都正确地签了名之后,验证才算通过,反之则验证失败。
接下来让我们深入细节。
多重签名方案基本上分两步进行。在协议的第一步中,每个节点将其公钥发送给聚合者,聚合者根据公钥的数学形式,通过简单的加法或乘法将之聚合为一个单一的公钥。
例如,聚合公钥= 公钥_1 + 公钥_2 + …+公钥_n。
然后聚合者将聚合公钥转发给验证者从而可以使后者验证聚合签名,与此同时聚合者也将聚合公钥发送给每个签名者让所有人签名。
在第二步中,聚合者启动与每个签名者的交互协议(interactive protocol)。这个交互协议总分包含三个阶段:
1、提交阶段(Commit phase):此阶段每个节点生成一些随机内容并提交给交互协议。加密提交(cryptographic commitment)可以通过这种类比的方式理解:每个节点都秘密地掷骰子,然后将结果写在一张纸上并将其放在一个盒子中锁好,最后发送给聚合者。聚合者无权打开盒子。
2、挑战阶段(Challenge phase):此阶段聚合者首先使用加法或乘法将所有的提交聚合为一个聚合提交,然后使用它以及聚合公钥、消息生成一个挑战,再将挑战发送到所有节点。之后挑战可用于确认所有节点都知道公钥对应的私钥。这与常规数字签名的工作方式类似,即由签名证明签名人确实知道私钥。
3、回应阶段(Response phase):所有节点为了应对挑战会向挑战发送私钥进行回应,之后聚合者将聚合所有的回应。因此回应可被视为签名者知道其公钥对应的私钥的证据。
因此,最后的聚合签名实际上是挑战和聚合回应的信息对,并能验证第一步生成的聚合公钥。
值得注意的是,聚合签名的大小不取决于签名者的数量,它是固定的。
当验证者检查聚合签名时,它检查的不是每个单独签名者是否都正确地遵守协议,而是检查所有签名者作为一个整体是否正确地遵守协议并知道私钥。因此,验证者做出的决定是全有或全无(all-or-nothing)。
1.2 工作证明
ZILLIQA的工作证明使用了以太坊1.0的Pow算法-Ethash.
该算法所采用的一般流程如下所示:
- 存在一个种子, 可以通过块高度直到该点来计算每个块。种子每隔30000块更新一次,称为1个epoch。下一轮的种子由前一轮种子通过SHA3-256计算得来。
- 从种子, 你可以计算一个 16 MB 的伪随机缓存, 用于轻客户端存储缓存。
- 从缓存中, 我们可以生成一个 1 GB 的数据集, 该属性表示数据集中的每个项只依赖于缓存中的少量项。完整的客户和矿工存储这个数据集。数据集会随时间线性增长。
- 挖矿涉及抓取数据集的随机切片并将它们一起哈希。可以通过使用缓存来重新生成所需的数据集的特定部分, 从而低内存的机器可以进行验证, 因为只需存储缓存即可验证。
2. 数据层
广义地说,数据层定义构成ZILLIQA全局状态的数据。
2.1 账户、地址、状态
ZILLIQA是基于账户的系统,一共有两种账户类型:普通账户和和合约账户。
每个帐户由不同类型的地址根据其类型来标识。普通帐户的地址是从帐户的私钥中导出的。对于给定的私钥SK,地址A是一个160位的值,计算为:
Anormal = LSB160 (SHA3-256(PubKey(sk))),
合同帐户的地址是从其创建者的地址和创建者帐户发送了多少交易,也叫做account nonce(下面描述)计算的:
Acontract = LSB160 (SHA3-256(address||nonce)),
其中address是创建者的账户地址,nonce是创建者的nonce值。
每个账户包括如下的状态值:
- account nonce: 一个对从普通账户发送交易数量计数的计数器。对于合约账户,对从该账户创建的合约数量计数。
- balance: 非负值,保存tokens数量。
- code hash: 存储合约代码的SHA3-256摘要,对于普通账户为空字符串摘要。
- storage root: 账户存储的SHA3-256摘要。
2.2 交易
一笔交易包括以下部分:
- version: 当前版本号。
- nonce: 计数器,等于交易的发送方发送的交易数。
- to: 目标账户地址
- amount: 交易数量
- gas price: gas价格
- gas limit: 完成交易所需的最大gas数
- code: 可扩展大小,用于指定合约代码,只有当交易创造一个新的合约账户时才使用。
- data: 可扩展大小,用于指定交易所需的数据,只有当交易调用合约时才使用。
- pubkey: 公钥
- signature: 对整个数据的Schnorr 签名
每个交易都有一个唯一的ID,是以上除了signature部分外的SHA-256摘要
2.3 区块
ZILLIQA定义了两种类型的区块(因此存在两条区块链),交易块(TX-Block)和目录服务块(DS-Block),TX-Block包含用户发送的交易,DS-Block包含参与共识协议的矿工的元数据。
2.3.1 DS Blocks
DS Blocks包含两部分:头部和签名。
其中头部结构如下:
- version: 当前版本号
- previous hash:父块头部的哈希值
- pubkey: 挖到该区块的矿工的公钥
- difficulty: 挖矿难度
- number: 祖先区块的数量
- timestamp: 构建本区块的时间戳
- mixHash: 由nonce计算的摘要,用于检测Dos攻击
- nonce: Pow的解
而签名包括以下两部分:
- signature: 由DS nodes签署的对DS block头部的多重签名。
- bitmap: 记录了哪些DS nodes参与了多重签名,由一个向量B表示,B[i]=1表示第i个DS node参与了签名。
2.3.2 TX Blocks
TX-Block存储由DS块中的节点约定的交易的信息。每个DS-Block都链接到多个TX-Block。一个TX-Block包含头部、数据、签名三部分。
头部结构如下:
- type: 有两种类型,micro block(0x00)和final block(0x01),具体在网络层会有介绍。
- version: 版本号
- previous hash:父块头部的哈希值
- gas limit: 当前每个区块的gas消耗限制
- gas used: 本区块中所有交易消耗的gas数量
- number: 祖先区块的数量
- timestamp: 构建本区块的时间戳
- state root: 代表在所有交易执行之后的全局状态的摘要
- transaction root: 块中所有交易的默克尔树的根的摘要
- tx hashes: 块中每个交易的哈希
- pubkey: 提出这个区块的组长的公钥
- pubkey micro blocks: 提出本块中所有交易的组长的公钥集合,只有当区块为final block时使用。
- parent block hash:上一个final block头部的哈希
- parent ds hash: 父DS-Block的头部哈希
- parent ds block number: 父DS-Block的数
数据部分结构:
- tx count: 块中交易的数量
- tx list: 交易列表
签名部分结构:
- signature: 一系列节点对TX-Block头部的多重签名,根据是final block还是micro block决定哪些节点签名。
- bitmap: 记录了哪些节点参与了多重签名,由一个向量B表示,B[i]=1表示第i个节点参与了签名。
以上的数据结构可以结合ZILLIQA测试网络查看
3. 网络层
ZILLIQA最主要的思想就是分片,即将挖矿网络划分成许多小的碎片,从而实现并行化处理,从而提高交易速率。本节我们提出了网络分片和交易分片的思想。
3.1 网络分片
将网络分片主要分为两步:首先,选举一部分特定的节点作为目录服务委员会(DS委员会),然后将网络分片并将剩余节点指派到不同的分片中。
3.1.1 目录服务委员会
为了促进网络分片,我们首先选举一系列的节点作为,称为目录服务节点。这些节点组成目录服务委员会。这个选举是基于工作证明的算法Pow1,算法的介绍如下:
每个比其他节点先及计算出正确nonce的节点提出一个新的DS Block的头部。随后将头部多播至其他目录服务委员会的节点。目录服务委员会根据提出的头部运行共识并产生签名部分。一旦2f个节点对头部签名,则将其提交至 DS blockchain。DS节点的数量为预先定义的大小n0,前n0个成功挖出DS-block的节点构成目录服务委员会。
两个连续DS-block之间的平均开采时间被称为DS-epoch,这样设定是为了最小化两个竞争块的可能性。在每个DS-epoch开始时,一个新的DS节点将加入,而最老的节点将会退出。这样保证了委员会的节点数量维持在n0.最新加入的节点将成为领导者,来引导本次的共识协议。
3.1.2 解决争议
当多个节点几乎同时挖矿成功时,领导者会选择nonce值最大的头部作为新的头部并构建DS-Block.
3.1.3 构建分片
在委员会被选举出来之后将开始网络分片。一个节点为了想参与底层共识协议,它必须执行Pow2.算法如下:
计算出的正确的nonce将被广播至委员会,当委员会的领导人接收到足够多的nonce时,他将发起一个同意这些nonce解的共识协议。当超过2/3的DS节点对其签名后生效。
假设我们需要l个分片,每个分片有n0个节点。我们会对nonce的值进行排序,前n0个节点将被分配至第一个分片,之后的n0个节点将被分配至第二个分片,以此类推。每个分片中nonce最大的节点将成为该分片的领导。如下图所示:
3.2 新节点加入
当一个新节点加入网络时,他可以尝试计算PoW1以加入委员会或者计算PoW2以加入一个分片。
3.3 交易分片
本节我们将介绍一个特定的交易如何被分配至一个分片以及交易将如何运行。我们用 A→n B表示一笔从A向B转n个ZIL的交易。
3.3.1 交易分配
对于一笔交易,假设我们有l个分片,其编号从0到l-1。这笔交易的分配取决于发送者地址的最右边[log2 l]+1位,发送者的地址为160位整数,则l满足:实际中,l的值将小于100.
例如:假设l的值为80,则选择其最右6+1=7位,假设A的最右地址7位为0011001=25,则将其分配至第25个分片。(这里有个问题,假设A的地址最右7位为1100001=81,此时超出l的总值,白皮书好像没有详细解释这种情况,猜测此时会分配给81-79=2个分片。可能需要查看源代码)。
当交易被分配至指定的分片后,这笔交易会广播至分片中的其他节点。当分片的领导者接收到交易时,领导者将会把这笔交易放入一个TX-Block并运行共识协议。
3.3.2交易处理
由分片提出的区块称为micro block,由委员会提出的区块称为final block.一个micro block包含分片中超过2/3节点的多重签名,分片的领导者会构建一个位图记录那些节点对区块头进行了签名。当一个分片对一个TX-Block达成共识后,领导者将会把区块头部和签名多播给DS节点。DS节点收到后会在委员会内部广播,此时委员会领导者可以收到区块,区块的数据部分可以被异步送达至这些节点。
委员会将其他分片发送的区块收集起来,并在他们自己的另一轮共识协议中达成关于final block的协议。一个final block包含委员会超过2/3节点的多重签名。委员会领导者同样会构建一个位图记录哪些节点参与了签名。随后,final block的头部和签名会多播给各个分片的节点。
在每个分片中,采取以下步骤来处理final block:
- 分片中的每个节点使用DS节点的公钥验证多重签名。如果签名对位图所表示的超过2/3的公钥比对有效,则节点执行下一步检查。
- 对于包含在final block中的每个交易哈希,节点检查其对应的交易内容是否可用。如果对应的交易由节点所属的分片提出,则交易数据的哈希与final block头部中包含的哈希进行比较。如果交易是由另一个分片提出的,则交易数据在分片之间异步共享。
- 一旦交易数据可用,final block的data部分将重建,并将TX-Block加入本地的交易链上,同时更新账户状态和全局状态。
-
如果交易内容不可用,则该节点在其本地视图中暂时使该事务的发送帐户无效,从而该帐户的任何其他未处理的交易将被拒绝,直到本地交易内容能够与全局状态同步。此类被拒绝的交易将必须由发送节点进行重发。
4. 共识层
如以上提到的,每个分片和DS委员会需要分别在微块和终块上跑一个共识协议。在这一块,我们将展示在每一个分片和DS委员会中定义的共识协议的共识层。在讨论中,我们将分片和DS委员会代指为共识组。
4.1 实用拜占庭容错
ZILLIQA共识协议的核心依赖于实用拜占庭容错(PBFT)协议。然而我们通过在PBFT中使用EC-Schnorr多签名来提升效率。EC-Schnorr多重签名的使用将正常情况下的通信延迟从O(n*n)降低为O(n),并将签名大小从O(n)减小到O(1),其中n是共识组的大小。 在这个部分,我们提供PBFT的概述。
在PBFT中,共识组内的所有节点都按顺序排列,它有一个主节点(或领导者),其他节点称为备份节点。 每轮PBFT都有三个阶段,如下所述:
- 预准备阶段: 在这个阶段,领导者宣布该小组将应该达成一致共识的下一个记录(在我们的案例中是TX-Block)
- 准备阶段:在接收到预先准备消息后,每个节点验证其正确性并将准备消息多播给所有其他节点
- 提交阶段:在收到超过2/3n准备消息时,节点向组播组发送提交消息。最后,节点等待超过2/3n的提交消息,以确保有足够数量的节点做出相同的决定。 因此,所有诚实的节点都接受相同的有效记录。
PBFT依靠正确的领导者开始每个阶段,并在足够多节点存在时继续进行。 如果领导是拜占庭,它可能会拖延整个共识协议。 为了应对这一挑战,PBFT提供了视图更改协议来使用另一个取代拜占庭领袖。 如果节点在有限的时间内没有看到任何进展,他们可以独立宣布改变领导者的愿望。 如果超过2/3*n个节点的法定人数决定领导者有问题,那么在已知计划中的下一个领导者就会接管。
由于在准备/提交阶段每个节点的多播,正常情况下PBFT的通信复杂度为O(n*n)
4.2 提高效率
经典的PBFT使用消息认证码(MAC)进行节点之间的认证通信。 由于MAC需要在每两个节点之间共享密钥,所以一个共识组中的节点可以在同一个记录上达成一致,其中每个节点的通信复杂度为O(n*n)。 由于二次复杂性,当委员会有20多个节点时,PBFT变得不切实际。
为了提高效率,我们使用来源于ByzCoin的想法:
- 我们用数字签名替换MAC来有效地减少O(n)的通信开销。
- 与此同时,为了让其他节点能够验证协议,一种典型的方法是从诚实的多数收集签名并将它们附加到协议中,从而导致协商规模与协商组的大小成线性关系。 为了改善这一点,我们使用EC-Schnorr多重签名来将几个签名聚合成O(1) - 大小多重签名
然而,我们不能直接在PBFT设置中使用经典的EC-Schnorr多重签名方案。 这是因为在古典设置中,所有签名者都同意签署给定的消息,并且签名只有在所有签名者都签名后才有效。 在PBFT设置中,我们只需要在共识组中超过2/3*n个节点签署消息。 所需的主要修改之一是为参与签名过程的签名者维护位图B. 如果第i个节点参与该过程,则B [i] = 1,否则为0。位图由领导者构建。 位图可以被任何验证者用来验证签名。 最终的协议留在附录B中。
4.3 Zilliqa共识
在ZILLIQA中,我们使用PBFT作为基础共识协议,并采用两轮EC-Schnorr多重签名来替换PBFT中的准备阶段和提交阶段。 下面将解释对PBFT阶段的不同修改。
- 预准备阶段: 与标准PBFT中一样,领导者将TX-Block或声明(由领导者签名)分发给共识组中的所有节点。
- 准备阶段:所有诚实的节点检查TX块的有效性,并且领导者收集来自超过2/3*n个节点的响应。 这保证领导者提出的陈述是安全的并且与以前的所有历史一致。 签名是使用EC-Schnorr多重签名生成的。 领导者还构建签署TX块的节点的位图
- 提交阶段:为了确保超过2/3n的节点知道超过2/3n节点验证了TX-Block的事实。我们进行第二轮EC-Schnorr多重签名。 正在签署的声明是上一轮生成的多重签名。
在三个阶段结束时,就领导者提出的TX-Block将达成共识。
4.4 领导者改变
在我们的共识协议中,如果领导者是诚实的,它可以不断的推动共识委员会中的节点就新的交易达成协议。 但是,如果领导是拜占庭,它可以有意地延迟或丢弃来自诚实节点的消息,并减慢协议。 为了惩罚这些恶意领导者,我们的协议会定期更改每个分片的领导和DS委员会。 这可以防止拜占庭领袖在无限期的时间内拖延共识协议。 由于所有节点都是有序的,下一个领导者将以循环方式选择。
事实上,每一个micro block后分片的领导者都会改变,并且在每个final block之后DS委员会的领导者也会更改。 让我们假设共识组的大小为n,那么在一个DS-epoch时期内,我们允许的final block的最大值为n,每个final block最多在1个分片聚合1个micro block。
5. 智能合约层
ZILLIQA 中的智能合同语言遵循数据流程编程风格,非常适合运行大规模并行计算。包括简单的计算,比如搜索,排序和线性代数计算等;以及更复杂的运算处理,比如训练神经网络,数据挖掘,财务建模,科学计算等等。
6. 激励层
ZILLIQA的代币被称为Zillings或ZIL。 Zillings为用户提供平台使用权,用于支付交易处理或运行智能合同。任何金额,价值,余额或付款的功能都使用ZIL作为单位来计算。代币供应量为210亿个ZIL。
每个产生的区块都带有一个区块奖励,可以产生新的代币。区块奖励将随着时间的推移而在10年内递减。挖矿的产量是预计在前四年挖掘大约80%的代币,在之后六年内挖掘其余的20%。代币的产生将是“平滑”的,因为在一定数量的区块之后,区块奖励不会大幅减少。区块奖励的平滑减少意味着网络哈希率可以随着时间的推移逐渐减小,从而保持稳定。
十年之后,预计在网络中的节点数量和执行交易的用户方面已经达到了相当大的规模。届时,市场的交易费率会稳定下来,足够维持网络的运行,而不需要新的代币进入系统作为回报,也就是说没有增发。
7. 以太坊分片
V神近期在介绍“Ethereum2.0 Roadmap”中提到用分片技术解决扩展性问题,他这样描述分片“笼统简单地来说,你可以把分片看成是,设置一个区块链,在其中有一百个各自不同的宇宙,每一个宇宙都是一个独立的账户空间。
所以你可以在某个宇宙中拥有一个账户,也可以在数个宇宙中持有一个合约,当然,你还可以在数个宇宙间发起一笔交易,而这笔交易仅仅会对涉及到的这几个宇宙产生影响。”
这句话看上去似乎有些难于理解,请看下图:
从图中我们可以看出,以太坊2.0将以太网络分为两层,上层为现有的以太坊(也叫主链),基本保持不变;下层为各个分片,他们相互独立,拥有不同的账户空间。
各个分片延生属于自己的链,并将最新区块头发给主链。主链收集各个分片的区块头,然后生成主链区块。值得注意的是,在主链上只保存各个分片的区块头,具体交易并不在主链上保存。
从以上特征我们可以看出,以太坊2.0通过引入多个独立分片,可以很大程度上分担主链的压力。一方面,多个分片可以并行处理交易,提升整个系统的吞吐量;
另一方面,分片节点只保存与自己相关的历史状态,主链节点也不用包含分片的具体交易信息,从而可以大大降低节点的存储压力。
也许上面的讲解还不够清晰,举个例子:将以太坊主链比如父亲,分片比作已经分家的三个亲兄弟,老大卖猪肉,老二卖电脑,老三卖衣服,他们都干着不同的事情,各自有各自的账本,但是每隔一段时间都需要向父亲进行汇报。而父亲只记录儿子报给他的摘要信息,具体每一笔具体交易他不用保存。
综述所述:以太坊2.0通过引入相互独立的分片,提升了系统的吞吐能力,也降低了节点的存储压力,并且在需要的时候,增加分片具有相当的灵活性,比如父亲又生了一个儿子,这个儿子去卖水果。
以太坊和Zilliqa对比
项目 | 以太坊2.0 | Zilliqa |
---|---|---|
存储扩展性问题 | 解决 | 没解决 |
吞吐量扩展性问题 | 整体提升,主链没提升 | 主链提升 |
地址空间 | 每个分片一个独立地址空间 | 全网一个地址空间 |
分片共识 | PoS | PBFT |
进度 | 3-5年内实现 | 测试网络已发布 |