OSDN Git Service

66d182634df716f4ea8334b296612a31f942cae6
[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         order := getBlockerOrder(startTimestamp, timeStamp, uint64(len(consensusNodeMap)))
53         for xPub, consensusNode := range consensusNodeMap {
54                 if consensusNode.Order == order {
55                         return xPub, nil
56                 }
57         }
58
59         // impossible occur
60         return "", errors.New("can not find blocker by given timestamp")
61 }
62
63 func getBlockerOrder(startTimestamp, blockTimestamp, numOfConsensusNode uint64) uint64 {
64         // One round of product block time for all consensus nodes
65         roundBlockTime := consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval
66         // The start time of the last round of product block
67         lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
68         // Order of blocker
69         return (blockTimestamp - lastRoundStartTime) / (consensus.BlockNumEachNode * consensus.BlockTimeInterval)
70 }
71
72 func (c *consensusNodeManager) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
73         node := c.blockIndex.GetNode(prevBlockHash)
74         if node == nil {
75                 return nil, errNotFoundBlockNode
76         }
77
78         for node.Height%consensus.RoundVoteBlockNums != 0 {
79                 node = node.Parent
80         }
81         return node, nil
82 }
83
84 func (c *consensusNodeManager) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
85         prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
86         if prevBlockNode == nil {
87                 return nil, errNotFoundBlockNode
88         }
89
90         preSeq := state.CalcVoteSeq(prevBlockNode.Height+1) - 1
91         if bestSeq := state.CalcVoteSeq(c.blockIndex.BestNode().Height); preSeq > bestSeq {
92                 preSeq = bestSeq
93         }
94
95         lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
96         if err != nil {
97                 return nil, err
98         }
99
100         voteResult, err := c.getVoteResult(preSeq, lastBlockNode)
101         if err != nil {
102                 return nil, err
103         }
104
105         return voteResult.ConsensusNodes()
106 }
107
108 func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
109         blockNode := c.blockIndex.BestNode()
110         seq := state.CalcVoteSeq(blockNode.Height)
111         return c.getVoteResult(seq, blockNode)
112 }
113
114 // getVoteResult return the vote result
115 // seq represent the sequence of vote
116 // blockNode represent the chain in which the result of the vote is located
117 // Voting results need to be adjusted according to the chain
118 func (c *consensusNodeManager) getVoteResult(seq uint64, blockNode *state.BlockNode) (*state.VoteResult, error) {
119         voteResult, err := c.store.GetVoteResult(seq)
120         if err != nil {
121                 return nil, err
122         }
123
124         if err := c.reorganizeVoteResult(voteResult, blockNode); err != nil {
125                 return nil, err
126         }
127
128         return voteResult, nil
129 }
130
131 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, node *state.BlockNode) error {
132         mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash)
133         var attachNodes []*state.BlockNode
134         var detachNodes []*state.BlockNode
135         for forkChainNode := node; mainChainNode != forkChainNode; {
136                 var forChainRollback, mainChainRollBack bool
137                 if forChainRollback = forkChainNode.Height >= mainChainNode.Height; forChainRollback {
138                         attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
139                 }
140                 if mainChainRollBack = forkChainNode.Height <= mainChainNode.Height; mainChainRollBack {
141                         detachNodes = append(detachNodes, mainChainNode)
142                 }
143                 if forChainRollback {
144                         forkChainNode = forkChainNode.Parent
145                 }
146                 if mainChainRollBack {
147                         mainChainNode = mainChainNode.Parent
148                 }
149         }
150
151         for _, node := range detachNodes {
152                 block, err := c.store.GetBlock(&node.Hash, node.Height)
153                 if err != nil {
154                         return err
155                 }
156
157                 if err := voteResult.DetachBlock(block); err != nil {
158                         return err
159                 }
160         }
161
162         for _, node := range attachNodes {
163                 block, err := c.store.GetBlock(&node.Hash, node.Height)
164                 if err != nil {
165                         return err
166                 }
167
168                 if err := voteResult.ApplyBlock(block); err != nil {
169                         return err
170                 }
171         }
172         return nil
173 }