文章目录
概括地说,PalletOne的BFT共识是基于DKS的TBLS阈值签名的解决方案,它是对DPOS共识的补充,对传统BFT共识的优化,能大大地提高了交易的确认速度。
1. PalletOne之共识模块概述
共识(Consensus): 在p2p网络、分布式计算和多代理系统中各个节点或者进程就计算期间所需的某些数据值达成一致。(见: https://en.wikipedia.org/wiki/Consensus_(computer_science) )
共识机制:达成上述共识的某种机制、某种协议或者某种算法。常见的共识机制有POW共识、POS共识等,在PalletOne中使用的是DPOS+BFT联合共识机制;
1.1 POW共识有如下问题:
- 越来越中心化(算力大是王道)。
- 资源在竞争浪费。
- 交易速度缓慢。
- 难于网络更改参数(只能硬分叉,例如:比特币大陆主导的BCC,为了隔离见证和扩容)
1.2 DPOS能有效的避免上述问题:
- 投票选出择若干指定数量的Mediator完成生产区块的工作。
- Mediator轮流生产区块,防止恶性竞争。
- 在计算性能和网络带宽允许的情况下,可以快速的生产区块。
- 通过选定的代表进行提议并全节点投票调整。
1.3 DPOS共识在去中心化上的努力:
- 所有mediator都是由股东以公平和民主的方式投票选出。
- 每届mediator都只有有限的区块生产时间,如果不满意,在下一届投票踢出就好了。
- mediator的数量可以提议投票修改。
1.4 PalletOne在提高交易确认速度上的努力
- 所有mediator必须满足一定的存储算力网络条件;
- 使用BFT共识来补充DPOS共识;
- 基于DKS的TBLS阈值签名的BFT共识,对传统BFT共识进行效率上的优化;
2. PalletOne的BFT共识介绍
2.1 各个共识机制下交易确认速度的对比
-
在传统的POW共识机制中,只有当区块的深度达到6以后,该区块被逆转的可能性才在理论上成为小概率事件。又由于POW共识的竞争机制下,生产区块(挖矿)的低速度导致交易的确认速度非常慢。
-
基于DPOS共识的传统BFT共识,尽管可能需要更大的深度(通常是大于2/3倍生产者数量)才能确认交易,但由于DPOS共识较快的区块生产速度,所以在交易的确认速度方面有比较喜人的提高。
-
在PalletOne中,由于使用的是基于DKS的TBLS阈值签名的BFT共识,使得其交易的确认速度摆脱了对区块深度的依赖,从而得以长足的提升。从理论上讲,PalletOne的交易确认速度只受到节点处理速度和网络传输速度的限制。
2.2 PalletOne之BFT共识实现流程
ProcessOn 上 PalletOne之BFT共识实现流程图 原图链接请点击:PalletOne之BFT共识实现流程
2.3 PalletOne之BFT共识代码实现概述
本小节所讲解的源码在 github 上的地址为: threshold_sign_test.go
- 变量定义:
var suite = bn256.NewSuiteG2()
var nbParticipants = 21
var ntThreshold = nbParticipants*2/3 + 1
var partSec []kyber.Scalar
var partPubs []kyber.Point
var dkgs []*dkg.DistKeyGenerator
- 生成初始公私钥分片:
func genPair() (kyber.Scalar, kyber.Point) {
sc := suite.Scalar().Pick(suite.RandomStream())
return sc, suite.Point().Mul(sc, nil)
}
func init() {
partPubs = make([]kyber.Point, nbParticipants)
partSec = make([]kyber.Scalar, nbParticipants)
for i := 0; i < nbParticipants; i++ {
sec, pub := genPair()
partSec[i] = sec
partPubs[i] = pub
}
}
- 初始化dkg:
func dkgGen() []*dkg.DistKeyGenerator {
dkgs := make([]*dkg.DistKeyGenerator, nbParticipants)
for i := 0; i < nbParticipants; i++ {
dkg, err := dkg.NewDistKeyGenerator(suite, partSec[i], partPubs, ntThreshold)
if err != nil {
panic(err)
}
dkgs[i] = dkg
}
return dkgs
}
- 完成VSS协议:
func fullExchange(t *testing.T) {
// full secret sharing exchange
// 1. broadcast deals
resps := make([]*dkg.Response, 0, nbParticipants*nbParticipants)
for _, dkg := range dkgs {
deals, err := dkg.Deals()
require.Nil(t, err)
for i, d := range deals {
resp, err := dkgs[i].ProcessDeal(d)
require.Nil(t, err)
require.Equal(t, vss.StatusApproval, resp.Response.Status)
resps = append(resps, resp)
}
}
// 2. Broadcast responses
for _, resp := range resps {
for i, dkg := range dkgs {
// ignore all messages from ourselves
if resp.Response.Index == uint32(i) {
continue
}
j, err := dkg.ProcessResponse(resp)
require.Nil(t, err)
require.Nil(t, j)
}
}
}
- TBLS签名和验证:
func TestTBLS(t *testing.T) {
msg := []byte("Hello DKG, VSS, TBLS and BLS!")
sigShares := make([][]byte, 0)
for i, d := range dkgs {
if i >= ntThreshold {
break
}
dks, err := d.DistKeyShare()
assert.Nil(t, err)
sig, err := tbls.Sign(suite, dks.PriShare(), msg)
require.Nil(t, err)
sigShares = append(sigShares, sig)
}
dkg := dkgs[0]
dks, err := dkg.DistKeyShare()
require.Nil(t, err)
pubPoly := share.NewPubPoly(suite, suite.Point().Base(), dks.Commitments())
sig, err := tbls.Recover(suite, pubPoly, msg, sigShares, ntThreshold, nbParticipants)
require.Nil(t, err)
err = bls.Verify(suite, dks.Public(), msg, sig)
assert.Nil(t, err)
}