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
52 order := getBlockerOrder(startTimestamp, timeStamp, uint64(len(consensusNodeMap)))
53 for xPub, consensusNode := range consensusNodeMap {
54 if consensusNode.Order == order {
60 return "", errors.New("can not find blocker by given timestamp")
63 func getBlockerOrder(startTimestamp, blockTimestamp, 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 + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
69 return (blockTimestamp - lastRoundStartTime) / (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 preSeq := state.CalcVoteSeq(prevBlockNode.Height+1) - 1
91 if bestSeq := state.CalcVoteSeq(c.blockIndex.BestNode().Height); preSeq > bestSeq {
95 lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
100 voteResult, err := c.getVoteResult(preSeq, lastBlockNode)
105 return voteResult.ConsensusNodes()
108 func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
109 blockNode := c.blockIndex.BestNode()
110 seq := state.CalcVoteSeq(blockNode.Height)
111 return c.getVoteResult(seq, blockNode)
114 // getVoteResult return the vote result
115 // seq represent the sequence of vote
116 // blockNode represent the chain in which the result of the vote is located
117 // Voting results need to be adjusted according to the chain
118 func (c *consensusNodeManager) getVoteResult(seq uint64, blockNode *state.BlockNode) (*state.VoteResult, error) {
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; {
136 var forChainRollback, mainChainRollBack bool
137 if forChainRollback = forkChainNode.Height >= mainChainNode.Height; forChainRollback {
138 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
140 if mainChainRollBack = forkChainNode.Height <= mainChainNode.Height; mainChainRollBack {
141 detachNodes = append(detachNodes, mainChainNode)
143 if forChainRollback {
144 forkChainNode = forkChainNode.Parent
146 if mainChainRollBack {
147 mainChainNode = mainChainNode.Parent
151 for _, node := range detachNodes {
152 block, err := c.store.GetBlock(&node.Hash, node.Height)
157 if err := voteResult.DetachBlock(block); err != nil {
162 for _, node := range attachNodes {
163 block, err := c.store.GetBlock(&node.Hash, node.Height)
168 if err := voteResult.ApplyBlock(block); err != nil {