OSDN Git Service

add log (#373)
[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/bc/types"
8         "github.com/vapor/protocol/state"
9 )
10
11 var (
12         errNotFoundConsensusNode = errors.New("can not found consensus node")
13         errNotFoundBlockNode     = errors.New("can not find block node")
14 )
15
16 func (c *Chain) getBestConsensusResult() (*state.ConsensusResult, error) {
17         bestBlockHeader := c.bestBlockHeader
18         seq := state.CalcVoteSeq(bestBlockHeader.Height)
19         return c.getConsensusResult(seq, bestBlockHeader)
20 }
21
22 func getBlockerOrder(startTimestamp, blockTimestamp, numOfConsensusNode uint64) uint64 {
23         // One round of product block time for all consensus nodes
24         roundBlockTime := consensus.ActiveNetParams.BlockNumEachNode * numOfConsensusNode * consensus.ActiveNetParams.BlockTimeInterval
25         // The start time of the last round of product block
26         lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
27         // Order of blocker
28         return (blockTimestamp - lastRoundStartTime) / (consensus.ActiveNetParams.BlockNumEachNode * consensus.ActiveNetParams.BlockTimeInterval)
29 }
30
31 func (c *Chain) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
32         consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
33         if err != nil {
34                 return nil, err
35         }
36
37         node, exist := consensusNodeMap[pubkey]
38         if !exist {
39                 return nil, errNotFoundConsensusNode
40         }
41         return node, nil
42 }
43
44 func (c *Chain) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
45         prevBlockHeader, err := c.store.GetBlockHeader(prevBlockHash)
46         if err != nil {
47                 return nil, errNotFoundBlockNode
48         }
49
50         bestBlockHeader := c.bestBlockHeader
51         preSeq := state.CalcVoteSeq(prevBlockHeader.Height+1) - 1
52         if bestSeq := state.CalcVoteSeq(bestBlockHeader.Height); preSeq > bestSeq {
53                 preSeq = bestSeq
54         }
55
56         lastBlockHeader, err := c.getPrevRoundLastBlock(prevBlockHash)
57         if err != nil {
58                 return nil, err
59         }
60
61         consensusResult, err := c.getConsensusResult(preSeq, lastBlockHeader)
62         if err != nil {
63                 return nil, err
64         }
65
66         return consensusResult.ConsensusNodes()
67 }
68
69 // getConsensusResult return the vote result
70 // seq represent the sequence of vote
71 // blockHeader represent the chain in which the result of the vote is located
72 // Voting results need to be adjusted according to the chain
73 func (c *Chain) getConsensusResult(seq uint64, blockHeader *types.BlockHeader) (*state.ConsensusResult, error) {
74         consensusResult, err := c.store.GetConsensusResult(seq)
75         if err != nil {
76                 return nil, err
77         }
78
79         if err := c.reorganizeConsensusResult(consensusResult, blockHeader); err != nil {
80                 return nil, err
81         }
82
83         return consensusResult, nil
84 }
85
86 func (c *Chain) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*types.BlockHeader, error) {
87         blockHeader, err := c.store.GetBlockHeader(prevBlockHash)
88         if err != nil {
89                 return nil, errNotFoundBlockNode
90         }
91
92         for blockHeader.Height%consensus.ActiveNetParams.RoundVoteBlockNums != 0 {
93                 blockHeader, err = c.store.GetBlockHeader(&blockHeader.PreviousBlockHash)
94                 if err != nil {
95                         return nil, err
96                 }
97         }
98         return blockHeader, nil
99 }
100
101 func (c *Chain) reorganizeConsensusResult(consensusResult *state.ConsensusResult, blockHeader *types.BlockHeader) error {
102         mainChainBlockHeader, err := c.store.GetBlockHeader(&consensusResult.BlockHash)
103         if err != nil {
104                 return err
105         }
106
107         attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, mainChainBlockHeader)
108         if err != nil {
109                 return err
110         }
111
112         for _, bh := range detachBlockHeaders {
113                 blockHash := bh.Hash()
114                 block, err := c.store.GetBlock(&blockHash)
115                 if err != nil {
116                         return err
117                 }
118
119                 if err := consensusResult.DetachBlock(block); err != nil {
120                         return err
121                 }
122         }
123
124         for _, bh := range attachBlockHeaders {
125                 blockHash := bh.Hash()
126                 block, err := c.store.GetBlock(&blockHash)
127                 if err != nil {
128                         return err
129                 }
130
131                 if err := consensusResult.ApplyBlock(block); err != nil {
132                         return err
133                 }
134         }
135         return nil
136 }
137
138 // GetBlocker return blocker by specified timestamp
139 func (c *Chain) GetBlocker(prevBlockHash *bc.Hash, timeStamp uint64) (string, error) {
140         consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
141         if err != nil {
142                 return "", err
143         }
144
145         prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
146         if err != nil {
147                 return "", err
148         }
149
150         startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
151         order := getBlockerOrder(startTimestamp, timeStamp, uint64(len(consensusNodeMap)))
152         for xPub, consensusNode := range consensusNodeMap {
153                 if consensusNode.Order == order {
154                         return xPub, nil
155                 }
156         }
157
158         // impossible occur
159         return "", errors.New("can not find blocker by given timestamp")
160 }
161
162 // GetConsensusResultByHash return vote result by block hash
163 func (c *Chain) GetConsensusResultByHash(blockHash *bc.Hash) (*state.ConsensusResult, error) {
164         blockHeader, err := c.store.GetBlockHeader(blockHash)
165         if err != nil {
166                 return nil, err
167         }
168         return c.getConsensusResult(state.CalcVoteSeq(blockHeader.Height), blockHeader)
169 }