OSDN Git Service

a4b59e656b213ae7cc4f3b30bb30697a7953dda5
[bytom/vapor.git] / protocol / consensus_node_manager.go
1 package protocol
2
3 import (
4         "github.com/vapor/consensus"
5         "github.com/vapor/errors"
6         "github.com/vapor/protocol/bc"
7         "github.com/vapor/protocol/state"
8 )
9
10 var (
11         errNotFoundConsensusNode = errors.New("can not found consensus node")
12         errNotFoundBlockNode     = errors.New("can not find block node")
13 )
14
15 type consensusNodeManager struct {
16         store      Store
17         blockIndex *state.BlockIndex
18 }
19
20 func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager {
21         return &consensusNodeManager{
22                 store:      store,
23                 blockIndex: blockIndex,
24         }
25 }
26
27 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
28         consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
29         if err != nil {
30                 return nil, err
31         }
32
33         node, exist := consensusNodeMap[pubkey]
34         if !exist {
35                 return nil, errNotFoundConsensusNode
36         }
37         return node, nil
38 }
39
40 func (c *consensusNodeManager) getBlocker(prevBlockHash *bc.Hash, timeStamp uint64) (string, error) {
41         consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
42         if err != nil {
43                 return "", err
44         }
45
46         prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
47         if err != nil {
48                 return "", err
49         }
50
51         startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval
52
53         for xPub, consensusNode := range consensusNodeMap {
54                 begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, uint64(len(consensusNodeMap)))
55                 end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval
56                 if timeStamp >= begin && timeStamp < end {
57                         return xPub, nil
58                 }
59         }
60         // impossible occur
61         return "", errors.New("can not find blocker by given timestamp")
62 }
63
64 func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order, numOfConsensusNode uint64) uint64 {
65         // One round of product block time for all consensus nodes
66         roundBlockTime := 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) getPrevRoundLastBlock(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) getConsensusNodes(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         preSeq := state.CalcVoteSeq(prevBlockNode.Height+1) - 1
92         if bestSeq := state.CalcVoteSeq(c.blockIndex.BestNode().Height); preSeq > bestSeq {
93                 preSeq = bestSeq
94         }
95
96         lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
97         if err != nil {
98                 return nil, err
99         }
100
101         voteResult, err := c.getVoteResult(preSeq, lastBlockNode)
102         if err != nil {
103                 return nil, err
104         }
105
106         return voteResult.ConsensusNodes()
107 }
108
109 func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
110         blockNode := c.blockIndex.BestNode()
111         seq := state.CalcVoteSeq(blockNode.Height)
112         return c.getVoteResult(seq, blockNode)
113 }
114
115 // getVoteResult return the vote result
116 // seq represent the sequence of vote
117 // blockNode represent the chain in which the result of the vote is located
118 // Voting results need to be adjusted according to the chain 
119 func (c *consensusNodeManager) getVoteResult(seq uint64, blockNode *state.BlockNode) (*state.VoteResult, error) {
120         voteResult, err := c.store.GetVoteResult(seq)
121         if err != nil {
122                 return nil, err
123         }
124
125         if err := c.reorganizeVoteResult(voteResult, blockNode); err != nil {
126                 return nil, err
127         }
128
129         return voteResult, nil
130 }
131
132 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, node *state.BlockNode) error {
133         mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash)
134         var attachNodes []*state.BlockNode
135         var detachNodes []*state.BlockNode
136         for forkChainNode := node; mainChainNode != forkChainNode; {
137                 var forChainRollback, mainChainRollBack bool
138                 if forChainRollback = forkChainNode.Height >= mainChainNode.Height; forChainRollback {
139                         attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
140                 } 
141                 if mainChainRollBack = forkChainNode.Height <= mainChainNode.Height; mainChainRollBack {
142                         detachNodes = append(detachNodes, mainChainNode)
143                 }
144                 if forChainRollback {
145                         forkChainNode = forkChainNode.Parent
146                 }
147                 if mainChainRollBack {
148                         mainChainNode = mainChainNode.Parent
149                 }
150         }
151
152         for _, node := range detachNodes {
153                 block, err := c.store.GetBlock(&node.Hash)
154                 if err != nil {
155                         return err
156                 }
157
158                 if err := voteResult.DetachBlock(block); err != nil {
159                         return err
160                 }
161         }
162
163         for _, node := range attachNodes {
164                 block, err := c.store.GetBlock(&node.Hash)
165                 if err != nil {
166                         return err
167                 }
168
169                 if err := voteResult.ApplyBlock(block); err != nil {
170                         return err
171                 }
172         }
173         return nil
174 }