OSDN Git Service

edit (#129)
[bytom/vapor.git] / protocol / consensus_node_manager.go
1 package protocol
2
3 import (
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"
10 )
11
12 var (
13         errNotFoundConsensusNode = errors.New("can not found consensus node")
14         errNotFoundBlockNode     = errors.New("can not find block node")
15 )
16
17 type consensusNodeManager struct {
18         store      Store
19         blockIndex *state.BlockIndex
20 }
21
22 func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager {
23         return &consensusNodeManager{
24                 store:      store,
25                 blockIndex: blockIndex,
26         }
27 }
28
29 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
30         consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
31         if err != nil {
32                 return nil, err
33         }
34
35         node, exist := consensusNodeMap[pubkey]
36         if !exist {
37                 return nil, errNotFoundConsensusNode
38         }
39         return node, nil
40 }
41
42 func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) {
43         consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
44         if err != nil {
45                 return false, err
46         }
47
48         consensusNode := consensusNodeMap[pubKey]
49         if consensusNode == nil {
50                 return false, nil
51         }
52
53         prevVoteRoundLastBlock, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
54         if err != nil {
55                 return false, err
56         }
57
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
62 }
63
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)
71 }
72
73 func (c *consensusNodeManager) getPrevRoundVoteLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
74         node := c.blockIndex.GetNode(prevBlockHash)
75         if node == nil {
76                 return nil, errNotFoundBlockNode
77         }
78
79         for node.Height%consensus.RoundVoteBlockNums != 0 {
80                 node = node.Parent
81         }
82         return node, nil
83 }
84
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
89         }
90
91         seqHeight := prevBlockNode.Height + 1
92         if bestHeight := c.blockIndex.BestNode().Height; bestHeight < seqHeight {
93                 seqHeight = bestHeight
94         }
95
96         seq := seqHeight / consensus.RoundVoteBlockNums
97         voteResult, err := c.store.GetVoteResult(seq)
98         if err != nil {
99                 return nil, err
100         }
101
102         lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
103         if err != nil {
104                 return nil, err
105         }
106
107         if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
108                 return nil, err
109         }
110
111         if len(voteResult.NumOfVote) == 0 {
112                 return initConsensusNodes(), nil
113         }
114         return voteResult.ConsensusNodes()
115 }
116
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
125                 }
126                 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
127                 forkChainNode = forkChainNode.Parent
128         }
129
130         for _, node := range detachNodes {
131                 block, err := c.store.GetBlock(&node.Hash)
132                 if err != nil {
133                         return err
134                 }
135
136                 if err := voteResult.DetachBlock(block); err != nil {
137                         return err
138                 }
139         }
140
141         for _, node := range attachNodes {
142                 block, err := c.store.GetBlock(&node.Hash)
143                 if err != nil {
144                         return err
145                 }
146
147                 if err := voteResult.ApplyBlock(block); err != nil {
148                         return err
149                 }
150         }
151         return nil
152 }
153
154 func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
155         voteResult, err := c.getVoteResult(voteResultMap, block.Height)
156         if err != nil {
157                 return err
158         }
159
160         return voteResult.ApplyBlock(block)
161 }
162
163 func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) {
164         var err 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{
170                         Seq:       seq,
171                         NumOfVote: make(map[string]uint64),
172                 }
173         }
174
175         if voteResult == nil {
176                 prevVoteResult := voteResultMap[seq-1]
177                 if prevVoteResult != nil {
178                         voteResult = &state.VoteResult{
179                                 Seq:       seq,
180                                 NumOfVote: prevVoteResult.NumOfVote,
181                         }
182                 }
183         }
184
185         if voteResult == nil {
186                 voteResult, err = c.store.GetVoteResult(seq)
187                 if err != nil && err != ErrNotFoundVoteResult {
188                         return nil, err
189                 }
190         }
191
192         if voteResult == nil {
193                 voteResult, err = c.store.GetVoteResult(seq - 1)
194                 if err != nil && err != ErrNotFoundVoteResult {
195                         return nil, err
196                 }
197
198                 if voteResult != nil {
199                         voteResult.Seq = seq
200                         voteResult.LastBlockHash = bc.Hash{}
201                 }
202         }
203
204         if voteResult == nil {
205                 return nil, errors.New("fail to get vote result")
206         }
207
208         voteResultMap[seq] = voteResult
209         return voteResult, nil
210 }
211
212 func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
213         voteSeq := block.Height / consensus.RoundVoteBlockNums
214         voteResult := voteResultMap[voteSeq]
215
216         if voteResult == nil {
217                 voteResult, err := c.store.GetVoteResult(voteSeq)
218                 if err != nil {
219                         return err
220                 }
221                 voteResultMap[voteSeq] = voteResult
222         }
223
224         voteResult.DetachBlock(block)
225         return nil
226 }
227
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)}
232         }
233         return voteResult
234 }