123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- // Copyright 2017 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package core
- import (
- "math/big"
- "sync"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/consensus/istanbul"
- istanbulcommon "github.com/ethereum/go-ethereum/consensus/istanbul/common"
- ibfttypes "github.com/ethereum/go-ethereum/consensus/istanbul/ibft/types"
- )
- // sendNextRoundChange sends the ROUND CHANGE message with current round + 1
- func (c *core) sendNextRoundChange() {
- cv := c.currentView()
- c.sendRoundChange(new(big.Int).Add(cv.Round, common.Big1))
- }
- // sendRoundChange sends the ROUND CHANGE message with the given round
- func (c *core) sendRoundChange(round *big.Int) {
- logger := c.logger.New("state", c.state)
- cv := c.currentView()
- if cv.Round.Cmp(round) >= 0 {
- logger.Error("Cannot send out the round change", "current round", cv.Round, "target round", round)
- return
- }
- c.catchUpRound(&istanbul.View{
- // The round number we'd like to transfer to.
- Round: new(big.Int).Set(round),
- Sequence: new(big.Int).Set(cv.Sequence),
- })
- // Now we have the new round number and sequence number
- cv = c.currentView()
- rc := &istanbul.Subject{
- View: cv,
- Digest: common.Hash{},
- }
- payload, err := ibfttypes.Encode(rc)
- if err != nil {
- logger.Error("Failed to encode ROUND CHANGE", "rc", rc, "err", err)
- return
- }
- c.broadcast(&ibfttypes.Message{
- Code: ibfttypes.MsgRoundChange,
- Msg: payload,
- })
- }
- func (c *core) handleRoundChange(msg *ibfttypes.Message, src istanbul.Validator) error {
- logger := c.logger.New("state", c.state, "from", src.Address().Hex())
- // Decode ROUND CHANGE message
- var rc *istanbul.Subject
- if err := msg.Decode(&rc); err != nil {
- logger.Error("Failed to decode ROUND CHANGE", "err", err)
- return istanbulcommon.ErrInvalidMessage
- }
- if err := c.checkMessage(ibfttypes.MsgRoundChange, rc.View); err != nil {
- return err
- }
- cv := c.currentView()
- roundView := rc.View
- // Add the ROUND CHANGE message to its message set and return how many
- // messages we've got with the same round number and sequence number.
- num, err := c.roundChangeSet.Add(roundView.Round, msg)
- if err != nil {
- logger.Warn("Failed to add round change message", "from", src, "msg", msg, "err", err)
- return err
- }
- // Once we received f+1 ROUND CHANGE messages, those messages form a weak certificate.
- // If our round number is smaller than the certificate's round number, we would
- // try to catch up the round number.
- if c.waitingForRoundChange && num == c.valSet.F()+1 {
- if cv.Round.Cmp(roundView.Round) < 0 {
- c.sendRoundChange(roundView.Round)
- }
- return nil
- } else if num == c.QuorumSize() && (c.waitingForRoundChange || cv.Round.Cmp(roundView.Round) < 0) {
- // We've received 2f+1/Ceil(2N/3) ROUND CHANGE messages, start a new round immediately.
- c.startNewRound(roundView.Round)
- return nil
- } else if cv.Round.Cmp(roundView.Round) < 0 {
- // Only gossip the message with current round to other validators.
- return istanbulcommon.ErrIgnored
- }
- return nil
- }
- // ----------------------------------------------------------------------------
- func newRoundChangeSet(valSet istanbul.ValidatorSet) *roundChangeSet {
- return &roundChangeSet{
- validatorSet: valSet,
- roundChanges: make(map[uint64]*messageSet),
- mu: new(sync.Mutex),
- }
- }
- type roundChangeSet struct {
- validatorSet istanbul.ValidatorSet
- roundChanges map[uint64]*messageSet
- mu *sync.Mutex
- }
- // Add adds the round and message into round change set
- func (rcs *roundChangeSet) Add(r *big.Int, msg *ibfttypes.Message) (int, error) {
- rcs.mu.Lock()
- defer rcs.mu.Unlock()
- round := r.Uint64()
- if rcs.roundChanges[round] == nil {
- rcs.roundChanges[round] = newMessageSet(rcs.validatorSet)
- }
- err := rcs.roundChanges[round].Add(msg)
- if err != nil {
- return 0, err
- }
- return rcs.roundChanges[round].Size(), nil
- }
- // Clear deletes the messages with smaller round
- func (rcs *roundChangeSet) Clear(round *big.Int) {
- rcs.mu.Lock()
- defer rcs.mu.Unlock()
- for k, rms := range rcs.roundChanges {
- if len(rms.Values()) == 0 || k < round.Uint64() {
- delete(rcs.roundChanges, k)
- }
- }
- }
- // MaxRound returns the max round which the number of messages is equal or larger than num
- func (rcs *roundChangeSet) MaxRound(num int) *big.Int {
- rcs.mu.Lock()
- defer rcs.mu.Unlock()
- var maxRound *big.Int
- for k, rms := range rcs.roundChanges {
- if rms.Size() < num {
- continue
- }
- r := big.NewInt(int64(k))
- if maxRound == nil || maxRound.Cmp(r) < 0 {
- maxRound = r
- }
- }
- return maxRound
- }
|