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  }