type
status
date
slug
summary
tags
category
icon
password
5 区块链共识机制
重难点
- PoW
- PoS
- DPoS
- PBFT
- 共识算法对比
5.1 PoW
简介
- PoW 工作量证明(英文全称为 Proof of Work)早在比特币出现之前就已经有人探索,常见的是利用 HASH 运算的复杂度进行 CPU 运算实现工作量确定,当然也可以利用卷积求导、大质数分解这些复杂的运算来达到工作量证明的目的
- 简单理解就是一份证明,用来确认你做过一定量的工作
- PoW 系统中一定有两个角色,工作者和验证者,他们需要具有以下特点:
- 工作者需要完成的工作必须有一定的量,这个量由工作验证者给出
- 验证者可以迅速的检验工作量是否达标
- 工作者无法自己"创造工作",必须由验证者发布工作
- 工作者无法找到很快完成工作的办法
- 中本聪在其比特币奠基性论文中设计了 PoW 共识机制,其核心思想是通过引入分布式节点的算力竞争来保证数据一致性和共识的安全性
- 比特币系统中, 各节点 (即矿工) 基于各自的计算机算力相互竞争来共同解决一个求解复杂但验证容易的 SHA256 数学难题 (即挖矿)
- 最快解决该难题的节点将获得区块记账权和系统自动生成的比特币奖励
区块结构
比特币的结构分为区块头和区块体,其中区块头细分为:
- 父区块头哈希值:前一区块的哈希值,使用 SHA256(SHA256(父区块头)) 计算。占 32 字节
- 版本:区块版本号,表示本区块遵守的验证规则。占 4 字节
- 时间戳:该区块产生的近似时间,精确到秒的 UNIX 时间戳,必须严格大于前 11 个区块时间的中值,同时全节点也会拒绝那些超出自己 2 个小时时间戳的区块。占 4 字节
- 难度:该区块工作量证明算法的难度目标,已经使用特定算法编码。占 4 字节
- 随机数 (Nonce):为了找到满足难度目标所设定的随机数,为了解决 32 位随机数在算力飞升的情况下不够用的问题,规定时间戳和 coinbase 交易信息均可更改,以此扩展 nonce 的位数。占 4 字节
- Merkle 根:该区块中交易的 Merkle 树根的哈希值,同样采用 SHA256(SHA256()) 计算。占 32 字节
区块体包含的交易列表则附加在区块头后面,其中的第一笔交易是 coinbase 交易,这是一笔为了让矿工获得奖励及手续费的特殊交易
区块体
为了使区块头能体现区块所包含的所有交易,在区块的构造过程中,需要将该区块要包含的交易列表,通过 Merkle Tree 算法生成 Merkle Root Hash,作为交易列表的摘要存到区块头中
由一个根节点、一组中间节点和一组叶节点组成。叶节点包含存储数据或其哈希值,中间节点是它的两个孩子节点内容的哈希值,根节点也是由它的两个子节点内容的哈希值组成。所以 Merkle 树也称哈希树
计算方法
- 其中 data 是将时间戳、版本号、区块高度等信息组合的数据(header),nonce 为一种随机值,D(d) 为目标值,d 为挖矿难度,随着挖矿难度增加,目标值与哈希值也会越难匹配。从式(1)可以看出,PoW 是一个不断枚举的过程,算法使用嵌套哈希函数求解,当新的交易数据出现时,各个区块链节点开始全力运算,当某个节点最先满足式(1)则被称为矿工
- 在比特币中规定每产生 2016 块就会对难度值进行相应的调整,一个区块的验证时间一般为10min 左右
- 搜集当前时间段的全网未确认交易,并增加一个用于发行新比特币奖励的 Coinbase 交易,形成当前区块体的交易集合
- 计算区块体交易集合的 Merkle 根记入区块头,并填写区块头的其他元数据,其中随机数 Nonce 置零
- 随机数 Nonce 加 1;计算当前区块头的双 SHA256 哈希值,如果小于或等于目标哈希值,则成功搜索到合适的随机数并获得该区块的记账权;否则继续步骤 3 直到任一节点搜索到合适的随机数为止
- 如果一定时间内未成功,则更新时间戳和未确认交易集合、重新计算 Merkle 根后继续搜索
难度目标值
- 难度目标值在区块中以“尾数-指数”的格式,编码并存储,这种格式称作“难度位”
- 这种编码的首字节表示指数,后面的 3 字节表示尾数(系数) 以区块 277316 为例,难度位的值为 0x1903a30c,0x19 是指数的十六进制格式,后半部 0x03a30c 是系数
- 计算难度目标值的公式为:
其中 coefficient — 系数,exponent — 指数
由此公式及难度位的值 0x1903a30c,可得:
按十进制计算为:
转化为十六进制后为:
也就是说⾼度为 277,316 的有效区块的头信息哈希值是小于这个目标值的
难度调整
- 难度的调整是在每个完整节点中独立自动发生的
- 每 2,016 个区块中的所有节点都会调整难度
- 难度的调整公式是由最新 2,016 个区块的花费时长与 20,160 分钟(两周,即这些区块以 10 分钟一个速率所期望花费的时长)比较得出的
算法特点
- 效率低。在比特币系统中的区块容量只有 1 MB,其网络中交易量大约为 7 笔/s,出块时间则为10 min 左右
- 资源消耗大。由于矿工节点在挖矿的过程中需要大量的电力与流处理器等挖矿机器
- 去中心化程度较低。中本聪设计比特币挖矿的初衷是每个人都用 CPU 来挖矿,而现在算力大部分掌握在算力矿池手中,矿池与矿池也会联盟来竞争记账权利
5.2 PoS
简介
- PoS 机制全称是 Proof of stake,即为权益证明
- PoS 机制主要是通过权益记账的方式来解决网络的效率低下,资源浪费和各节点的一致性问题
- 原理:提高了节点处理数据的门槛,它规定每个人可以自由的加入进来成为节点,但只有满足一定条件的节点,比如抵押一定数量的代币才有资格成为验证节点,每隔一段时间,会重新选择,选举的结果不能被操纵,也不能被预测,从而避免网络被某一节点所控制
- 2011 年,权益证明共识算法 (Proof of Stake,PoS) 被提出,在 2012 年发布的点点币 (Peercoin,PPC) 中首次实现
- 权益证明共识算法的记账权决定于节点的币龄大小,其中币龄表示为持币数量与持币时间之积。根据币龄权值的大小关系降低了计算机 Hash 计算的难度,这有效缓解了工作量证明的算力浪费,缩短了共识时间,提高了共识的效率
算法流程
币 龄(coinAge)是 指 持 币 数 量 (coins)与持币时间(holdTime)的乘积:
PoS 共识算法给定一个全网统一的难度值 D,以及新打包进区块的元数据 tradeData,寻找满足条件的记数器 timeCounter,使得:
PoS 共识算法不需要矿工枚举所有的随机数 Nonce,而是在 1s 内只允许一次哈希值,大大减轻了计算工作量,从而减缓了算力竞争带来的资源消耗
算法举例
例如当前全网的难度值是 4369,A 矿工输入的币龄是 15,那么 A 矿工的目标值为 65535,换算成十六进制就是 0xFFFF,完整的哈希长度假设是 8 个字节,也就是 0x0000FFFF。而 B 矿工比较有钱,他输入的币龄是 240,那么 B 矿工的目标值就是 0x000FFFFF,所以 B 矿工获得记账权的概率肯定要比 A 高
算法特点
- PoS 是通过权益大小来寻找哈希值,不存在因算力竞争浪费能源的问题
- 由于 PoS 共识算法采用类似“币龄”的权益 值,并对成功挖矿者采用了币龄“清零”机制,PoS 共识算法更加公平
- 为了防止节点离线积累币龄,2014 年 Vasin 提出了 PoS2.0 并应用到黑币(BlackCoin)中,从而使黑币从模式发展到了纯 PoS 共识模式。PoS2.0 共识算法中的权益大小与用户当时的 PoW+PoS 共识在线时间成正比,这种激励机制有效增强了区块链 P2P 网络的健壮性
- PoS 共识算法容易产生分叉,且区块链的去中心化特点被弱化
5.3 DPoS
简介
- 针对 PoS 共识算法主要存在离线节点积累币龄和某些拥有权益的节点无意挖矿等缺陷,2014 年 4 月,Larimer 在 PoS 共识算法的基础上提出了委托权益证明(delegated proof of stake,DPoS)共识算法
- DPoS 共识算法引入了类似企业董事会的管理机制, 权益持有者通过投票方式选择能够代表自己利益的委托人(票数与持有代币的多少成正比),被选出的受信任的委托人需要交纳一定数量的保证金,最后形成一个由 101 个委托人组成的集合
- 该集合中的委托人将以平等的权利按规则轮流作为出块者生成区块,并从每笔交易的手续费中获得收益
算法流程
DPoS 通过选举见证人的方式行使权利,具体流程如下:
- 选举出块者。见证人即代表,通过持有选票者投票选举产生。见证人在系统中保持中立,每 24 小时更新一次,且投票情况决定其收益。持有选票的节点根据自己的意愿给被选举节点投票,投票的总数大于全网票数的 1/2 则选举有效,得票最高的 101 个节点成为见证人
- 提出区块。见证人轮流产生区块,签名、添加时间戳、广播新块。见证人在规定时间内没有产生新块,超时后,将由下一个见证人产生新区块
- 验证区块。“董事会”中的其他见证人将验证新产生区块的合法性,验证结果为合法新区块才能上链
- 更新区块链。验证结果合法的新区块上链,更新区块链
算法特点
DPoS 算法的优点:
- 能耗更低。DPoS 在确保网络安全的前提下,能够降低全网功耗,网络运营成本比较低
- 交易更快。减少了记账节点的数量,提升了区块验证和记账速度,能达到秒级共识
DPoS 算法的缺点:
- 节点收益不够合理。DPoS 按照得票股份分红,落选的备选见证人节点对于整个系统产生的边际收益小,分红收益低,对于落选的备选见证人节点收益分配不合理
- 投票积极性不高。投票需要花费各种资源,使大多数节点积极性降低,甚至有百分之九十的持股人都从未参与过投票
- 安全隐患。对于出现离线节点、坏节点或恶意节点的情况,DPoS 不能及时处理,因此网络安全存在极大的隐患
5.4 PBFT
简介
- 1999 年,Castro M 和 Liskov B 提出了拜占庭容错算法 (Practical Byzantine Fault Tolerance,PBFT),算法提出之初是为了解决拜占庭将军问题。PBFT 能提升系统的响应速度,同时有效降低复杂度,之后在其他领域有较为广泛的应用
- PBFT 中将节点分为客户端节点 (Client) 和共识节点,共识节点包含主节点 (Primary) 和副本节点 (Replica)
- Client 负责发送请求
- Primary 负责对请求消息进行排序,并将相关消息广播至所有 Replica,每轮共识过程有且只有一个 Primary
- Replica 负责区块共识,在验证并通过来自 Primary 的消息之后执行相关操作并将结果返回给 Client,每轮共识过程有多个 Replica 且工作内容类似
主要流程
PBFT的共识属于典型的三阶段,分别为预准备 (pre-prepare)、准备 (prepare) 和确认 (commit) 等阶段,主要过程如下:
- Client 提出请求,将请求消息发送给 Primary
- 预准备阶段:Primary 接收请求消息,对请求消息进行处理形成预准备消息,然后将预准备消息广播发送至所有 Replica
- 准备阶段:所有 Replica 节点接收预准备消息,验证预准备消息摘要是否被篡改, 若未被篡改,则将预准备消息处理成为准备消息,然后将准备消息广播至所有共识节点
- 确认阶段:共识节点接收并验证准备消息,若准备消息为真则将生成确认消息并广播至其他的共识节点
- 共识节点在接收和验证确认消息后,生成结果,然后将结果返回给 Client
注意:在 pre-prepare 阶段中,消息只由 Primary 发送,在 prepare 阶段中 Primary 不参与消息的验证与广播,commit 和 reply 阶段中 Primary 则都参与
PBFT 算法前提,采用密码学算法保证节点之间的消息传送是不可篡改的
PBFT 容忍无效或者恶意节点数:f,为了保障整个系统可以正常运转,需要有 2f+1 个正常节点,系统的总节点数为:|R| = 3f + 1。也就是说,PBFT 算法可以容忍小于 1/3 个无效或者恶意节点
PBFT 是一种状态机副本复制算法,所有的副本在一个视图(view)轮换的过程中操作,主节点通过视图编号以及节点数集合来确定,即:主节点 p = v mod |R|。v:视图编号,|R|:节点个数,p:主节点编号
PBFT 共识算法使用视图 view 记录每个节点的共识状态,相同视图节点维护相同的 Leader 和 Replicas 节点列表,与 Raft 算法中的 term 类似
- REQUEST:
客户端 c 向主节点 p 发送 <REQUEST, o, t, c> 请求。o:请求的具体操作,t:请求时客户端追加的时间戳,c:客户端标识。REQUEST:包含消息内容 m,以及消息摘要 d(m)。客户端对请求进行签名
- PRE-PREPARE:
主节点收到客户端的请求,需要进行以下校验:客户端请求消息签名是否正确
- 非法请求丢弃
- 正确请求,则分配一个编号 n,编号 n 主要用于对客户端的请求进行排序。然后广播一条 <<PRE-PREPARE, v, n, d>, m> 消息给其他副本节点。v:视图编号,d:客户端消息摘要,m:消息内容。<PRE-PREPARE, v, n, d> 进行主节点签名。n 是要在某一个范围区间内的 [h, H] (高低水位)
- PREPARE:
副本节点 i 收到主节点的 PRE-PREPARE 消息,需要进行以下校验:
- 主节点 PRE-PREPARE 消息签名是否正确
- 当前副本节点是否已经收到了一条在同一 v 下并且编号也是 n,但是签名不同的 PRE-PREPARE 信息
- d 与 m 的摘要是否一致
- n 是否在区间 [h, H] 内
非法请求丢弃
正确请求,则副本节点 i 向其他节点包括主节点发送一条 <PREPARE, v, n, d, i> 消息,i 是当前副本节点编号。<PREPARE, v, n, d, i> 进行副本节点 i 的签名
- COMMIT:
主节点和副本节点收到 PREPARE 消息,需要进行以下校验:
- 副本节点 PREPARE 消息签名是否正确
- 当前副本节点是否已经收到了同一视图 v 下的 n
- n 是否在区间 [h, H] 内
- d 是否和当前已收到 PRE-PPREPARE 中的 d 相同
非法请求丢弃
如果副本节点 i 收到了 2f+1 个验证通过的 PREPARE 消息,则向其他节点包括主节点发送一条 <COMMIT, v, n, d, i> 消息。<COMMIT, v, n, d, i> 进行副本节点 i 的签名
- REPLY:
主节点和副本节点收到 COMMIT 消息,需要进行以下校验:
- 副本节点 COMMIT 消息签名是否正确
- 当前副本节点是否已经收到了同一视图 v 下的 n
- d 与 m 的摘要是否一致
- n 是否在区间 [h, H] 内
非法请求丢弃
如果副本节点 i 收到了 2f+1 个验证通过的 COMMIT 消息,说明当前网络中的大部分节点已经达成共识,运行客户端的请求操作 o,并返回 <REPLY, v, t, c, i, r> 给客户端,r:是请求操作结果,客户端如果收到 f+1 个相同的 REPLY 消息,说明客户端发起的请求已经达成全网共识,否则客户端需要判断是否重新发送请求给主节点
Checkpoint 和 Stable checkpoint
Checkpoint 就是当前节点处理的最新请求序号。比如一个节点正在共识的一个请求编号是 101,那么对于这个节点,它的 Checkpoint 就是 101
Stable Checkpoint 就是大部分节点 (2f+1) 已经共识完成的最大请求序号。比如系统有 4 个节点,三个节点都已经共识完了的请求编号是 213 ,那么这个 213 就是 Stable Checkpoint 了
Stable Checkpoint 的作用:因为每个节点在日志中应该记录下之前曾经共识过什么请求,但如果一直记录下去,数据会越来越大,所以应该有一个机制来实现对数据的删除
高低水位区间
实际上当副本节点 i 向其他节点发出 CheckPoint 消息后,其他节点还没有完成 K 条请求,所以不会立即对 i 的请求作出响应,它还会按照自己的节奏,向前行进,但此时发出的 CheckPoint 并未形成 Stable Checkpoint,为了防止 i 的处理请求过快,设置一个上文提到的高低水位区间 [h, H] 来解决这个问题
低水位 h 等于上一个 Stable Checkpoint 的编号,高水位 H = h + L,其中 L 是我们指定的数值,等于 Checkpoint 周期处理请求数 K 的整数倍,可以设置为 L = 2K。当副本节点 i 处理请求超过高水位 H 时,此时就会停止脚步,等待 Stable Checkpoint 发生变化,再继续前进
视图切换
如果主节点作恶,它可能会给不同的请求编上相同的序号,或者不去分配序号,或者让相邻的序号不连续。备份节点应当有职责来主动检查这些序号的合法性
如果主节点掉线或者作恶不广播客户端的请求,客户端设置超时机制,超时的话,向所有副本节点广播请求消息。副本节点检测出主节点作恶或者下线,发起视图切换(View Change)协议
- view-change:各副本节点 (Replica) 认为主节点 (Primary) 有问题时,会向其它节点发送 view-change 消息
- view-change-ack:各节点接收到 2f+1 个 view-change 消息后,选举当前存活的节点编号最小的节点成为新的主节点,并向该节点发送 view-change-ack 消息
- new-view:当新的主节点收到 2f+1 个其它节点的 view-change-ack 消息后,向其它节点广播new-view 消息。注意:从节点不会发起 new-view 事件1
算法特点
- PBFT 算法由于每个副本节点都需要和其他节点进行 P2P 的共识同步,因此随着节点的增多,性能会下降的很快,但是在较少节点的情况下可以有不错的性能,并且分叉的几率很低
- PBFT 主要用于联盟链,但是如果能够结合类似 DPOS 这样的节点代表选举规则的话也可以应用于公链,并且可以在一个不可信的网络里解决拜占庭容错问题
5.5 共识算法对比
- 作者:Howe
- 链接:https://blog.0xhowe.top/article/ConsensusMechanism-Fourth
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。