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 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
75 if prevBlockNode == nil {
76 return nil, errNotFoundBlockNode
79 blockHeight := prevBlockNode.Height + 1
81 prevVoteRoundLastBlockHeight := blockHeight/consensus.RoundVoteBlockNums*consensus.RoundVoteBlockNums - 1
83 if blockHeight/consensus.RoundVoteBlockNums == 0 {
84 prevVoteRoundLastBlockHeight = 0
87 lastBlockNode := prevBlockNode.GetParent(prevVoteRoundLastBlockHeight)
88 if lastBlockNode == nil {
89 return nil, errNotFoundBlockNode
91 return lastBlockNode, nil
94 func (c *consensusNodeManager) getConsensusNodesByVoteResult(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
95 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
96 if prevBlockNode == nil {
97 return nil, errNotFoundBlockNode
100 seq := (prevBlockNode.Height + 1) / consensus.RoundVoteBlockNums
101 voteResult, err := c.store.GetVoteResult(seq)
103 // TODO find previous round vote
104 voteResult = &state.VoteResult{
106 NumOfVote: make(map[string]uint64),
110 lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
115 if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
119 if len(voteResult.NumOfVote) == 0 {
120 return initConsensusNodes(), nil
123 return voteResult.ConsensusNodes()
126 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, forkChainNode *state.BlockNode) error {
127 genesisBlockHash := config.GenesisBlock().Hash()
128 mainChainNode := c.blockIndex.GetNode(&genesisBlockHash)
130 emptyHash := bc.Hash{}
131 if voteResult.LastBlockHash != emptyHash {
132 mainChainNode = c.blockIndex.GetNode(&voteResult.LastBlockHash)
133 if mainChainNode == nil {
134 return errNotFoundBlockNode
138 var attachNodes []*state.BlockNode
139 var detachNodes []*state.BlockNode
141 for forkChainNode != nil && mainChainNode != nil && forkChainNode.Hash != mainChainNode.Hash {
142 if forkChainNode.Height == mainChainNode.Height {
143 detachNodes = append(detachNodes, mainChainNode)
144 mainChainNode = mainChainNode.Parent
146 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
147 forkChainNode = forkChainNode.Parent
150 for _, node := range detachNodes {
151 block, err := c.store.GetBlock(&node.Hash)
156 if err := c.detachBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil {
161 for _, node := range attachNodes {
162 block, err := c.store.GetBlock(&node.Hash)
167 if err := c.applyBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil {
174 func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
175 voteResult, err := c.getVoteResult(voteResultMap, block.Height)
180 return voteResult.ApplyBlock(block)
183 func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) {
185 // This round of voting prepares for the next round
186 seq := blockHeight/consensus.RoundVoteBlockNums + 1
187 voteResult := voteResultMap[seq]
188 if blockHeight == 0 {
189 voteResult = &state.VoteResult{
191 NumOfVote: make(map[string]uint64),
195 if voteResult == nil {
196 prevVoteResult := voteResultMap[seq-1]
197 if prevVoteResult != nil {
198 voteResult = &state.VoteResult{
200 NumOfVote: prevVoteResult.NumOfVote,
205 if voteResult == nil {
206 voteResult, err = c.store.GetVoteResult(seq)
207 if err != nil && err != ErrNotFoundVoteResult {
212 if voteResult == nil {
213 voteResult, err = c.store.GetVoteResult(seq - 1)
214 if err != nil && err != ErrNotFoundVoteResult {
218 if voteResult != nil {
220 voteResult.LastBlockHash = bc.Hash{}
224 if voteResult == nil {
225 return nil, errors.New("fail to get vote result")
228 voteResultMap[seq] = voteResult
229 return voteResult, nil
232 func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
233 voteSeq := block.Height / consensus.RoundVoteBlockNums
234 voteResult := voteResultMap[voteSeq]
236 if voteResult == nil {
237 voteResult, err := c.store.GetVoteResult(voteSeq)
241 voteResultMap[voteSeq] = voteResult
244 voteResult.DetachBlock(block)
248 func initConsensusNodes() map[string]*state.ConsensusNode {
249 voteResult := map[string]*state.ConsensusNode{}
250 for i, xpub := range config.CommonConfig.Federation.Xpubs {
251 voteResult[xpub.String()] = &state.ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}