7 "github.com/vapor/config"
8 "github.com/vapor/consensus"
9 "github.com/vapor/errors"
10 "github.com/vapor/math/checked"
11 "github.com/vapor/protocol/bc"
12 "github.com/vapor/protocol/bc/types"
13 "github.com/vapor/protocol/state"
17 errNotFoundConsensusNode = errors.New("can not found consensus node")
18 errNotFoundBlockNode = errors.New("can not find block node")
21 type consensusNode struct {
27 type consensusNodeSlice []*consensusNode
29 func (c consensusNodeSlice) Len() int { return len(c) }
30 func (c consensusNodeSlice) Less(i, j int) bool { return c[i].voteNum > c[j].voteNum }
31 func (c consensusNodeSlice) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
33 type consensusNodeManager struct {
35 blockIndex *state.BlockIndex
38 func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager {
39 return &consensusNodeManager{
41 blockIndex: blockIndex,
45 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*consensusNode, error) {
46 consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
51 node, exist := consensusNodeMap[pubkey]
53 return nil, errNotFoundConsensusNode
58 func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) {
59 consensusNode, err := c.getConsensusNode(prevBlockHash, pubKey)
60 if err != nil && err != errNotFoundConsensusNode {
64 if consensusNode == nil {
68 prevVoteRoundLastBlock, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
73 startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval
74 begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.order)
75 end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval
76 return timeStamp >= begin && timeStamp < end, nil
79 func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order uint64) uint64 {
80 // One round of product block time for all consensus nodes
81 roundBlockTime := uint64(consensus.BlockNumEachNode * consensus.NumOfConsensusNode * consensus.BlockTimeInterval)
82 // The start time of the last round of product block
83 lastRoundStartTime := startTimestamp + (endTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
84 // The time of product block of the consensus in last round
85 return lastRoundStartTime + order*(consensus.BlockNumEachNode*consensus.BlockTimeInterval)
88 func (c *consensusNodeManager) getPrevRoundVoteLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
89 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
90 if prevBlockNode == nil {
91 return nil, errNotFoundBlockNode
94 blockHeight := prevBlockNode.Height + 1
96 prevVoteRoundLastBlockHeight := blockHeight/consensus.RoundVoteBlockNums*consensus.RoundVoteBlockNums - 1
98 if blockHeight/consensus.RoundVoteBlockNums == 0 {
99 prevVoteRoundLastBlockHeight = 0
102 lastBlockNode := prevBlockNode.GetParent(prevVoteRoundLastBlockHeight)
103 if lastBlockNode == nil {
104 return nil, errNotFoundBlockNode
106 return lastBlockNode, nil
109 func (c *consensusNodeManager) getConsensusNodesByVoteResult(prevBlockHash *bc.Hash) (map[string]*consensusNode, error) {
110 prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
111 if prevBlockNode == nil {
112 return nil, errNotFoundBlockNode
115 seq := (prevBlockNode.Height + 1) / consensus.RoundVoteBlockNums
116 voteResult, err := c.store.GetVoteResult(seq)
118 // TODO find previous round vote
119 voteResult = &state.VoteResult{
121 NumOfVote: make(map[string]uint64),
126 lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
131 if err := c.reorganizeVoteResult(voteResult, lastBlockNode); err != nil {
135 if len(voteResult.NumOfVote) == 0 {
136 return initConsensusNodes(), nil
139 var nodes []*consensusNode
140 for pubkey, voteNum := range voteResult.NumOfVote {
141 if voteNum >= consensus.MinVoteNum {
142 nodes = append(nodes, &consensusNode{
148 // In principle, there is no need to sort all voting nodes.
149 // if there is a performance problem, consider the optimization later.
150 // TODO not consider the same number of votes
151 sort.Sort(consensusNodeSlice(nodes))
153 result := make(map[string]*consensusNode)
154 for i := 0; i < len(nodes) && i < consensus.NumOfConsensusNode; i++ {
156 node.order = uint64(i)
157 result[node.pubkey] = node
162 func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, forkChainNode *state.BlockNode) error {
163 genesisBlockHash := config.GenesisBlock().Hash()
164 mainChainNode := c.blockIndex.GetNode(&genesisBlockHash)
166 emptyHash := bc.Hash{}
167 if voteResult.LastBlockHash != emptyHash {
168 mainChainNode = c.blockIndex.GetNode(&voteResult.LastBlockHash)
169 if mainChainNode == nil {
170 return errNotFoundBlockNode
174 var attachNodes []*state.BlockNode
175 var detachNodes []*state.BlockNode
177 for forkChainNode != nil && mainChainNode != nil && forkChainNode.Hash != mainChainNode.Hash {
178 if forkChainNode.Height == mainChainNode.Height {
179 detachNodes = append(detachNodes, mainChainNode)
180 mainChainNode = mainChainNode.Parent
182 attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
183 forkChainNode = forkChainNode.Parent
186 for _, node := range detachNodes {
187 block, err := c.store.GetBlock(&node.Hash)
192 if err := c.detachBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil {
197 for _, node := range attachNodes {
198 block, err := c.store.GetBlock(&node.Hash)
203 if err := c.applyBlock(map[uint64]*state.VoteResult{voteResult.Seq: voteResult}, block); err != nil {
210 func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
211 voteResult, err := c.getVoteResult(voteResultMap, block.Height)
216 emptyHash := bc.Hash{}
217 if voteResult.LastBlockHash != emptyHash && voteResult.LastBlockHash != block.PreviousBlockHash {
218 return errors.New("bbft append block error, the block parent hash is not equals last block hash of vote result")
221 for _, tx := range block.Transactions {
222 for _, input := range tx.Inputs {
223 unVoteInput, ok := input.TypedInput.(*types.UnvoteInput)
228 pubkey := hex.EncodeToString(unVoteInput.Vote)
229 voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount)
231 return errVotingOperationOverFlow
234 for _, output := range tx.Outputs {
235 voteOutput, ok := output.TypedOutput.(*types.VoteTxOutput)
240 pubkey := hex.EncodeToString(voteOutput.Vote)
241 voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount)
243 return errVotingOperationOverFlow
248 voteResult.Finalized = (block.Height+1)%consensus.RoundVoteBlockNums == 0
252 func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) {
254 // This round of voting prepares for the next round
255 seq := blockHeight/consensus.RoundVoteBlockNums + 1
256 voteResult := voteResultMap[seq]
257 if blockHeight == 0 {
258 voteResult = &state.VoteResult{
260 NumOfVote: make(map[string]uint64),
265 if voteResult == nil {
266 prevVoteResult := voteResultMap[seq-1]
267 if prevVoteResult != nil {
268 voteResult = &state.VoteResult{
270 NumOfVote: prevVoteResult.NumOfVote,
276 if voteResult == nil {
277 voteResult, err = c.store.GetVoteResult(seq)
278 if err != nil && err != ErrNotFoundVoteResult {
283 if voteResult == nil {
284 voteResult, err = c.store.GetVoteResult(seq - 1)
285 if err != nil && err != ErrNotFoundVoteResult {
289 if voteResult != nil {
290 // previous round voting must have finalized
291 if !voteResult.Finalized {
292 return nil, errors.New("previous round voting has not finalized")
296 voteResult.Finalized = false
297 voteResult.LastBlockHash = bc.Hash{}
301 if voteResult == nil {
302 return nil, errors.New("fail to get vote result")
305 voteResultMap[seq] = voteResult
306 return voteResult, nil
309 func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
310 voteSeq := block.Height / consensus.RoundVoteBlockNums
311 voteResult := voteResultMap[voteSeq]
313 if voteResult == nil {
314 voteResult, err := c.store.GetVoteResult(voteSeq)
318 voteResultMap[voteSeq] = voteResult
321 if voteResult.LastBlockHash != block.Hash() {
322 return errors.New("bbft detach block error, the block hash is not equals last block hash of vote result")
325 for _, tx := range block.Transactions {
326 for _, input := range tx.Inputs {
327 unVoteInput, ok := input.TypedInput.(*types.UnvoteInput)
332 pubkey := hex.EncodeToString(unVoteInput.Vote)
333 voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount)
335 return errVotingOperationOverFlow
338 for _, output := range tx.Outputs {
339 voteOutput, ok := output.TypedOutput.(*types.VoteTxOutput)
344 pubkey := hex.EncodeToString(voteOutput.Vote)
345 voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount)
347 return errVotingOperationOverFlow
352 voteResult.Finalized = false
356 func initConsensusNodes() map[string]*consensusNode {
357 voteResult := map[string]*consensusNode{}
358 for i, pubkey := range config.CommonConfig.Federation.Xpubs {
359 pubkeyStr := pubkey.String()
360 voteResult[pubkeyStr] = &consensusNode{pubkey: pubkeyStr, voteNum: 0, order: uint64(i)}