OSDN Git Service

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