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"
12 errNotFoundConsensusNode = errors.New("can not found consensus node")
13 errNotFoundBlockNode = errors.New("can not find block node")
16 func (c *Chain) getBestConsensusResult() (*state.ConsensusResult, error) {
17 bestBlockHeader := c.bestBlockHeader
18 seq := state.CalcVoteSeq(bestBlockHeader.Height)
19 return c.getConsensusResult(seq, bestBlockHeader)
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
28 return (blockTimestamp - lastRoundStartTime) / (consensus.ActiveNetParams.BlockNumEachNode * consensus.ActiveNetParams.BlockTimeInterval)
31 func (c *Chain) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
32 consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
37 node, exist := consensusNodeMap[pubkey]
39 return nil, errNotFoundConsensusNode
44 func (c *Chain) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
45 prevBlockHeader, err := c.store.GetBlockHeader(prevBlockHash)
47 return nil, errNotFoundBlockNode
50 bestBlockHeader := c.bestBlockHeader
51 preSeq := state.CalcVoteSeq(prevBlockHeader.Height+1) - 1
52 if bestSeq := state.CalcVoteSeq(bestBlockHeader.Height); preSeq > bestSeq {
56 lastBlockHeader, err := c.getPrevRoundLastBlock(prevBlockHash)
61 consensusResult, err := c.getConsensusResult(preSeq, lastBlockHeader)
66 return consensusResult.ConsensusNodes()
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)
79 if err := c.reorganizeConsensusResult(consensusResult, blockHeader); err != nil {
83 return consensusResult, nil
86 func (c *Chain) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*types.BlockHeader, error) {
87 blockHeader, err := c.store.GetBlockHeader(prevBlockHash)
89 return nil, errNotFoundBlockNode
92 for blockHeader.Height%consensus.ActiveNetParams.RoundVoteBlockNums != 0 {
93 blockHeader, err = c.store.GetBlockHeader(&blockHeader.PreviousBlockHash)
98 return blockHeader, nil
101 func (c *Chain) reorganizeConsensusResult(consensusResult *state.ConsensusResult, blockHeader *types.BlockHeader) error {
102 mainChainBlockHeader, err := c.store.GetBlockHeader(&consensusResult.BlockHash)
107 attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, mainChainBlockHeader)
112 for _, bh := range detachBlockHeaders {
113 blockHash := bh.Hash()
114 block, err := c.store.GetBlock(&blockHash)
119 if err := consensusResult.DetachBlock(block); err != nil {
124 for _, bh := range attachBlockHeaders {
125 blockHash := bh.Hash()
126 block, err := c.store.GetBlock(&blockHash)
131 if err := consensusResult.ApplyBlock(block); err != nil {
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)
145 prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
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 {
159 return "", errors.New("can not find blocker by given timestamp")
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)
168 return c.getConsensusResult(state.CalcVoteSeq(blockHeader.Height), blockHeader)