X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=blobdiff_plain;f=protocol%2Fconsensus_node_manager.go;h=12146f11a55abd6aff7fff5733d7d11ac10a9dfc;hp=fd7de372a611882cab66bdd6ea8bedbacf4e499d;hb=42c5ab23c13e7f43d0055221ec38752555bd987e;hpb=96b79e74c5defa5144136e26b642df5ae2adc372 diff --git a/protocol/consensus_node_manager.go b/protocol/consensus_node_manager.go index fd7de372..12146f11 100644 --- a/protocol/consensus_node_manager.go +++ b/protocol/consensus_node_manager.go @@ -1,7 +1,6 @@ package protocol import ( - "github.com/vapor/config" "github.com/vapor/consensus" "github.com/vapor/errors" "github.com/vapor/protocol/bc" @@ -14,20 +13,8 @@ var ( errNotFoundBlockNode = errors.New("can not find block node") ) -type consensusNodeManager struct { - store Store - blockIndex *state.BlockIndex -} - -func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager { - return &consensusNodeManager{ - store: store, - blockIndex: blockIndex, - } -} - -func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) { - consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash) +func (c *Chain) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) { + consensusNodeMap, err := c.getConsensusNodes(prevBlockHash) if err != nil { return nil, err } @@ -39,216 +26,135 @@ func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey s return node, nil } -func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) { - consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash) +// GetBlocker return blocker by specified timestamp +func (c *Chain) GetBlocker(prevBlockHash *bc.Hash, timeStamp uint64) (string, error) { + consensusNodeMap, err := c.getConsensusNodes(prevBlockHash) if err != nil { - return false, err + return "", err } - consensusNode := consensusNodeMap[pubKey] - if consensusNode == nil { - return false, nil - } - - prevVoteRoundLastBlock, err := c.getPrevRoundVoteLastBlock(prevBlockHash) + prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash) if err != nil { - return false, err + return "", err } startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval - begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, len(consensusNodeMap)) - end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval - return timeStamp >= begin && timeStamp < end, nil + order := getBlockerOrder(startTimestamp, timeStamp, uint64(len(consensusNodeMap))) + for xPub, consensusNode := range consensusNodeMap { + if consensusNode.Order == order { + return xPub, nil + } + } + + // impossible occur + return "", errors.New("can not find blocker by given timestamp") } -func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order uint64, numOfConsensusNode int) uint64 { +func getBlockerOrder(startTimestamp, blockTimestamp, numOfConsensusNode uint64) uint64 { // One round of product block time for all consensus nodes - roundBlockTime := uint64(consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval) + roundBlockTime := consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval // The start time of the last round of product block - lastRoundStartTime := startTimestamp + (endTimestamp-startTimestamp)/roundBlockTime*roundBlockTime - // The time of product block of the consensus in last round - return lastRoundStartTime + order*(consensus.BlockNumEachNode*consensus.BlockTimeInterval) + lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime + // Order of blocker + return (blockTimestamp - lastRoundStartTime) / (consensus.BlockNumEachNode * consensus.BlockTimeInterval) } -func (c *consensusNodeManager) getPrevRoundVoteLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) { - prevBlockNode := c.blockIndex.GetNode(prevBlockHash) - if prevBlockNode == nil { +func (c *Chain) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*types.BlockHeader, error) { + blockHeader, err := c.store.GetBlockHeader(prevBlockHash) + if err != nil { return nil, errNotFoundBlockNode } - blockHeight := prevBlockNode.Height + 1 - - prevVoteRoundLastBlockHeight := blockHeight/consensus.RoundVoteBlockNums*consensus.RoundVoteBlockNums - 1 - // first round - if blockHeight/consensus.RoundVoteBlockNums == 0 { - prevVoteRoundLastBlockHeight = 0 - } - - lastBlockNode := prevBlockNode.GetParent(prevVoteRoundLastBlockHeight) - if lastBlockNode == nil { - return nil, errNotFoundBlockNode + for blockHeader.Height%consensus.RoundVoteBlockNums != 0 { + blockHeader, err = c.store.GetBlockHeader(&blockHeader.PreviousBlockHash) + if err != nil { + return nil, err + } } - return lastBlockNode, nil + return blockHeader, nil } -func (c *consensusNodeManager) getConsensusNodesByVoteResult(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) { - prevBlockNode := c.blockIndex.GetNode(prevBlockHash) - if prevBlockNode == nil { +func (c *Chain) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) { + prevBlockHeader, err := c.store.GetBlockHeader(prevBlockHash) + if err != nil { return nil, errNotFoundBlockNode } - seq := (prevBlockNode.Height + 1) / consensus.RoundVoteBlockNums - voteResult, err := c.store.GetVoteResult(seq) - if err != nil { - // TODO find previous round vote - voteResult = &state.VoteResult{ - Seq: seq, - NumOfVote: make(map[string]uint64), - } + bestBlockHeader := c.bestBlockHeader + preSeq := state.CalcVoteSeq(prevBlockHeader.Height+1) - 1 + if bestSeq := state.CalcVoteSeq(bestBlockHeader.Height); preSeq > bestSeq { + preSeq = bestSeq } - lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash) + lastBlockHeader, err := c.getPrevRoundLastBlock(prevBlockHash) if err != nil { return nil, err } - if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil { + voteResult, err := c.getVoteResult(preSeq, lastBlockHeader) + if err != nil { return nil, err } - if len(voteResult.NumOfVote) == 0 { - return initConsensusNodes(), nil - } - return voteResult.ConsensusNodes() } -func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, forkChainNode *state.BlockNode) error { - genesisBlockHash := config.GenesisBlock().Hash() - mainChainNode := c.blockIndex.GetNode(&genesisBlockHash) - - emptyHash := bc.Hash{} - if voteResult.LastBlockHash != emptyHash { - mainChainNode = c.blockIndex.GetNode(&voteResult.LastBlockHash) - if mainChainNode == nil { - return errNotFoundBlockNode - } - } - - var attachNodes []*state.BlockNode - var detachNodes []*state.BlockNode +func (c *Chain) getBestVoteResult() (*state.VoteResult, error) { + bestBlockHeader := c.bestBlockHeader + seq := state.CalcVoteSeq(bestBlockHeader.Height) + return c.getVoteResult(seq, bestBlockHeader) +} - for forkChainNode != nil && mainChainNode != nil && forkChainNode.Hash != mainChainNode.Hash { - if forkChainNode.Height == mainChainNode.Height { - detachNodes = append(detachNodes, mainChainNode) - mainChainNode = mainChainNode.Parent - } - attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...) - forkChainNode = forkChainNode.Parent +// getVoteResult return the vote result +// seq represent the sequence of vote +// blockHeader represent the chain in which the result of the vote is located +// Voting results need to be adjusted according to the chain +func (c *Chain) getVoteResult(seq uint64, blockHeader *types.BlockHeader) (*state.VoteResult, error) { + voteResult, err := c.store.GetVoteResult(seq) + if err != nil { + return nil, err } - for _, node := range detachNodes { - block, err := c.store.GetBlock(&node.Hash) - if err != nil { - return err - } - - if err := c.detachBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil { - return err - } + if err := c.reorganizeVoteResult(voteResult, blockHeader); err != nil { + return nil, err } - for _, node := range attachNodes { - block, err := c.store.GetBlock(&node.Hash) - if err != nil { - return err - } - - if err := c.applyBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil { - return err - } - } - return nil + return voteResult, nil } -func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) { - voteResult, err := c.getVoteResult(voteResultMap, block.Height) +func (c *Chain) reorganizeVoteResult(voteResult *state.VoteResult, blockHeader *types.BlockHeader) error { + mainChainBlockHeader, err := c.store.GetBlockHeader(&voteResult.BlockHash) if err != nil { return err } - return voteResult.ApplyBlock(block) -} - -func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) { - var err error - // This round of voting prepares for the next round - seq := blockHeight/consensus.RoundVoteBlockNums + 1 - voteResult := voteResultMap[seq] - if blockHeight == 0 { - voteResult = &state.VoteResult{ - Seq: seq, - NumOfVote: make(map[string]uint64), - } + attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, mainChainBlockHeader) + if err != nil { + return err } - if voteResult == nil { - prevVoteResult := voteResultMap[seq-1] - if prevVoteResult != nil { - voteResult = &state.VoteResult{ - Seq: seq, - NumOfVote: prevVoteResult.NumOfVote, - } + for _, bh := range detachBlockHeaders { + blockHash := bh.Hash() + block, err := c.store.GetBlock(&blockHash) + if err != nil { + return err } - } - if voteResult == nil { - voteResult, err = c.store.GetVoteResult(seq) - if err != nil && err != ErrNotFoundVoteResult { - return nil, err + if err := voteResult.DetachBlock(block); err != nil { + return err } } - if voteResult == nil { - voteResult, err = c.store.GetVoteResult(seq - 1) - if err != nil && err != ErrNotFoundVoteResult { - return nil, err - } - - if voteResult != nil { - voteResult.Seq = seq - voteResult.LastBlockHash = bc.Hash{} + for _, bh := range attachBlockHeaders { + blockHash := bh.Hash() + block, err := c.store.GetBlock(&blockHash) + if err != nil { + return err } - } - - if voteResult == nil { - return nil, errors.New("fail to get vote result") - } - voteResultMap[seq] = voteResult - return voteResult, nil -} - -func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error { - voteSeq := block.Height / consensus.RoundVoteBlockNums - voteResult := voteResultMap[voteSeq] - - if voteResult == nil { - voteResult, err := c.store.GetVoteResult(voteSeq) - if err != nil { + if err := voteResult.ApplyBlock(block); err != nil { return err } - voteResultMap[voteSeq] = voteResult } - - voteResult.DetachBlock(block) return nil } - -func initConsensusNodes() map[string]*state.ConsensusNode { - voteResult := map[string]*state.ConsensusNode{} - for i, xpub := range config.CommonConfig.Federation.Xpubs { - voteResult[xpub.String()] = &state.ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)} - } - return voteResult -}