基于泰岳链实现Tendermint POS的细节 (一):选举

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

选举

  • 成员的产生可以通过随机数生成如ETH2.0
  • 通过从POW矿工中寻找满足一定算力的成员 混合共识
  • 通过Balance质押量选择排行前20的成员

获取委员会信息

选举出了委员会成员后,一般只知道它的公钥,并不知道它的IP端口,如何实现委员会成员之间的互联呢。

//CommitteeNode contains  main info of committee node
type CommitteeNode struct {
	IP        string
	Port      uint32
	Port2     uint32
	Coinbase  common.Address  //reward address
	Publickey []byte
}

发送节点nodeinfo信息

将本节点信息用所有委员会成员的公钥加密一遍,

	for _, member := range committeeInfo.GetAllMembers() {
		pubkey, _ := crypto.UnmarshalPubkey(member.Publickey)
		encryptNode, err := ecies.Encrypt(rand.Reader, ecies.ImportECDSAPublic(pubkey), nodeByte, nil, nil)
		if err != nil {
			log.Error("publickey encrypt node error ", "member.Publickey", common.Bytes2Hex(member.Publickey), "err", err)
		}
		encryptNodes = append(encryptNodes, encryptNode)
	}

如果对方是委员会节点,则可解密出委员会成员的信息。

	priKey := ecies.ImportECDSA(privateKey)
	for _, encryptNode := range cryNodeInfo.Nodes {
		decryptNode, err := priKey.Decrypt(encryptNode, nil, nil)
		if err == nil { // can Decrypt by priKey
			transportCommitteeNode := new(types.TransportCommitteeNode) //receive nodeInfo
			rlp.DecodeBytes(decryptNode, transportCommitteeNode)
			committeeNode := transportCommitteeNode.ConvertTransportToCommitteeNode(pubKey)
			return committeeNode
		}
	}

此时节点可实现连接。

epoch

pos中一般都有界数的概念,每一届都会有开始高度和结束高度,以太坊中的SLOT可以当高度去处理。

type EpochIDInfo struct {
	EpochID     uint64
	BeginHeight uint64
	EndHeight   uint64
}

创世成员

func (e *Election) getCommitteeByGenesis() *committee {
	begin, end := types.GetEpochHeigth(new(big.Int).Set(common.Big0))
	return &committee{
		id:              new(big.Int).Set(common.Big0),
		beginFastNumber: begin,
		endFastNumber:   end,
		members:         e.genesisCommittee,
	}
}

新选举出来的委员会成员都会在下一届生效,实现中新选出来的成员会在本界开始高度之前的100个块,提前发送节点nodeinfo信息,使用Port2启动tendermint server

	if next == epoch.EndHeight-params.ElectionPoint+1 {
		epoch := types.GetEpochFromHeight(next + params.NewEpochLength)
		committee := &types.CommitteeInfo{
			Id:          new(big.Int).SetUint64(epoch.EpochID),
			StartHeight: new(big.Int).SetUint64(epoch.BeginHeight),
			EndHeight:   new(big.Int).SetUint64(epoch.EndHeight),
		}
		validators := agent.getValidators(epoch.EpochID)

		committee.Members = validators
		// Switch to new epoch
		agent.setCommitteeInfo(nextCommittee, committee)
		if agent.IsUsedOrUnusedMember(committee, agent.committeeNode.Publickey) {
		   //是委员会成员 发送nodeinfo
			agent.startSend(committee, true)
			// 更新server节点信息,启动server
			help.CheckAndPrintError(agent.server.PutCommittee(committee))
			help.CheckAndPrintError(agent.server.PutNodes(committee.Id, []*types.CommitteeNode{agent.committeeNode}))
		} else {
			agent.startSend(committee, false)
		}
	}

这样在本届出块之前,委员会成员已经实现了充分连接。

猜你喜欢

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