4 "github.com/vapor/config"
5 "github.com/vapor/consensus"
6 "github.com/vapor/errors"
7 "github.com/vapor/protocol/bc"
8 "github.com/vapor/protocol/state"
12 errNotFoundConsensusNode = errors.New("can not found consensus node")
13 errNotFoundBlockNode = errors.New("can not find block node")
16 type consensusNodeManager struct {
18 blockIndex *state.BlockIndex
21 func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager {
22 return &consensusNodeManager{
24 blockIndex: blockIndex,
28 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
29 consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
34 node, exist := consensusNodeMap[pubkey]
36 return nil, errNotFoundConsensusNode
41 func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) {
42 consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
47 consensusNode := consensusNodeMap[pubKey]
48 if consensusNode == nil {
52 prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
57 startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval
58 begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, uint64(len(consensusNodeMap)))
59 end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval
60 return timeStamp >= begin && timeStamp < end, nil
63 func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order, numOfConsensusNode uint64) uint64 {
64 // One round of product block time for all consensus nodes
65 roundBlockTime := consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval
66 // The start time of the last round of product block
67 lastRoundStartTime := startTimestamp + (endTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
68 // The time of product block of the consensus in last round
69 return lastRoundStartTime + order*(consensus.BlockNumEachNode*consensus.BlockTimeInterval)
72 func (c *consensusNodeManager) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
73 node := c.blockIndex.GetNode(prevBlockHash)
75 return nil, errNotFoundBlockNode
78 for node.Height%consensus.RoundVoteBlockNums != 0 {
84 func (c *consensusNodeManager) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
85 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
86 if prevBlockNode == nil {
87 return nil, errNotFoundBlockNode
90 seqHeight := prevBlockNode.Height + 1
91 if bestHeight := c.blockIndex.BestNode().Height; bestHeight < seqHeight && bestHeight != 0 {
92 seqHeight = bestHeight
95 preSeq := state.CalcVoteSeq(seqHeight) - 1
96 voteResult, err := c.store.GetVoteResult(preSeq)
101 lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
106 if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
110 if len(voteResult.NumOfVote) == 0 {
111 return federationNodes(), nil
113 return voteResult.ConsensusNodes()
116 func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
117 blockNode := c.blockIndex.BestNode()
118 seq := state.CalcVoteSeq(blockNode.Height)
119 voteResult, err := c.store.GetVoteResult(seq)
124 if err := c.reorganizeVoteResult(voteResult, blockNode); err != nil {
128 return voteResult, nil
131 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, node *state.BlockNode) error {
132 mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash)
133 var attachNodes []*state.BlockNode
134 var detachNodes []*state.BlockNode
135 for forkChainNode := node; mainChainNode != forkChainNode; node = node.Parent {
136 if forkChainNode.Height == mainChainNode.Height {
137 detachNodes = append(detachNodes, mainChainNode)
138 mainChainNode = mainChainNode.Parent
140 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
143 for _, node := range detachNodes {
144 block, err := c.store.GetBlock(&node.Hash)
149 if err := voteResult.DetachBlock(block); err != nil {
154 for _, node := range attachNodes {
155 block, err := c.store.GetBlock(&node.Hash)
160 if err := voteResult.ApplyBlock(block); err != nil {
167 func federationNodes() map[string]*state.ConsensusNode {
168 voteResult := map[string]*state.ConsensusNode{}
169 for i, xpub := range config.CommonConfig.Federation.Xpubs {
170 voteResult[xpub.String()] = &state.ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}