X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=protocol%2Fconsensus_node_manager.go;h=d55e7ccf044c25c3c08f7de95f1adac80ebdafa9;hb=faa1881b5d4ad5e6f8409b6c4aaecf6aa7f8a946;hp=a941860f8053f766fe2b36a691a521c2e848d7de;hpb=eea317c609eee0bb184a6cdfdda39d9f336f92c4;p=bytom%2Fvapor.git diff --git a/protocol/consensus_node_manager.go b/protocol/consensus_node_manager.go index a941860f..d55e7ccf 100644 --- a/protocol/consensus_node_manager.go +++ b/protocol/consensus_node_manager.go @@ -1,10 +1,10 @@ package protocol import ( - "github.com/vapor/config" "github.com/vapor/consensus" "github.com/vapor/errors" "github.com/vapor/protocol/bc" + "github.com/vapor/protocol/bc/types" "github.com/vapor/protocol/state" ) @@ -13,19 +13,22 @@ var ( errNotFoundBlockNode = errors.New("can not find block node") ) -type consensusNodeManager struct { - store Store - blockIndex *state.BlockIndex +func (c *Chain) getBestConsensusResult() (*state.ConsensusResult, error) { + bestBlockHeader := c.bestBlockHeader + seq := state.CalcVoteSeq(bestBlockHeader.Height) + return c.getConsensusResult(seq, bestBlockHeader) } -func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager { - return &consensusNodeManager{ - store: store, - blockIndex: blockIndex, - } +func getBlockerOrder(startTimestamp, blockTimestamp, numOfConsensusNode uint64) uint64 { + // One round of product block time for all consensus nodes + roundBlockTime := consensus.ActiveNetParams.BlockNumEachNode * numOfConsensusNode * consensus.ActiveNetParams.BlockTimeInterval + // The start time of the last round of product block + lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime + // Order of blocker + return (blockTimestamp - lastRoundStartTime) / (consensus.ActiveNetParams.BlockNumEachNode * consensus.ActiveNetParams.BlockTimeInterval) } -func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) { +func (c *Chain) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) { consensusNodeMap, err := c.getConsensusNodes(prevBlockHash) if err != nil { return nil, err @@ -38,135 +41,129 @@ 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.getConsensusNodes(prevBlockHash) - if err != nil { - return false, err - } - - consensusNode := consensusNodeMap[pubKey] - if consensusNode == nil { - return false, nil - } - - prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash) +func (c *Chain) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) { + prevBlockHeader, err := c.store.GetBlockHeader(prevBlockHash) if err != nil { - return false, err - } - - startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval - begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, uint64(len(consensusNodeMap))) - end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval - return timeStamp >= begin && timeStamp < end, nil -} - -func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order, numOfConsensusNode uint64) uint64 { - // One round of product block time for all consensus nodes - 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) -} - -func (c *consensusNodeManager) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) { - node := c.blockIndex.GetNode(prevBlockHash) - if node == nil { - return nil, errNotFoundBlockNode - } - - for node.Height%consensus.RoundVoteBlockNums != 0 { - node = node.Parent - } - return node, nil -} - -func (c *consensusNodeManager) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) { - prevBlockNode := c.blockIndex.GetNode(prevBlockHash) - if prevBlockNode == nil { return nil, errNotFoundBlockNode } - preSeq := state.CalcVoteSeq(prevBlockNode.Height+1) - 1 - if bestSeq := state.CalcVoteSeq(c.blockIndex.BestNode().Height); preSeq > bestSeq { + bestBlockHeader := c.bestBlockHeader + preSeq := state.CalcVoteSeq(prevBlockHeader.Height+1) - 1 + if bestSeq := state.CalcVoteSeq(bestBlockHeader.Height); preSeq > bestSeq { preSeq = bestSeq } - voteResult, err := c.store.GetVoteResult(preSeq) + lastBlockHeader, err := c.getPrevRoundLastBlock(prevBlockHash) if err != nil { return nil, err } - lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash) + consensusResult, err := c.getConsensusResult(preSeq, lastBlockHeader) if err != nil { return nil, err } - if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil { - return nil, err - } - - if len(voteResult.NumOfVote) == 0 { - return federationNodes(), nil - } - return voteResult.ConsensusNodes() + return consensusResult.ConsensusNodes() } -func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) { - blockNode := c.blockIndex.BestNode() - seq := state.CalcVoteSeq(blockNode.Height) - voteResult, err := c.store.GetVoteResult(seq) +// getConsensusResult 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) getConsensusResult(seq uint64, blockHeader *types.BlockHeader) (*state.ConsensusResult, error) { + consensusResult, err := c.store.GetConsensusResult(seq) if err != nil { return nil, err } - if err := c.reorganizeVoteResult(voteResult, blockNode); err != nil { + if err := c.reorganizeConsensusResult(consensusResult, blockHeader); err != nil { return nil, err } - return voteResult, nil + return consensusResult, nil } -func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, node *state.BlockNode) error { - mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash) - var attachNodes []*state.BlockNode - var detachNodes []*state.BlockNode - for forkChainNode := node; mainChainNode != forkChainNode; forkChainNode = forkChainNode.Parent { - if forkChainNode.Height == mainChainNode.Height { - detachNodes = append(detachNodes, mainChainNode) - mainChainNode = mainChainNode.Parent +func (c *Chain) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*types.BlockHeader, error) { + blockHeader, err := c.store.GetBlockHeader(prevBlockHash) + if err != nil { + return nil, errNotFoundBlockNode + } + + for blockHeader.Height%consensus.ActiveNetParams.RoundVoteBlockNums != 0 { + blockHeader, err = c.store.GetBlockHeader(&blockHeader.PreviousBlockHash) + if err != nil { + return nil, err } - attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...) + } + return blockHeader, nil +} + +func (c *Chain) reorganizeConsensusResult(consensusResult *state.ConsensusResult, blockHeader *types.BlockHeader) error { + mainChainBlockHeader, err := c.store.GetBlockHeader(&consensusResult.BlockHash) + if err != nil { + return err } - for _, node := range detachNodes { - block, err := c.store.GetBlock(&node.Hash) + attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, mainChainBlockHeader) + if err != nil { + return err + } + + for _, bh := range detachBlockHeaders { + blockHash := bh.Hash() + block, err := c.store.GetBlock(&blockHash) if err != nil { return err } - if err := voteResult.DetachBlock(block); err != nil { + if err := consensusResult.DetachBlock(block); err != nil { return err } } - for _, node := range attachNodes { - block, err := c.store.GetBlock(&node.Hash) + for _, bh := range attachBlockHeaders { + blockHash := bh.Hash() + block, err := c.store.GetBlock(&blockHash) if err != nil { return err } - if err := voteResult.ApplyBlock(block); err != nil { + if err := consensusResult.ApplyBlock(block); err != nil { return err } } return nil } -func federationNodes() 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)} +// 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 "", err + } + + prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash) + if err != nil { + return "", err + } + + startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.ActiveNetParams.BlockTimeInterval + 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") +} + +// GetConsensusResultByHash return vote result by block hash +func (c *Chain) GetConsensusResultByHash(blockHash *bc.Hash) (*state.ConsensusResult, error) { + blockHeader, err := c.store.GetBlockHeader(blockHash) + if err != nil { + return nil, err } - return voteResult + return c.getConsensusResult(state.CalcVoteSeq(blockHeader.Height), blockHeader) }