github.com/klaytn/klaytn@v1.10.2/consensus/istanbul/backend/handler.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2017 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from quorum/consensus/istanbul/backend/handler.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package backend
    22  
    23  import (
    24  	"errors"
    25  
    26  	lru "github.com/hashicorp/golang-lru"
    27  	"github.com/klaytn/klaytn/common"
    28  	"github.com/klaytn/klaytn/consensus"
    29  	"github.com/klaytn/klaytn/consensus/istanbul"
    30  	"github.com/klaytn/klaytn/networks/p2p"
    31  )
    32  
    33  const (
    34  	IstanbulMsg = 0x11
    35  )
    36  
    37  var (
    38  	// errDecodeFailed is returned when decode message fails
    39  	errDecodeFailed       = errors.New("fail to decode istanbul message")
    40  	errNoChainReader      = errors.New("sb.chain is nil! --mine option might be missing")
    41  	errInvalidPeerAddress = errors.New("invalid address")
    42  
    43  	// TODO-Klaytn-Istanbul: define Versions and Lengths with correct values.
    44  	IstanbulProtocol = consensus.Protocol{
    45  		Name:     "istanbul",
    46  		Versions: []uint{65, 64},
    47  		Lengths:  []uint64{23, 21},
    48  	}
    49  )
    50  
    51  // Protocol implements consensus.Engine.Protocol
    52  func (sb *backend) Protocol() consensus.Protocol {
    53  	return IstanbulProtocol
    54  }
    55  
    56  // HandleMsg implements consensus.Handler.HandleMsg
    57  func (sb *backend) HandleMsg(addr common.Address, msg p2p.Msg) (bool, error) {
    58  	sb.coreMu.Lock()
    59  	defer sb.coreMu.Unlock()
    60  
    61  	if msg.Code == IstanbulMsg {
    62  		if !sb.coreStarted {
    63  			return true, istanbul.ErrStoppedEngine
    64  		}
    65  
    66  		var cmsg istanbul.ConsensusMsg
    67  
    68  		// var data []byte
    69  		if err := msg.Decode(&cmsg); err != nil {
    70  			return true, errDecodeFailed
    71  		}
    72  		data := cmsg.Payload
    73  		hash := istanbul.RLPHash(data)
    74  
    75  		// Mark peer's message
    76  		var m *lru.ARCCache
    77  		ms, ok := sb.recentMessages.Get(addr)
    78  		if ok {
    79  			m, _ = ms.(*lru.ARCCache)
    80  		} else {
    81  			m, _ = lru.NewARC(inmemoryMessages)
    82  			sb.recentMessages.Add(addr, m)
    83  		}
    84  		m.Add(hash, true)
    85  
    86  		// Mark self known message
    87  		if _, ok := sb.knownMessages.Get(hash); ok {
    88  			return true, nil
    89  		}
    90  		sb.knownMessages.Add(hash, true)
    91  
    92  		go sb.istanbulEventMux.Post(istanbul.MessageEvent{
    93  			Payload: data,
    94  			Hash:    cmsg.PrevHash,
    95  		})
    96  
    97  		return true, nil
    98  	}
    99  	return false, nil
   100  }
   101  
   102  func (sb *backend) ValidatePeerType(addr common.Address) error {
   103  	// istanbul.Start vs try to connect by peer
   104  	for sb.chain == nil {
   105  		return errNoChainReader
   106  	}
   107  	validators := sb.getValidators(sb.chain.CurrentHeader().Number.Uint64(), sb.chain.CurrentHeader().Hash())
   108  	for _, val := range validators.List() {
   109  		if addr == val.Address() {
   110  			return nil
   111  		}
   112  	}
   113  	for _, val := range validators.DemotedList() {
   114  		if addr == val.Address() {
   115  			return nil
   116  		}
   117  	}
   118  	return errInvalidPeerAddress
   119  }
   120  
   121  // SetBroadcaster implements consensus.Handler.SetBroadcaster
   122  func (sb *backend) SetBroadcaster(broadcaster consensus.Broadcaster, nodetype common.ConnType) {
   123  	sb.broadcaster = broadcaster
   124  	if nodetype == common.CONSENSUSNODE {
   125  		sb.broadcaster.RegisterValidator(common.CONSENSUSNODE, sb)
   126  	}
   127  }
   128  
   129  // RegisterConsensusMsgCode registers the channel of consensus msg.
   130  func (sb *backend) RegisterConsensusMsgCode(peer consensus.Peer) {
   131  	if err := peer.RegisterConsensusMsgCode(IstanbulMsg); err != nil {
   132  		logger.Error("RegisterConsensusMsgCode failed", "err", err)
   133  	}
   134  }
   135  
   136  func (sb *backend) NewChainHead() error {
   137  	sb.coreMu.RLock()
   138  	defer sb.coreMu.RUnlock()
   139  	if !sb.coreStarted {
   140  		return istanbul.ErrStoppedEngine
   141  	}
   142  
   143  	go sb.istanbulEventMux.Post(istanbul.FinalCommittedEvent{})
   144  	return nil
   145  }