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"
13 errNotFoundConsensusNode = errors.New("can not found consensus node")
14 errNotFoundBlockNode = errors.New("can not find block node")
17 func (c *Chain) getBestConsensusResult() (*state.ConsensusResult, error) {
21 bestBlockHeader := c.bestBlockHeader
22 seq := state.CalcVoteSeq(bestBlockHeader.Height)
23 return c.getConsensusResult(seq, bestBlockHeader)
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
32 return (blockTimestamp - lastRoundStartTime) / (consensus.ActiveNetParams.BlockNumEachNode * consensus.ActiveNetParams.BlockTimeInterval)
35 func (c *Chain) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
36 consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
41 node, exist := consensusNodeMap[pubkey]
43 return nil, errNotFoundConsensusNode
48 func (c *Chain) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
49 prevBlockHeader, err := c.store.GetBlockHeader(prevBlockHash)
51 return nil, errNotFoundBlockNode
54 bestBlockHeader := c.bestBlockHeader
55 preSeq := state.CalcVoteSeq(prevBlockHeader.Height+1) - 1
56 if bestSeq := state.CalcVoteSeq(bestBlockHeader.Height); preSeq > bestSeq {
60 lastBlockHeader, err := c.getPrevRoundLastBlock(prevBlockHash)
65 consensusResult, err := c.getConsensusResult(preSeq, lastBlockHeader)
70 return consensusResult.ConsensusNodes()
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)
83 if err := c.reorganizeConsensusResult(consensusResult, blockHeader); err != nil {
87 return consensusResult, nil
90 func (c *Chain) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*types.BlockHeader, error) {
91 blockHeader, err := c.store.GetBlockHeader(prevBlockHash)
93 return nil, errNotFoundBlockNode
96 for blockHeader.Height%consensus.ActiveNetParams.RoundVoteBlockNums != 0 {
97 blockHeader, err = c.store.GetBlockHeader(&blockHeader.PreviousBlockHash)
102 return blockHeader, nil
105 func (c *Chain) reorganizeConsensusResult(consensusResult *state.ConsensusResult, blockHeader *types.BlockHeader) error {
106 mainChainBlockHeader, err := c.store.GetBlockHeader(&consensusResult.BlockHash)
111 attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, mainChainBlockHeader)
116 for _, bh := range detachBlockHeaders {
117 blockHash := bh.Hash()
118 block, err := c.store.GetBlock(&blockHash)
123 if err := consensusResult.DetachBlock(block); err != nil {
128 for _, bh := range attachBlockHeaders {
129 blockHash := bh.Hash()
130 block, err := c.store.GetBlock(&blockHash)
135 if err := consensusResult.ApplyBlock(block); err != nil {
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)
149 prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
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 {
163 return "", errors.New("can not find blocker by given timestamp")
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)
172 return c.getConsensusResult(state.CalcVoteSeq(blockHeader.Height), blockHeader)