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/bc/types"
9 "github.com/vapor/protocol/state"
13 errNotFoundConsensusNode = errors.New("can not found consensus node")
14 errNotFoundBlockNode = errors.New("can not find block node")
17 type consensusNodeManager struct {
19 blockIndex *state.BlockIndex
22 func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager {
23 return &consensusNodeManager{
25 blockIndex: blockIndex,
29 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
30 consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
35 node, exist := consensusNodeMap[pubkey]
37 return nil, errNotFoundConsensusNode
42 func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) {
43 consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
48 consensusNode := consensusNodeMap[pubKey]
49 if consensusNode == nil {
53 prevVoteRoundLastBlock, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
58 startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval
59 begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, len(consensusNodeMap))
60 end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval
61 return timeStamp >= begin && timeStamp < end, nil
64 func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order uint64, numOfConsensusNode int) uint64 {
65 // One round of product block time for all consensus nodes
66 roundBlockTime := uint64(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) getPrevRoundVoteLastBlock(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) getConsensusNodesByVoteResult(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
86 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
87 if prevBlockNode == nil {
88 return nil, errNotFoundBlockNode
91 seqHeight := prevBlockNode.Height + 1
92 if bestHeight := c.blockIndex.BestNode().Height; bestHeight < seqHeight {
93 seqHeight = bestHeight
96 seq := seqHeight / consensus.RoundVoteBlockNums
97 voteResult, err := c.store.GetVoteResult(seq)
102 lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
107 if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
111 if len(voteResult.NumOfVote) == 0 {
112 return initConsensusNodes(), nil
114 return voteResult.ConsensusNodes()
117 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, forkChainNode *state.BlockNode) error {
118 mainChainNode := c.blockIndex.GetNode(&voteResult.LastBlockHash)
119 var attachNodes []*state.BlockNode
120 var detachNodes []*state.BlockNode
121 for mainChainNode != forkChainNode {
122 if forkChainNode.Height == mainChainNode.Height {
123 detachNodes = append(detachNodes, mainChainNode)
124 mainChainNode = mainChainNode.Parent
126 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
127 forkChainNode = forkChainNode.Parent
130 for _, node := range detachNodes {
131 block, err := c.store.GetBlock(&node.Hash)
136 if err := voteResult.DetachBlock(block); err != nil {
141 for _, node := range attachNodes {
142 block, err := c.store.GetBlock(&node.Hash)
147 if err := voteResult.ApplyBlock(block); err != nil {
154 func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
155 voteResult, err := c.getVoteResult(voteResultMap, block.Height)
160 return voteResult.ApplyBlock(block)
163 func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) {
165 // This round of voting prepares for the next round
166 seq := blockHeight/consensus.RoundVoteBlockNums + 1
167 voteResult := voteResultMap[seq]
168 if blockHeight == 0 {
169 voteResult = &state.VoteResult{
171 NumOfVote: make(map[string]uint64),
175 if voteResult == nil {
176 prevVoteResult := voteResultMap[seq-1]
177 if prevVoteResult != nil {
178 voteResult = &state.VoteResult{
180 NumOfVote: prevVoteResult.NumOfVote,
185 if voteResult == nil {
186 voteResult, err = c.store.GetVoteResult(seq)
187 if err != nil && err != ErrNotFoundVoteResult {
192 if voteResult == nil {
193 voteResult, err = c.store.GetVoteResult(seq - 1)
194 if err != nil && err != ErrNotFoundVoteResult {
198 if voteResult != nil {
200 voteResult.LastBlockHash = bc.Hash{}
204 if voteResult == nil {
205 return nil, errors.New("fail to get vote result")
208 voteResultMap[seq] = voteResult
209 return voteResult, nil
212 func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
213 voteSeq := block.Height / consensus.RoundVoteBlockNums
214 voteResult := voteResultMap[voteSeq]
216 if voteResult == nil {
217 voteResult, err := c.store.GetVoteResult(voteSeq)
221 voteResultMap[voteSeq] = voteResult
224 voteResult.DetachBlock(block)
228 func initConsensusNodes() map[string]*state.ConsensusNode {
229 voteResult := map[string]*state.ConsensusNode{}
230 for i, xpub := range config.CommonConfig.Federation.Xpubs {
231 voteResult[xpub.String()] = &state.ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}