對於公有區塊鏈來說,由於委員會成員會更迭,自然會有成員的退出和更新,本文介紹的是一種POS的實現,委員會之間的通信使用
Tendermint
,普通節點使用devp2p
會存在兩個p2p連接。
這是基於上一篇基於以太坊實現Tendermint POS的細節 (一):選舉寫的,沒看的可以瞭解下。
PBFT Server初始化
初始化本地配置
- 端口
- IP
- 私鑰
agent
爲Tendermint
和應用協議的橋樑。
func (s *Taiyuechain) startPbftServer() error {
priv, err := crypto.ToECDSA(s.config.CommitteeKey)
cfg := config.DefaultConfig()
cfg.P2P.ListenAddress1 = "tcp://0.0.0.0:" + strconv.Itoa(s.config.Port)
cfg.P2P.ListenAddress2 = "tcp://0.0.0.0:" + strconv.Itoa(s.config.StandbyPort)
n1, err := tbft.NewNode(cfg, "1", priv, s.agent)
s.pbftServer = n1
return n1.Start()
}
PBFT的幾種事件
委員會啓動
需要傳遞給Server
界數,委員會成員,本屆開始高度。
e.electionFeed.Send(types.ElectionEvent{
Option: types.CommitteeStart,
CommitteeID: e.committee.id,
CommitteeMembers: members,
BeginFastNumber: e.committee.beginFastNumber,
})
選舉點
訂閱區塊上鍊的chainHead事件,獲取當前上鍊高度。
func (e *Election) subScribeEvent() {
e.chainHeadSub = e.fastchain.SubscribeChainHeadEvent(e.chainHeadCh)
}
當塊高度等於選舉點
,計算本屆結束高度,和下屆委員會成員。
- 本屆結束高度
計算出本屆結束高度,通知server。e.electionFeed.Send(types.ElectionEvent{ Option: types.CommitteeOver, CommitteeID: e.committee.id, CommitteeMembers: e.committee.Members(), BeginFastNumber: e.committee.beginFastNumber, EndFastNumber: e.committee.endFastNumber, })
- 下屆選舉
需要計算下屆委員會
成員,下屆開始高度e.electionFeed.Send(types.ElectionEvent{ Option: types.CommitteeSwitchover, CommitteeID: e.nextCommittee.id, CommitteeMembers: e.nextCommittee.Members(), BeginFastNumber: e.nextCommittee.beginFastNumber, })
換屆點
當塊高度等於換屆點
,本屆委員會停止工作,啓動下屆委員會。
- 本屆結束
通知server退出,結束端口監聽e.electionFeed.Send(types.ElectionEvent{ Option: types.CommitteeOver, CommitteeID: e.committee.id, CommitteeMembers: e.committee.Members(), BeginFastNumber: e.committee.beginFastNumber, EndFastNumber: e.committee.endFastNumber, })
- 下屆開始工作
設置下屆委員會成員爲本屆成員,啓動委員會。e.committee = e.nextCommittee e.electionFeed.Send(types.ElectionEvent{ Option: types.CommitteeStart, CommitteeID: e.committee.id, CommitteeMembers: e.committee.Members(), BeginFastNumber: e.committee.beginFastNumber, })
同步中的問題
當一個新節點啓動的時候,會向其他節點同步數據,這時候計算委員會會有一些問題。因爲當有一批數據上鍊時,只有最後一個區塊發出chainhead事件,這時候上面的流程會有跳過。
計算最新高度的委員會成員,並賦值給當前屆,這樣區塊中籤名的驗證就可以通過了。func (e *Election) getCommitteeInfoByCommitteeId(committeeId *big.Int) *committee { begin, end := types.GetEpochHeigth(committeeId) committee := &committee{ id: committeeId, beginFastNumber: new(big.Int).Set(begin), endFastNumber: new(big.Int).Set(end), } caCertPubkeyList := e.getCACertList() committee.members = e.assignmentCommitteeMember(caCertPubkeyList, committeeId) return committee }