区块链的共识机制有很多,著名的有:工作量证明(PoW,竞争计算 Hash 碰撞)、权益证明(PoS,持币量和持币时长)、委任权益证明(DPoS,持币人选举 leader 投票)、拜占庭容错(例如 PBFT)、分布式一致性协议(例如 Raft,无法容忍随机错误)、容量证明(PoC,竞争解决 Memory Hard Function)、烧钱证明(PoBurn,烧毁其他币种)。
HotStuff 是一种使用 BFT SMR(拜占庭容错的状态机复制)共识机制的区块链,它利用区块链的链式特性改进了 PBFT,使得 leader failure 的通信复杂度从
O
(
n
3
)
O(n^3)
O(n3) 降低到了
O
(
n
)
O(n)
O(n) 的线性复杂度。
不可能定理(FLP 1985):reaching consensus in full asynchrony with a single process crashing is impossible with a deterministic protocol,从理论上证明了在纯异步环境下不可能存在一种确定性的共识协议。为了绕过这个定理以达成共识,要么加强对网络的假设,要么引入随机源。
通信模型(communication model):
Synchronous:网络中发出的消息可以在已知的时间
Δ
\Delta
Δ 内抵达。
Partially Synchronous:正确进程在未知的 global stabilization time (GST) 之后的某时刻
t
t
t 发送消息,则消息可以在已知的延迟
Δ
\Delta
Δ 内抵达。
Asynchronous:网络仅保证消息最终能抵达,不对到达时间做限制。
通信网络是点对点(point-to-point)、可认证(authenticated)、可靠的(reliable): one correct replica receives a message from another correct replica if and only if the latter sent that message to the former.
我们说的广播(broadcast):it involves the broadcaster, if correct, sending the same point-to-point messages to all replicas, including itself.
PBFT 是工作在 partially synchronous 网络上的 BFT SMR,要求
n
≥
3
f
+
1
n \ge 3f+1
n≥3f+1,这里
n
n
n 是状态机数量,
f
f
f 是拜占庭错误状态机的数量上界。核心任务是对不断增长的客户指令请求的是否执行以及执行的顺序在所有 correct replica 上达成共识。
在每个阶段里,leader 需要收集 a quorum of
n
−
f
n-f
n−f replicas 的投票,来形成 quorum certificate(QC)
HotStuff 使用
(
k
,
n
)
(k,\, n)
(k,n)threshold signature scheme(门限签名),仅当收集到了
∣
I
∣
=
k
=
2
f
+
1
|I| = k=2f+1
∣I∣=k=2f+1 个 partial signature
ρ
i
←
t
s
i
g
n
i
(
m
)
\rho_i \leftarrow tsign_i(m)
ρi←tsigni(m),才可以组合出合法签名
σ
←
t
c
o
m
b
i
n
e
(
m
,
{
ρ
i
}
i
∈
I
)
\sigma \leftarrow tcombine(m,\{\rho_i\}_{i \in I})
σ←tcombine(m,{ρi}i∈I),使得它满足
t
v
e
r
i
f
y
(
m
,
σ
)
=
1
tverify(m,\sigma)=1
tverify(m,σ)=1
与 PBFT 不同的是,HotStuff 每次结束三阶段,都会切换视图。它的 three phase 如下:
prepare phase:新的 leader 收集
n
−
f
n-f
n−f 个 NEW-VIEW 消息,找出其中有最高视图的
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC,作为自己的
h
i
g
h
Q
C
highQC
highQC,然后在对应的区块 node 上延长分支
c
r
e
a
t
e
L
E
A
F
createLEAF
createLEAF(叶子上包含客户指令),广播 prepare 消息(包括 leader 自己)以发布提案(Proposal)。各个 replica(包括 leader 自己)根据
s
a
f
e
N
o
d
e
safeNode
safeNode 谓词,判断是否对此提案投赞同票(仅发消息给 leader)。
pre-commit phase:若 leader 收集到了
n
−
f
n-f
n−f 个 prepare votes,那么可以形成
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC 证书,广播 pre-commit 消息。各个 replica 接收到后(此时可确认大多数 correct replica 赞同延长分支),设置本地状态
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC,然后投票。
commit phase:若 leader 收集到了
n
−
f
n-f
n−f 个 pre-commit votes,那么可以形成
p
r
e
c
o
m
m
i
t
Q
C
precommitQC
precommitQC 证书,广播 commit 消息。各个 replica 接收到后(此时可确认大多数 correct replica 都已知道“大多数 correct replica 赞同延长分支”这件事),设置本地状态
l
o
c
k
e
d
Q
C
lockedQC
lockedQC,然后投票(同意提交提案)。
decide phase:若 leader 收集到了
n
−
f
n-f
n−f 个 commit votes,那么可以形成
c
o
m
m
i
t
Q
C
commitQC
commitQC 证书,广播 decide 消息。各个 replica 接收到后(此时确认大多数 correct replica 都同意提交这个提案,这个分支成为 committed branch),执行叶子上的客户指令。然后,各个 replica 执行视图切换。
Safety rule: the branch of
m
.
n
o
d
e
m.node
m.node extends from the currently locked node
l
o
c
k
e
d
Q
C
.
n
o
d
e
lockedQC.node
lockedQC.node(正确的 replica 仅认可在 本地的已锁定节点的所在分支 的链增长,敌手无法使系统共识另一条冲突的链)
Liveness rule: the replica will accept
m
m
m if
m
.
j
u
s
t
i
f
y
m.justify
m.justify has a higher view than the current
l
o
c
k
e
d
Q
C
lockedQC
lockedQC(正确的 replica 仅接受 比本地的已锁定节点的视图更高 的证书,敌手无法使系统共识更短的链)
伪代码
一些基本的功能:
三阶段的共识协议:
每当 timer 超时,就会执行 new-view 中断,此时将等待时间翻倍。由于通信系统是部分同步的,因此总会使得等待时间足够长,足以接收到其他 replica 发出的消息。
L
e
a
d
e
r
(
⋅
)
Leader(\cdot)
Leader(⋅) 是任意的确定性算法,只要保证全部的 replica 都可以轮转成为 next leader。
Safety, Liveness, and Complexity
我们说两个 branch 是冲突的(conflicting),如果两者都不是对方的扩展(neither one is an extension of the other)。我们说两个 node 是冲突的,如果它们引导的 branch 是冲突的。
分布式系统中的
n
n
n 个 replica 各自维护本地的树,其中的
n
−
f
=
2
f
+
1
n-f=2f+1
n−f=2f+1 个 correct replica 维护着基本相同(除了最后的若干格区块)的树。在三阶段协议中,correct replica 仅对 存在于本地树上的拥有最高视图序号的
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC 证书的节点的后继分支上的安全的叶子 投赞同票。
Safety:
对于任意有效的
q
c
1
,
q
c
2
qc_1,\, qc_2
qc1,qc2,其中
q
c
1
.
t
y
p
e
=
q
c
2
.
t
y
p
e
qc_1.type = qc_2.type
qc1.type=qc2.type,并且
q
c
1
.
m
o
d
e
qc_1.mode
qc1.mode 和
q
c
2
.
n
o
d
e
qc_2.node
qc2.node 冲突,那么必然有
q
c
1
.
v
i
e
w
N
u
m
b
e
r
≠
q
c
2
.
v
i
e
w
N
u
m
b
e
r
qc_1.viewNumber \neq qc_2.viewNumber
qc1.viewNumber=qc2.viewNumber
如果
w
,
b
w,\, b
w,b 是冲突的节点,那么在任何的 correct replica 上,它们不会被同时 commit
Liveness:
如果一个 correct replica 锁定在了
l
o
c
k
e
d
Q
C
=
p
r
e
c
o
m
m
i
t
Q
C
lockedQC = precommitQC
lockedQC=precommitQC 上,那么至少有
f
+
1
f+1
f+1 个 correct replica 对匹配
l
o
c
k
e
d
Q
C
lockedQC
lockedQC 的一些
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC 投了赞同票
在 GST 后,存在一个有界时间段(bounded time period)
T
f
T_f
Tf,使得:如果所有的 correct replica 在时间段
T
f
T_f
Tf 中,都同时停留在视图
v
v
v 里,并且视图
v
v
v 的 leader 是正确的,那么将会达成 decision
The protocol is Optimistically Responsive(最优响应性)
Complexity:
在 HotStuff 协议中,身份认证是最耗时的,replica 在每次投票时都需要附加上自己的签名。在每个阶段,需要
O
(
n
)
O(n)
O(n) 次签名。
在 Chained HotStuff 中,使用
g
e
n
e
r
i
c
Q
C
genericQC
genericQC 取代所有的其他证书,各个阶段度被 generic-phase 取代。因此,只需要两种类型的消息:new-view 消息、generic 消息。
在视图
v
v
v 上的 generic-phase,它对应于 Basic Hotstuff 里的:
视图
v
v
v 上提案的 prepare 阶段,
g
e
n
e
r
i
c
Q
C
genericQC
genericQC 是其
h
i
g
h
Q
C
highQC
highQC
视图
v
−
1
v-1
v−1 上提案的 pre-commit 阶段,
g
e
n
e
r
i
c
Q
C
genericQC
genericQC 是其
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC
视图
v
−
2
v-2
v−2 上提案的
c
o
m
m
i
t
commit
commit 阶段,
g
e
n
e
r
i
c
Q
C
genericQC
genericQC 是其
l
o
c
k
e
d
Q
C
lockedQC
lockedQC
视图
v
−
3
v-3
v−3 上提案的 decide 阶段,
g
e
n
e
r
i
c
Q
C
genericQC
genericQC 是其
c
o
m
m
i
t
Q
C
commitQC
commitQC
在 Chained HotStuff 中,节点
b
b
b 的高度被设置为对应提案的视图序号
v
v
v,它的 parent 是视图
v
−
1
v-1
v−1 的节点。如果视图
v
v
v 上的 leader 没能收集出
g
e
n
e
r
i
c
Q
C
genericQC
genericQC(提交的提案不安全、leader 崩溃、通信延迟),那么这个节点就成为了哑结点(Dummy nodes),使得
b
.
j
u
s
t
i
f
y
.
n
o
d
e
≠
b
.
p
a
r
e
n
t
b.justify.node \neq b.parent
b.justify.node=b.parent,也就是
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC 并不指向它的 parent 节点。
上图中,
b
∗
.
j
u
s
t
i
f
y
.
n
o
d
e
=
b
∗
.
p
a
r
e
n
t
=
b
′
′
b^*.justify.node = b^*.parent = b''
b∗.justify.node=b∗.parent=b′′,我们说
b
∗
b^*
b∗ 形成了 One-Chain,此时要更新本地状态
g
e
n
e
r
i
c
Q
C
←
b
∗
.
j
u
s
t
i
f
y
genericQC \leftarrow b^*.justify
genericQC←b∗.justify(因为
b
∗
.
j
u
s
t
i
f
y
b^*.justify
b∗.justify 是节点
b
′
′
b''
b′′ 的提案的
p
r
e
p
a
r
e
Q
C
prepareQC
prepareQC)
同时,
b
′
′
.
j
u
s
t
i
f
y
.
n
o
d
e
=
b
′
′
.
p
a
r
e
n
t
=
b
′
b''.justify.node = b''.parent = b'
b′′.justify.node=b′′.parent=b′,我们说
b
∗
b^*
b∗ 形成了 Two-Chain,此时要更新本地状态
l
o
c
k
e
d
Q
C
←
b
′
′
.
j
u
s
t
i
f
y
lockedQC \leftarrow b''.justify
lockedQC←b′′.justify(因为
b
′
′
.
j
u
s
t
i
f
y
b''.justify
b′′.justify 是节点
b
′
b'
b′ 的提案的
p
r
e
c
o
m
m
i
t
Q
C
precommitQC
precommitQC)
而且,
b
′
.
j
u
s
t
i
f
y
.
n
o
d
e
=
b
′
.
p
a
r
e
n
t
=
b
b'.justify.node = b'.parent = b
b′.justify.node=b′.parent=b,我们说
b
∗
b^*
b∗ 形成了 Three-Chain,此时要执行客户指令
b
.
c
m
d
b.cmd
b.cmd(因为
b
′
.
j
u
s
t
i
f
y
b'.justify
b′.justify 是节点
b
b
b 的提案的
c
o
m
m
i
t
Q
C
commitQC
commitQC)
伪代码
Event-driven HotStuff
文章中还将 Chained HotStuff 转化为了 event-driven-style(事件驱动风格)。就是添加了一个起搏器(Pacemaker),代替 next leader 在 generic phase 的最后等待和收集
g
e
n
r
i
c
Q
C
genricQC
genricQC