github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/roundchange.go (about) 1 package core 2 3 import ( 4 "math/big" 5 "sync" 6 7 "github.com/quickchainproject/quickchain/common" 8 bft "github.com/quickchainproject/quickchain/consensus/dbft" 9 ) 10 11 // sendNextRoundChange sends the ROUND CHANGE message with current round + 1 12 func (c *core) sendNextRoundChange() { 13 cv := c.currentView() 14 c.sendRoundChange(new(big.Int).Add(cv.Round, common.Big1)) 15 } 16 17 // sendRoundChange sends the ROUND CHANGE message with the given round 18 func (c *core) sendRoundChange(round *big.Int) { 19 logger := c.logger.New("state", c.state) 20 21 cv := c.currentView() 22 if cv.Round.Cmp(round) >= 0 { 23 logger.Error("Cannot send out the round change", "current round", cv.Round, "target round", round) 24 return 25 } 26 27 c.catchUpRound(&bft.View{ 28 // The round number we'd like to transfer to. 29 Round: new(big.Int).Set(round), 30 Sequence: new(big.Int).Set(cv.Sequence), 31 }) 32 33 // Now we have the new round number and sequence number 34 cv = c.currentView() 35 rc := &bft.Subject{ 36 View: cv, 37 Digest: common.Hash{}, 38 } 39 40 payload, err := Encode(rc) 41 if err != nil { 42 logger.Error("Failed to encode ROUND CHANGE", "rc", rc, "err", err) 43 return 44 } 45 46 c.broadcast(&message{ 47 Code: msgRoundChange, 48 Msg: payload, 49 }) 50 } 51 52 func (c *core) handleRoundChange(msg *message, src bft.Validator) error { 53 logger := c.logger.New("state", c.state, "from", src.Address().Hex()) 54 55 // Decode ROUND CHANGE message 56 var rc *bft.Subject 57 if err := msg.Decode(&rc); err != nil { 58 logger.Error("Failed to decode ROUND CHANGE", "err", err) 59 return errInvalidMessage 60 } 61 62 if err := c.checkMessage(msgRoundChange, rc.View); err != nil { 63 return err 64 } 65 66 cv := c.currentView() 67 roundView := rc.View 68 69 // Add the ROUND CHANGE message to its message set and return how many 70 // messages we've got with the same round number and sequence number. 71 num, err := c.roundChangeSet.Add(roundView.Round, msg) 72 if err != nil { 73 logger.Warn("Failed to add round change message", "from", src, "msg", msg, "err", err) 74 return err 75 } 76 77 // Once we received f+1 ROUND CHANGE messages, those messages form a weak certificate. 78 // If our round number is smaller than the certificate's round number, we would 79 // try to catch up the round number. 80 if c.waitingForRoundChange && num == int(c.valSet.F()+1) { 81 if cv.Round.Cmp(roundView.Round) < 0 { 82 c.sendRoundChange(roundView.Round) 83 } 84 return nil 85 } else if num == int(2*c.valSet.F()+1) && (c.waitingForRoundChange || cv.Round.Cmp(roundView.Round) < 0) { 86 // We've received 2f+1 ROUND CHANGE messages, start a new round immediately. 87 c.startNewRound(roundView.Round) 88 return nil 89 } else if cv.Round.Cmp(roundView.Round) < 0 { 90 // Only gossip the message with current round to other validators. 91 return errIgnored 92 } 93 return nil 94 } 95 96 // ---------------------------------------------------------------------------- 97 98 func newRoundChangeSet(valSet bft.ValidatorSet) *roundChangeSet { 99 return &roundChangeSet{ 100 validatorSet: valSet, 101 roundChanges: make(map[uint64]*messageSet), 102 mu: new(sync.Mutex), 103 } 104 } 105 106 type roundChangeSet struct { 107 validatorSet bft.ValidatorSet 108 roundChanges map[uint64]*messageSet 109 mu *sync.Mutex 110 } 111 112 // Add adds the round and message into round change set 113 func (rcs *roundChangeSet) Add(r *big.Int, msg *message) (int, error) { 114 rcs.mu.Lock() 115 defer rcs.mu.Unlock() 116 117 round := r.Uint64() 118 if rcs.roundChanges[round] == nil { 119 rcs.roundChanges[round] = newMessageSet(rcs.validatorSet) 120 } 121 err := rcs.roundChanges[round].Add(msg) 122 if err != nil { 123 return 0, err 124 } 125 return rcs.roundChanges[round].Size(), nil 126 } 127 128 // Clear deletes the messages with smaller round 129 func (rcs *roundChangeSet) Clear(round *big.Int) { 130 rcs.mu.Lock() 131 defer rcs.mu.Unlock() 132 133 for k, rms := range rcs.roundChanges { 134 if len(rms.Values()) == 0 || k < round.Uint64() { 135 delete(rcs.roundChanges, k) 136 } 137 } 138 } 139 140 // MaxRound returns the max round which the number of messages is equal or larger than num 141 func (rcs *roundChangeSet) MaxRound(num int) *big.Int { 142 rcs.mu.Lock() 143 defer rcs.mu.Unlock() 144 145 var maxRound *big.Int 146 for k, rms := range rcs.roundChanges { 147 if rms.Size() < num { 148 continue 149 } 150 r := big.NewInt(int64(k)) 151 if maxRound == nil || maxRound.Cmp(r) < 0 { 152 maxRound = r 153 } 154 } 155 return maxRound 156 }