OSDN Git Service

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