OSDN Git Service

Revert "edit" (#132)
[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         prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
75         if prevBlockNode == nil {
76                 return nil, errNotFoundBlockNode
77         }
78
79         blockHeight := prevBlockNode.Height + 1
80
81         prevVoteRoundLastBlockHeight := blockHeight/consensus.RoundVoteBlockNums*consensus.RoundVoteBlockNums - 1
82         // first round
83         if blockHeight/consensus.RoundVoteBlockNums == 0 {
84                 prevVoteRoundLastBlockHeight = 0
85         }
86
87         lastBlockNode := prevBlockNode.GetParent(prevVoteRoundLastBlockHeight)
88         if lastBlockNode == nil {
89                 return nil, errNotFoundBlockNode
90         }
91         return lastBlockNode, nil
92 }
93
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
98         }
99
100         seq := (prevBlockNode.Height + 1) / consensus.RoundVoteBlockNums
101         voteResult, err := c.store.GetVoteResult(seq)
102         if err != nil {
103                 // TODO find previous round vote
104                 voteResult = &state.VoteResult{
105                         Seq:       seq,
106                         NumOfVote: make(map[string]uint64),
107                 }
108         }
109
110         lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
111         if err != nil {
112                 return nil, err
113         }
114
115         if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
116                 return nil, err
117         }
118
119         if len(voteResult.NumOfVote) == 0 {
120                 return initConsensusNodes(), nil
121         }
122
123         return voteResult.ConsensusNodes()
124 }
125
126 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, forkChainNode *state.BlockNode) error {
127         genesisBlockHash := config.GenesisBlock().Hash()
128         mainChainNode := c.blockIndex.GetNode(&genesisBlockHash)
129
130         emptyHash := bc.Hash{}
131         if voteResult.LastBlockHash != emptyHash {
132                 mainChainNode = c.blockIndex.GetNode(&voteResult.LastBlockHash)
133                 if mainChainNode == nil {
134                         return errNotFoundBlockNode
135                 }
136         }
137
138         var attachNodes []*state.BlockNode
139         var detachNodes []*state.BlockNode
140
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
145                 }
146                 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
147                 forkChainNode = forkChainNode.Parent
148         }
149
150         for _, node := range detachNodes {
151                 block, err := c.store.GetBlock(&node.Hash)
152                 if err != nil {
153                         return err
154                 }
155
156                 if err := c.detachBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil {
157                         return err
158                 }
159         }
160
161         for _, node := range attachNodes {
162                 block, err := c.store.GetBlock(&node.Hash)
163                 if err != nil {
164                         return err
165                 }
166
167                 if err := c.applyBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil {
168                         return err
169                 }
170         }
171         return nil
172 }
173
174 func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
175         voteResult, err := c.getVoteResult(voteResultMap, block.Height)
176         if err != nil {
177                 return err
178         }
179
180         return voteResult.ApplyBlock(block)
181 }
182
183 func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) {
184         var err 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{
190                         Seq:       seq,
191                         NumOfVote: make(map[string]uint64),
192                 }
193         }
194
195         if voteResult == nil {
196                 prevVoteResult := voteResultMap[seq-1]
197                 if prevVoteResult != nil {
198                         voteResult = &state.VoteResult{
199                                 Seq:       seq,
200                                 NumOfVote: prevVoteResult.NumOfVote,
201                         }
202                 }
203         }
204
205         if voteResult == nil {
206                 voteResult, err = c.store.GetVoteResult(seq)
207                 if err != nil && err != ErrNotFoundVoteResult {
208                         return nil, err
209                 }
210         }
211
212         if voteResult == nil {
213                 voteResult, err = c.store.GetVoteResult(seq - 1)
214                 if err != nil && err != ErrNotFoundVoteResult {
215                         return nil, err
216                 }
217
218                 if voteResult != nil {
219                         voteResult.Seq = seq
220                         voteResult.LastBlockHash = bc.Hash{}
221                 }
222         }
223
224         if voteResult == nil {
225                 return nil, errors.New("fail to get vote result")
226         }
227
228         voteResultMap[seq] = voteResult
229         return voteResult, nil
230 }
231
232 func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
233         voteSeq := block.Height / consensus.RoundVoteBlockNums
234         voteResult := voteResultMap[voteSeq]
235
236         if voteResult == nil {
237                 voteResult, err := c.store.GetVoteResult(voteSeq)
238                 if err != nil {
239                         return err
240                 }
241                 voteResultMap[voteSeq] = voteResult
242         }
243
244         voteResult.DetachBlock(block)
245         return nil
246 }
247
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)}
252         }
253         return voteResult
254 }