4 "github.com/vapor/consensus"
5 "github.com/vapor/errors"
6 "github.com/vapor/protocol/bc"
7 "github.com/vapor/protocol/state"
11 errNotFoundConsensusNode = errors.New("can not found consensus node")
12 errNotFoundBlockNode = errors.New("can not find block node")
15 type consensusNodeManager struct {
17 blockIndex *state.BlockIndex
20 func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager {
21 return &consensusNodeManager{
23 blockIndex: blockIndex,
27 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
28 consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
33 node, exist := consensusNodeMap[pubkey]
35 return nil, errNotFoundConsensusNode
40 func (c *consensusNodeManager) getBlocker(prevBlockHash *bc.Hash, timeStamp uint64) (string, error) {
41 consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
46 prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
51 startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval
53 for xPub, consensusNode := range consensusNodeMap {
54 begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, uint64(len(consensusNodeMap)))
55 end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval
56 if timeStamp >= begin && timeStamp < end {
61 return "", errors.New("can not find blocker by given timestamp")
64 func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order, numOfConsensusNode uint64) uint64 {
65 // One round of product block time for all consensus nodes
66 roundBlockTime := consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval
67 // The start time of the last round of product block
68 lastRoundStartTime := startTimestamp + (endTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
69 // The time of product block of the consensus in last round
70 return lastRoundStartTime + order*(consensus.BlockNumEachNode*consensus.BlockTimeInterval)
73 func (c *consensusNodeManager) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
74 node := c.blockIndex.GetNode(prevBlockHash)
76 return nil, errNotFoundBlockNode
79 for node.Height%consensus.RoundVoteBlockNums != 0 {
85 func (c *consensusNodeManager) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
86 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
87 if prevBlockNode == nil {
88 return nil, errNotFoundBlockNode
91 preSeq := state.CalcVoteSeq(prevBlockNode.Height+1) - 1
92 if bestSeq := state.CalcVoteSeq(c.blockIndex.BestNode().Height); preSeq > bestSeq {
96 lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
101 voteResult, err := c.getVoteResult(preSeq, lastBlockNode)
106 return voteResult.ConsensusNodes()
109 func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
110 blockNode := c.blockIndex.BestNode()
111 seq := state.CalcVoteSeq(blockNode.Height)
112 return c.getVoteResult(seq, blockNode)
115 // getVoteResult return the vote result
116 // seq represent the sequence of vote
117 // blockNode represent the chain in which the result of the vote is located
118 // Voting results need to be adjusted according to the chain
119 func (c *consensusNodeManager) getVoteResult(seq uint64, blockNode *state.BlockNode) (*state.VoteResult, error) {
120 voteResult, err := c.store.GetVoteResult(seq)
125 if err := c.reorganizeVoteResult(voteResult, blockNode); err != nil {
129 return voteResult, nil
132 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, node *state.BlockNode) error {
133 mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash)
134 var attachNodes []*state.BlockNode
135 var detachNodes []*state.BlockNode
136 for forkChainNode := node; mainChainNode != forkChainNode; {
137 var forChainRollback, mainChainRollBack bool
138 if forChainRollback = forkChainNode.Height >= mainChainNode.Height; forChainRollback {
139 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
141 if mainChainRollBack = forkChainNode.Height <= mainChainNode.Height; mainChainRollBack {
142 detachNodes = append(detachNodes, mainChainNode)
144 if forChainRollback {
145 forkChainNode = forkChainNode.Parent
147 if mainChainRollBack {
148 mainChainNode = mainChainNode.Parent
152 for _, node := range detachNodes {
153 block, err := c.store.GetBlock(&node.Hash)
158 if err := voteResult.DetachBlock(block); err != nil {
163 for _, node := range attachNodes {
164 block, err := c.store.GetBlock(&node.Hash)
169 if err := voteResult.ApplyBlock(block); err != nil {