基于泰岳链实现Tendermint POS的细节 (二):换届

对于公有区块链来说,由于委员会成员会更迭,自然会有成员的退出和更新,本文介绍的是一种POS的实现,委员会之间的通信使用Tendermint,普通节点使用devp2p会存在两个p2p连接。

这是基于上一篇基于以太坊实现Tendermint POS的细节 (一):选举写的,没看的可以了解下。

PBFT Server初始化

初始化本地配置

  • 端口
  • IP
  • 私钥

agentTendermint和应用协议的桥梁。

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
    }
    
    计算最新高度的委员会成员,并赋值给当前届,这样区块中签名的验证就可以通过了。

猜你喜欢

转载自blog.csdn.net/JIYILANZHOU/article/details/106716217