看了好久的SBFT终于快看完了,然而有些细节还是没搞懂=_=||,接下来准备去看源码了
需要说明的是一下内容只是读完论文后的一些梳理,我并没有完全理解,可能存在错误,后续我会再进行修改。
SBFT可以说是PBFT的扩展,它解决了扩展性(scalabillity
)的问题,可以支持世界范围内的209个replicas
(其中64个拜占庭错误replica
)正常运行,并且吞吐量可以达到PBFT的两倍,延迟也更低。
中心化提供了好的性能,但存在一系列问题,比特币和以太坊的成功说明了去中心化巨大的潜在价值。但是研究表明,比特币和以太坊并没有先前想的那么去中心化,前20%的矿池控制了超过90%的算力。这一研究说明了BFT算法应用于区块链的可行性(由于PoW过于消耗资源),也促使了BFT相关算法的研究。近年来BFT相关算法有替换掉PoW或者与PoW组合应用于区块链的趋势。
SBFT为了做到这些性能上的提升,基于PBFT增加了四点设计上的改进:
很多之前的系统都使用了多对多(all-to-all)的消息模式
来提交一个确认区块,SBFT提出了一个使用收集器(collector
)的线性通信模式。这种模式下不再将消息发给每一个replica
,而是发给collector
,然后再由collector
广播给所有replicas
。同时通过使用门限签名(threshold signatures
)可以将消息长度从线性降低到常数。
Zyzzyva也使用了
collector
,但是将collector
的职责放到了client,而SBFT将collector
的职责放到了replica
。
当所有replica
都没有错误并且是同步(synchronous
)时,SBFT允许使用快速共识机制。
SBFT实现了第一个正确且实用的双模式view change
,可以在快速共识和正常共识之间无缝切换。
在之前所有的解决方案中,client都需要收到 f + 1 f+1 f+1个来自replicas
的一致的reply
才可以确认自己发出的request
是否被执行。当client
和replicas
增多时,通信负载压力会增大。在SBFT中,正常情况下,每一个client
只需要收到一个reply
就足够了,这使得SBFT可以支持非常多的瘦客户端。
SBFT通过使用execution collector
来做到这一点,execution collector
收集replicas
的execution threshold signatures
并将其组合起来发送给client
。像公链(比如比特币和以太坊)一样,SBFT也使用了默克尔树(merkle tree
)来认证从某一个replica
读取的信息。
SBFT使用了BLS签名,相比RSA签名,BLS只需要33个bytes就可以达到2048个bit的RSA签名的安全性。(其实不太理解这里为什么论文作者不使用相同的单位,2048个bit也就是256个bytes,不过八倍还是很可观的,当然BLS还有很多其他很有用的性质)。
SBFT是安全的当有 f f f个拜占庭节点时,不过只有当所有的节点都没有错误且系统是同步的时候才可以使用标准的快速共识,因此即使一个节点的故障都会使系统从fast path
切换到slow path
。
SBFT借鉴了single-shot consensus algorithm
中提出的理论,使得fast path
可以在 3 f + 2 c + 1 3f+2c+1 3f+2c+1个replicas
的系统中容忍 c c c个故障replicas
。
由于目前没有什么可以和SBFT比的,于是作者改进了已有的PBFT算法,称之为scale optimized PBFT
,作为比较对象。
总之就是效果很好就是了:)
While our view change protocol is new, one could argue that the other ingredients mentioned have appeared in some form in previous work. Nevertheless, SBFT is the first to careful weave and implement all these ingredients into a highly efficient and scalable BFT system.
论文中讨论了三种模型:
标准异步模式
敌人最多控制网络中的 f f f个拜占庭节点、可以造成整个网络的延迟。
SBFT可以保证safety
,也就是任何两个replicas
都会按同样的顺序执行同一个block。
同步模型
敌人最多控制网络中的 f f f个拜占庭节点。
SBFT可以保证liveness
,也就是client的request
都会得到reply
一般模式
敌人最多控制网络专供的 c c c个节点。
SBFT可以保证linearity
,就是说每提交一个block只需要固定数量的消息(大概是吧)
SBFT还使用了门限签名(threshold signature
),对于 n n n个replicas
,只需要replicas
的一个子集对block进行签名就可以验证。即子集中的replica
分别使用自己的私钥签名之后再组合起来,最后可以只验证一次就可以了。
SBFT使用了比RSA签名算法更短更快的BLS签名算法,BLS基于椭圆曲线,有很多实用的性质,比如支持批量验证签名。
SBFT提供了一个可扩展的通用复制服务的容错实现(也就是状态机复制服务),在这之上使用默克尔树实现了一个可认证的键值存储,之上又实现了可以执行EVM字节码的智能合约层。
实现了确定的带状态的复制服务、确定的操作、只读的查询接口。
v a l = e x e c u t e ( D , o ) val = execute(D,o) val=execute(D,o):根据操作 o o o修改状态 D D D,并返回 v a l val val.
v a l = q u e r y ( D , q ) val = query(D,q) val=query(D,q):返回状态 D D D下的查询 q q q,不修改 D D D.
服务的状态由离散的block改变,每一个block包含一些request,论文中使用 D j D_j Dj表示执行完序号为 j j j的block的状态,使用 r e q j req_j reqj表示序号为 j j j的block包含的request.
为了支持client高效地认证来自某个replica
的消息,在键值存储中设计了一些数据认证接口。
True
这一层是为了以后方便集成其它智能合约语言。
目前的EVM layer实现了两个主要组件:
整个系统有 3 f + 2 c + 1 3f+2c+1 3f+2c+1个replica
,编号从 1 1 1到 3 f + 2 c + 1 3f+2c+1 3f+2c+1。
使用了三个门限签名:
σ \sigma σ with threshold ( 3 f + c + 1 ) (3 f + c + 1) (3f+c+1), τ \tau τ with threshold ( 2 f + c + 1 ) (2 f + c + 1) (2f+c+1), and π \pi π with threshold ( f + 1 ) ( f + 1) (f+1).
和PBFT一样使用了view change
协议,每一个view
有一个primary
,其它repplica
是backups
,与PBFT不同的是,这些backups
还拥有其他身份,Commit collectors
和Execution collectors
。每一个view
中都会有 c + 1 c+1 c+1个Commit collectors
和Execution collectors
用来收集并组合门限签名和传播结果签名。为了liveness
,至少需要一个collector
,论文中在fast path
情况下用了c+1
个collector
实现冗余。
The role of a C-collector is to collect commit messages and send a combined signature back to replicas to confirm commit. The role of an E-collector is to collect execution messages and send a combined signature back to replicas and clients so they all have a certificate that their request is executed.
client
向primary
发送request
primary
收集request
,将其打包成block
,并作为pre-prepare message
转发给其他replicas
replicas
对收到的pre-prepare message
使用 σ ( 3 f + c + 1 ) \sigma(3f+c+1) σ(3f+c+1)签名,然后将签名消息发给C-collectors
.C-collector
收集签名,为该block
创建一个full-commit-proof
消息发给replicas
一旦replica
收到full-commit-proof
消息,它就commit这个block
,然后开始执行execution protocol:
replica
执行完提交的block之前的blocks,它执行这个block中的request,并使用 π ( f + 1 ) \pi(f+1) π(f+1)进行签名,然后发送sign-state message
给E-collectors
E-collector
收集签名,并为该block创建一个full-execute-proof
,然后告诉replicas
和client
当前状态是持久的并且操作已经被执行。通过对给一个decision block选不同的E-collectors
和C-collectors
实现负载均衡。
client k 通过发送 ⟨ “ r e q u e s t ” , o , t , k ⟩ \left\langle“request”, o, t, k \right\rangle ⟨“request”,o,t,k⟩消息给primary
,primary
再转发给backups
,开始共识。
先前的系统中client需要等待 f + 1 f+1 f+1个replica
才完成确认,SBFT中只需要一个 ⟨ “ e x e c u t e − a c k ” , s , v a l , o , π ( d ) , p r o o f ( o , l , s , D , v a l ) ⟩ \left\langle“execute-ack”, s, val, o, \pi(d), proof(o, l, s, D, val) \right\rangle ⟨“execute−ack”,s,val,o,π(d),proof(o,l,s,D,val)⟩消息就可以确认。如果client等待超时,就会将该request
发给所有的replicas
。
replica
的状态包含一个记录所有消息的log,状态还包含了视图编号、上一个稳定的序号(last stable sequence
)、执行完所有commited requests后服务的状态 D D D。还使用了一个固定值win
限制超前太多的block。
有的replicas
还担任C-collectors
或则E-collector
,执行特殊的任务。
The role of a C-collector is to collect commit messages and send a combined signature back to replicas to confirm commit. The role of an E-collector is to collect execution messages and send a combined signature back to replicas and clients so they all have a certificate that their request is executed.
fast path protocol
是执行的默认模式,可以在不超过 c c c个crashed/slow replicas
的同步环境下正常运行。
为了commit一个新的block,primary
开始执行一个三阶段的协议:pre-prepare
、sign-share
、commit-proof
.
primary
收到来自client k的 ⟨ “ r e q u e s t ” , o , t , k ⟩ \left\langle“request”, o, t, k \right\rangle ⟨“request”,o,t,k⟩(如果操作 o o o通过静态服务认证和访问控制规则就接受),当收到至少 b b b个( b ≥ b a t c h b\ge batch b≥batch)client发来的request(或者超时)后,将这些request打包到集合 r = ( r 1 , r 2 , . . . , r b ) r=(r_1, r_2, ..., r_b) r=(r1,r2,...,rb)中,然后广播 ⟨ “ p r e − p r e p a r e ” , s , v , r ⟩ \left\langle“pre-prepare”, s, v, r \right\rangle ⟨“pre−prepare”,s,v,r⟩给所有的replicas
,其中 s s s是当前的序号, v v v是视图号。replica
收到 ⟨ “ p r e − p r e p a r e ” , s , v , r ⟩ \left\langle“pre-prepare”, s, v, r \right\rangle ⟨“pre−prepare”,s,v,r⟩消息后,进行检查,满足条件(具体条件参考论文)就接受。然后计算 h = H ( s ∣ ∣ v ∣ ∣ r ) h=H(s||v||r) h=H(s∣∣v∣∣r),其中 H H H是一个加密哈希函数(比如SHA256),接着对h进行签名 σ i ( h ) \sigma_i(h) σi(h),最后发送 ⟨ “ s i g n − s h a r e ” , s , v , σ i ( h ) ⟩ \left\langle“sign-share”, s, v, \sigma_i(h) \right\rangle ⟨“sign−share”,s,v,σi(h)⟩消息给那些C-collectors
replicas
。replica
收到 ⟨ “ f u l l − c o m m i t − p r o o f ” , s , v , σ ( h ) ⟩ \left\langle“full-commit-proof”, s, v, \sigma(h) \right\rangle ⟨“full−commit−proof”,s,v,σ(h)⟩消息后,检查,确认接受,然后commit r r r( r r r是序号为 s s s的请求)。与先前的其他算法主要的不同在于使用了门限签名。一旦replica
收到committed的block,就启动一个两阶段的协议:sign-state
、execute-proof
.
Execute trigger and sign state:
当收到committed的block(序号为s)后,replica_i
执行request将状态从 D s − 1 D_{s-1} Ds−1更新到 D s D_s Ds。然后更新状态摘要 d = d i g e s t ( D x ) d=digest(D_x) d=digest(Dx),签名 π i ( d ) \pi_i(d) πi(d),最后发送 ⟨ “ s i g n − s t a t e ” , s , π i ( d ) ⟩ \left\langle“sign-state”, s, \pi_i(d)\right\rangle ⟨“sign−state”,s,πi(d)⟩消息给集合E-collectors(s)
。
Execute-proof:
E-collector
收集 ⟨ “ s i g n − s t a t e ” , s , π i ( d ) ⟩ \left\langle“sign-state”, s, \pi_i(d)\right\rangle ⟨“sign−state”,s,πi(d)⟩消息并验证签名,当收到 f + 1 f+1 f+1个时,将其租着成一个签名 π ( d ) \pi(d) π(d),发送 ⟨ “ f u l l − e x e c u t e − p r o o f ” , s , π ( d ) ⟩ \left\langle“full-execute-proof”, s, \pi(d)\right\rangle ⟨“full−execute−proof”,s,π(d)⟩消息给所有的replica
,replicas
检查签名决定是否接受。
然后E-collector
对每一个request
o ∈ r o\in r o∈r,发给client一个 ⟨ “ e x e c u t e − a c k ” , s , l , v a l , o , π ( d ) , p r o o f ( o , l , s , D , v a l ) ⟩ \left\lang“execute-ack”, s, l, val, o, \pi(d), proof(o, l, s, D, val) \right\rangle ⟨“execute−ack”,s,l,val,o,π(d),proof(o,l,s,D,val)⟩,其中是 o o o的返回值。client接收 ⟨ “ e x e c u t e − a c k ” , s , l , v a l , o , π ( d ) , P ⟩ \left\lang“execute-ack”, s, l, val, o, \pi(d), P\right\rangle ⟨“execute−ack”,s,l,val,o,π(d),P⟩消息后,检查 π ( d ) \pi(d) π(d)是否有效 && v e r i f y ( d , o , v a l , s , l , P ) verify(d, o, val, s, l, P) verify(d,o,val,s,l,P)是否为真,确认有效后client标记 o o o已执行,将 v a l val val设置为返回值。如果client超时就重发该request,进行正常共识。
当fast path
无法达成共识时,就使用Linear-PBFT
。Linear-PBFT
是对PBFT的改编,使用了门限签名和线性通信。
fast path
)和 τ i ( h ) \tau_i(h) τi(h)(for Linear PBFT path
)Linear-PBFT
。C-collector
收集签名,创建 τ ( h ) \tau(h) τ(h),如果超时,就发送 ⟨ “ p r e p a r e ” , s , v , τ ( h ) ⟩ \left\lang“prepare”, s, v, \tau(h)\right\rangle ⟨“prepare”,s,v,τ(h)⟩给所有replicas
。replica
收到 ⟨ “ p r e p a r e ” , s , v , τ ( h ) ⟩ \left\lang“prepare”, s, v, \tau(h)\right\rangle ⟨“prepare”,s,v,τ(h)⟩消息并进行检查,如果通过检查就发送 ⟨ “ c o m m i t ” , s , v , τ i ( τ ( h ) ) ⟩ \left\lang“commit”, s, v, \tau_i(\tau(h))\right\rangle ⟨“commit”,s,v,τi(τ(h))⟩给所有C-collectors
C-collectors
收集足够的签名来创建 ⟨ “ f u l l − c o m m i t − p r o o f − s l o w ” , s , v , τ ( τ ( h ) ) ⟩ \left\lang“full-commit-proof-slow”, s, v, \tau(\tau(h))\right\rangle ⟨“full−commit−proof−slow”,s,v,τ(τ(h))⟩消息,发给所有replicas
。replica
收到 ⟨ “ f u l l − c o m m i t − p r o o f − s l o w ” , s , v , τ ( τ ( h ) ) ⟩ \left\lang“full-commit-proof-slow”, s, v, \tau(\tau(h))\right\rangle ⟨“full−commit−proof−slow”,s,v,τ(τ(h))⟩和 ⟨ “ p r e − p r e p a r e ” , s , v , r , h ⟩ \left\langle“pre-prepare”, s, v, r, h\right\rangle ⟨“pre−prepare”,s,v,r,h⟩消息,验证通过 h = H ( s ∣ ∣ v ∣ ∣ r ) h=H(s||v||r) h=H(s∣∣v∣∣r),然后就commit r r r( r r r是 b l o c k s block_s blocks包含的request)。b l o c k s block_s blocks有三种状态:
Committed
:至少一个正常的replica
commit了该blockExecuted
:至少一个正常的replica
commit完了1到s的所有blockStable
:至少 f + 1 f+1 f+1个正常的replica
execute了该block当一个block状态时Stable时,可以收集先前的block。像PBFT中一样,每隔一定周期( w i n / 2 win/2 win/2)进行一次checkpoint protocol,更新ls(the last stable sequence number
)。
SBFT中有两种commit模式,Fast-path
和Linear-PBFT
。
先前的方案需要显式地指出使用哪一种模式,SBFT提出了新的View Change Protocol,支持同时运行两种模式,并无缝切换。
TODO