github.com/klaytn/klaytn@v1.12.1/node/cn/peer_set.go (about)

     1  // Modifications Copyright 2019 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of go-ethereum.
     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 eth/peer.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package cn
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"math/big"
    27  	"sync"
    28  	"time"
    29  
    30  	"github.com/klaytn/klaytn/blockchain/types"
    31  	"github.com/klaytn/klaytn/common"
    32  	"github.com/klaytn/klaytn/consensus/istanbul/backend"
    33  	"github.com/klaytn/klaytn/networks/p2p"
    34  	"github.com/klaytn/klaytn/node/cn/snap"
    35  )
    36  
    37  var (
    38  	// errPeerAlreadyRegistered is returned if a peer is attempted to be added
    39  	// to the peer set, but one with the same id already exists.
    40  	errPeerAlreadyRegistered = errors.New("peer already registered")
    41  
    42  	// errSnapWithoutIstanbul is returned if a peer attempts to connect only on the
    43  	// snap protocol without advertizing the istanbul main protocol.
    44  	errSnapWithoutIstanbul = errors.New("peer connected on snap without compatible istanbul support")
    45  )
    46  
    47  //go:generate mockgen -destination=node/cn/peer_set_mock_test.go -package=cn github.com/klaytn/klaytn/node/cn PeerSet
    48  type PeerSet interface {
    49  	Register(p Peer, ext *snap.Peer) error
    50  	Unregister(id string) error
    51  
    52  	Peers() map[string]Peer
    53  	CNPeers() map[common.Address]Peer
    54  	ENPeers() map[common.Address]Peer
    55  	PNPeers() map[common.Address]Peer
    56  	Peer(id string) Peer
    57  	Len() int
    58  	SnapLen() int
    59  
    60  	PeersWithoutBlock(hash common.Hash) []Peer
    61  
    62  	SamplePeersToSendBlock(block *types.Block, nodeType common.ConnType) []Peer
    63  	SampleResendPeersByType(nodeType common.ConnType) []Peer
    64  
    65  	PeersWithoutTx(hash common.Hash) []Peer
    66  	TypePeersWithoutTx(hash common.Hash, nodetype common.ConnType) []Peer
    67  	CNWithoutTx(hash common.Hash) []Peer
    68  	UpdateTypePeersWithoutTxs(tx *types.Transaction, nodeType common.ConnType, peersWithoutTxsMap map[Peer]types.Transactions)
    69  
    70  	RegisterSnapExtension(peer *snap.Peer) error
    71  	WaitSnapExtension(peer Peer) (*snap.Peer, error)
    72  
    73  	BestPeer() Peer
    74  	RegisterValidator(connType common.ConnType, validator p2p.PeerTypeValidator)
    75  	Close()
    76  }
    77  
    78  // peerSet represents the collection of active peers currently participating in
    79  // the Klaytn sub-protocol.
    80  type peerSet struct {
    81  	peers   map[string]Peer
    82  	cnpeers map[common.Address]Peer
    83  	pnpeers map[common.Address]Peer
    84  	enpeers map[common.Address]Peer
    85  
    86  	snapPeers int                        // Number of `snap` compatible peers for connection prioritization
    87  	snapWait  map[string]chan *snap.Peer // Peers connected on `eth` waiting for their snap extension
    88  	snapPend  map[string]*snap.Peer      // Peers connected on the `snap` protocol, but not yet on `eth`
    89  
    90  	lock   sync.RWMutex
    91  	closed bool
    92  
    93  	validator map[common.ConnType]p2p.PeerTypeValidator
    94  }
    95  
    96  // newPeerSet creates a new peer set to track the active participants.
    97  func newPeerSet() *peerSet {
    98  	peerSet := &peerSet{
    99  		peers:     make(map[string]Peer),
   100  		cnpeers:   make(map[common.Address]Peer),
   101  		pnpeers:   make(map[common.Address]Peer),
   102  		enpeers:   make(map[common.Address]Peer),
   103  		snapWait:  make(map[string]chan *snap.Peer),
   104  		snapPend:  make(map[string]*snap.Peer),
   105  		validator: make(map[common.ConnType]p2p.PeerTypeValidator),
   106  	}
   107  
   108  	peerSet.validator[common.CONSENSUSNODE] = ByPassValidator{}
   109  	peerSet.validator[common.PROXYNODE] = ByPassValidator{}
   110  	peerSet.validator[common.ENDPOINTNODE] = ByPassValidator{}
   111  
   112  	return peerSet
   113  }
   114  
   115  // Register injects a new peer into the working set, or returns an error if the
   116  // peer is already known.
   117  func (ps *peerSet) Register(p Peer, ext *snap.Peer) error {
   118  	ps.lock.Lock()
   119  	defer ps.lock.Unlock()
   120  
   121  	if ps.closed {
   122  		return errClosed
   123  	}
   124  	if _, ok := ps.peers[p.GetID()]; ok {
   125  		return errAlreadyRegistered
   126  	}
   127  
   128  	var peersByNodeType map[common.Address]Peer
   129  	var peerTypeValidator p2p.PeerTypeValidator
   130  
   131  	switch p.ConnType() {
   132  	case common.CONSENSUSNODE:
   133  		peersByNodeType = ps.cnpeers
   134  		peerTypeValidator = ps.validator[common.CONSENSUSNODE]
   135  	case common.PROXYNODE:
   136  		peersByNodeType = ps.pnpeers
   137  		peerTypeValidator = ps.validator[common.PROXYNODE]
   138  	case common.ENDPOINTNODE:
   139  		peersByNodeType = ps.enpeers
   140  		peerTypeValidator = ps.validator[common.ENDPOINTNODE]
   141  	default:
   142  		return fmt.Errorf("undefined peer type entered, p.ConnType(): %v", p.ConnType())
   143  	}
   144  
   145  	if _, ok := peersByNodeType[p.GetAddr()]; ok {
   146  		return errAlreadyRegistered
   147  	}
   148  
   149  	if err := peerTypeValidator.ValidatePeerType(p.GetAddr()); err != nil {
   150  		return fmt.Errorf("fail to validate peer type: %s", err)
   151  	}
   152  
   153  	if ext != nil {
   154  		p.AddSnapExtension(ext)
   155  		ps.snapPeers++
   156  	}
   157  
   158  	peersByNodeType[p.GetAddr()] = p // add peer to its node type peer map.
   159  	ps.peers[p.GetID()] = p          // add peer to entire peer map.
   160  
   161  	cnPeerCountGauge.Update(int64(len(ps.cnpeers)))
   162  	pnPeerCountGauge.Update(int64(len(ps.pnpeers)))
   163  	enPeerCountGauge.Update(int64(len(ps.enpeers)))
   164  	go p.Broadcast()
   165  
   166  	return nil
   167  }
   168  
   169  // Unregister removes a remote peer from the active set, disabling any further
   170  // actions to/from that particular entity.
   171  func (ps *peerSet) Unregister(id string) error {
   172  	ps.lock.Lock()
   173  	defer ps.lock.Unlock()
   174  
   175  	p, ok := ps.peers[id]
   176  	if !ok {
   177  		return errNotRegistered
   178  	}
   179  	delete(ps.peers, id)
   180  	p.Close()
   181  
   182  	switch p.ConnType() {
   183  	case common.CONSENSUSNODE:
   184  		delete(ps.cnpeers, p.GetAddr())
   185  	case common.PROXYNODE:
   186  		delete(ps.pnpeers, p.GetAddr())
   187  	case common.ENDPOINTNODE:
   188  		delete(ps.enpeers, p.GetAddr())
   189  	default:
   190  		return errUnexpectedNodeType
   191  	}
   192  
   193  	if p.ExistSnapExtension() {
   194  		ps.snapPeers--
   195  	}
   196  
   197  	cnPeerCountGauge.Update(int64(len(ps.cnpeers)))
   198  	pnPeerCountGauge.Update(int64(len(ps.pnpeers)))
   199  	enPeerCountGauge.Update(int64(len(ps.enpeers)))
   200  	return nil
   201  }
   202  
   203  func (ps *peerSet) Peers() map[string]Peer {
   204  	ps.lock.RLock()
   205  	defer ps.lock.RUnlock()
   206  
   207  	set := make(map[string]Peer)
   208  	for id, p := range ps.peers {
   209  		set[id] = p
   210  	}
   211  	return set
   212  }
   213  
   214  func (ps *peerSet) CNPeers() map[common.Address]Peer {
   215  	ps.lock.RLock()
   216  	defer ps.lock.RUnlock()
   217  
   218  	set := make(map[common.Address]Peer)
   219  	for addr, p := range ps.cnpeers {
   220  		set[addr] = p
   221  	}
   222  	return set
   223  }
   224  
   225  func (ps *peerSet) ENPeers() map[common.Address]Peer {
   226  	ps.lock.RLock()
   227  	defer ps.lock.RUnlock()
   228  
   229  	set := make(map[common.Address]Peer)
   230  	for addr, p := range ps.enpeers {
   231  		set[addr] = p
   232  	}
   233  	return set
   234  }
   235  
   236  func (ps *peerSet) PNPeers() map[common.Address]Peer {
   237  	ps.lock.RLock()
   238  	defer ps.lock.RUnlock()
   239  
   240  	set := make(map[common.Address]Peer)
   241  	for addr, p := range ps.pnpeers {
   242  		set[addr] = p
   243  	}
   244  	return set
   245  }
   246  
   247  // Peer retrieves the registered peer with the given id.
   248  func (ps *peerSet) Peer(id string) Peer {
   249  	ps.lock.RLock()
   250  	defer ps.lock.RUnlock()
   251  
   252  	return ps.peers[id]
   253  }
   254  
   255  // Len returns if the current number of peers in the set.
   256  func (ps *peerSet) Len() int {
   257  	ps.lock.RLock()
   258  	defer ps.lock.RUnlock()
   259  
   260  	return len(ps.peers)
   261  }
   262  
   263  // SnapLen returns if the current number of `snap` peers in the set.
   264  func (ps *peerSet) SnapLen() int {
   265  	ps.lock.RLock()
   266  	defer ps.lock.RUnlock()
   267  
   268  	return ps.snapPeers
   269  }
   270  
   271  // PeersWithoutBlock retrieves a list of peers that do not have a given block in
   272  // their set of known hashes.
   273  func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []Peer {
   274  	ps.lock.RLock()
   275  	defer ps.lock.RUnlock()
   276  
   277  	list := make([]Peer, 0, len(ps.peers))
   278  	for _, p := range ps.peers {
   279  		if !p.KnowsBlock(hash) {
   280  			list = append(list, p)
   281  		}
   282  	}
   283  	return list
   284  }
   285  
   286  func (ps *peerSet) typePeersWithoutBlock(hash common.Hash, nodetype common.ConnType) []Peer {
   287  	ps.lock.RLock()
   288  	defer ps.lock.RUnlock()
   289  
   290  	list := make([]Peer, 0, len(ps.peers))
   291  	for _, p := range ps.peers {
   292  		if p.ConnType() == nodetype && !p.KnowsBlock(hash) {
   293  			list = append(list, p)
   294  		}
   295  	}
   296  	return list
   297  }
   298  
   299  func (ps *peerSet) PeersWithoutBlockExceptCN(hash common.Hash) []Peer {
   300  	ps.lock.RLock()
   301  	defer ps.lock.RUnlock()
   302  
   303  	list := make([]Peer, 0, len(ps.peers))
   304  	for _, p := range ps.peers {
   305  		if p.ConnType() != common.CONSENSUSNODE && !p.KnowsBlock(hash) {
   306  			list = append(list, p)
   307  		}
   308  	}
   309  	return list
   310  }
   311  
   312  func (ps *peerSet) CNWithoutBlock(hash common.Hash) []Peer {
   313  	ps.lock.RLock()
   314  	defer ps.lock.RUnlock()
   315  
   316  	list := make([]Peer, 0, len(ps.cnpeers))
   317  	for _, p := range ps.cnpeers {
   318  		if !p.KnowsBlock(hash) {
   319  			list = append(list, p)
   320  		}
   321  	}
   322  	return list
   323  }
   324  
   325  func (ps *peerSet) PNWithoutBlock(hash common.Hash) []Peer {
   326  	ps.lock.RLock()
   327  	defer ps.lock.RUnlock()
   328  
   329  	list := make([]Peer, 0, len(ps.pnpeers))
   330  	for _, p := range ps.pnpeers {
   331  		if !p.KnowsBlock(hash) {
   332  			list = append(list, p)
   333  		}
   334  	}
   335  	return list
   336  }
   337  
   338  func (ps *peerSet) ENWithoutBlock(hash common.Hash) []Peer {
   339  	ps.lock.RLock()
   340  	defer ps.lock.RUnlock()
   341  
   342  	list := make([]Peer, 0, len(ps.enpeers))
   343  	for _, p := range ps.enpeers {
   344  		if !p.KnowsBlock(hash) {
   345  			list = append(list, p)
   346  		}
   347  	}
   348  	return list
   349  }
   350  
   351  func (ps *peerSet) typePeers(nodetype common.ConnType) []Peer {
   352  	ps.lock.RLock()
   353  	defer ps.lock.RUnlock()
   354  	list := make([]Peer, 0, len(ps.peers))
   355  	for _, p := range ps.peers {
   356  		if p.ConnType() == nodetype {
   357  			list = append(list, p)
   358  		}
   359  	}
   360  	return list
   361  }
   362  
   363  // PeersWithoutTx retrieves a list of peers that do not have a given transaction
   364  // in their set of known hashes.
   365  func (ps *peerSet) PeersWithoutTx(hash common.Hash) []Peer {
   366  	ps.lock.RLock()
   367  	defer ps.lock.RUnlock()
   368  
   369  	list := make([]Peer, 0, len(ps.peers))
   370  	for _, p := range ps.peers {
   371  		if !p.KnowsTx(hash) {
   372  			list = append(list, p)
   373  		}
   374  	}
   375  	return list
   376  }
   377  
   378  func (ps *peerSet) TypePeersWithoutTx(hash common.Hash, nodetype common.ConnType) []Peer {
   379  	ps.lock.RLock()
   380  	defer ps.lock.RUnlock()
   381  
   382  	list := make([]Peer, 0, len(ps.peers))
   383  	for _, p := range ps.peers {
   384  		if p.ConnType() == nodetype && !p.KnowsTx(hash) {
   385  			list = append(list, p)
   386  		}
   387  	}
   388  	return list
   389  }
   390  
   391  func (ps *peerSet) CNWithoutTx(hash common.Hash) []Peer {
   392  	ps.lock.RLock()
   393  	defer ps.lock.RUnlock()
   394  
   395  	list := make([]Peer, 0, len(ps.cnpeers))
   396  	for _, p := range ps.cnpeers {
   397  		if !p.KnowsTx(hash) {
   398  			list = append(list, p)
   399  		}
   400  	}
   401  	return list
   402  }
   403  
   404  // BestPeer retrieves the known peer with the currently highest total blockscore.
   405  func (ps *peerSet) BestPeer() Peer {
   406  	ps.lock.RLock()
   407  	defer ps.lock.RUnlock()
   408  
   409  	var (
   410  		bestPeer       Peer
   411  		bestBlockScore *big.Int
   412  	)
   413  	for _, p := range ps.peers {
   414  		if _, currBlockScore := p.Head(); bestPeer == nil || currBlockScore.Cmp(bestBlockScore) > 0 {
   415  			bestPeer, bestBlockScore = p, currBlockScore
   416  		}
   417  	}
   418  	return bestPeer
   419  }
   420  
   421  // RegisterValidator registers a validator.
   422  func (ps *peerSet) RegisterValidator(connType common.ConnType, validator p2p.PeerTypeValidator) {
   423  	ps.validator[connType] = validator
   424  }
   425  
   426  // Close disconnects all peers.
   427  // No new peers can be registered after Close has returned.
   428  func (ps *peerSet) Close() {
   429  	ps.lock.Lock()
   430  	defer ps.lock.Unlock()
   431  
   432  	for _, p := range ps.peers {
   433  		p.DisconnectP2PPeer(p2p.DiscQuitting)
   434  	}
   435  	ps.closed = true
   436  }
   437  
   438  // samplePeersToSendBlock samples peers from peers without block.
   439  // It uses different sampling policy for different node type.
   440  func (peers *peerSet) SamplePeersToSendBlock(block *types.Block, nodeType common.ConnType) []Peer {
   441  	var peersWithoutBlock []Peer
   442  	hash := block.Hash()
   443  
   444  	switch nodeType {
   445  	case common.CONSENSUSNODE:
   446  		// If currNode is CN, sends block to sampled peers from (CN + PN), not to EN.
   447  		cnsWithoutBlock := peers.CNWithoutBlock(hash)
   448  		sampledCNsWithoutBlock := samplingPeers(cnsWithoutBlock, sampleSize(cnsWithoutBlock))
   449  
   450  		// CN always broadcasts a block to its PN peers, unless the number of PN peers exceeds the limit.
   451  		pnsWithoutBlock := peers.PNWithoutBlock(hash)
   452  		if len(pnsWithoutBlock) > blockReceivingPNLimit {
   453  			pnsWithoutBlock = samplingPeers(pnsWithoutBlock, blockReceivingPNLimit)
   454  		}
   455  
   456  		logger.Trace("Propagated block", "hash", hash,
   457  			"CN recipients", len(sampledCNsWithoutBlock), "PN recipients", len(pnsWithoutBlock), "duration", common.PrettyDuration(time.Since(block.ReceivedAt)))
   458  
   459  		return append(cnsWithoutBlock, pnsWithoutBlock...)
   460  	case common.PROXYNODE:
   461  		// If currNode is PN, sends block to sampled peers from (PN + EN), not to CN.
   462  		peersWithoutBlock = peers.PeersWithoutBlockExceptCN(hash)
   463  
   464  	case common.ENDPOINTNODE:
   465  		// If currNode is EN, sends block to sampled EN peers, not to EN nor CN.
   466  		peersWithoutBlock = peers.ENWithoutBlock(hash)
   467  
   468  	default:
   469  		logger.Error("Undefined nodeType of protocolManager! nodeType: %v", nodeType)
   470  		return []Peer{}
   471  	}
   472  
   473  	sampledPeersWithoutBlock := samplingPeers(peersWithoutBlock, sampleSize(peersWithoutBlock))
   474  	logger.Trace("Propagated block", "hash", hash,
   475  		"recipients", len(sampledPeersWithoutBlock), "duration", common.PrettyDuration(time.Since(block.ReceivedAt)))
   476  
   477  	return sampledPeersWithoutBlock
   478  }
   479  
   480  func (peers *peerSet) SampleResendPeersByType(nodeType common.ConnType) []Peer {
   481  	// TODO-Klaytn Need to tune pickSize. Currently use 2 for availability and efficiency.
   482  	var sampledPeers []Peer
   483  	switch nodeType {
   484  	case common.ENDPOINTNODE:
   485  		sampledPeers = peers.typePeers(common.CONSENSUSNODE)
   486  		if len(sampledPeers) < 2 {
   487  			sampledPeers = append(sampledPeers, samplingPeers(peers.typePeers(common.PROXYNODE), 2-len(sampledPeers))...)
   488  		}
   489  		if len(sampledPeers) < 2 {
   490  			sampledPeers = append(sampledPeers, samplingPeers(peers.typePeers(common.ENDPOINTNODE), 2-len(sampledPeers))...)
   491  		}
   492  		sampledPeers = samplingPeers(sampledPeers, 2)
   493  	case common.PROXYNODE:
   494  		sampledPeers = peers.typePeers(common.CONSENSUSNODE)
   495  		if len(sampledPeers) == 0 {
   496  			sampledPeers = peers.typePeers(common.PROXYNODE)
   497  		}
   498  		sampledPeers = samplingPeers(sampledPeers, 2)
   499  	default:
   500  		logger.Warn("Not supported nodeType", "nodeType", nodeType)
   501  		return nil
   502  	}
   503  	return sampledPeers
   504  }
   505  
   506  func (peers *peerSet) UpdateTypePeersWithoutTxs(tx *types.Transaction, nodeType common.ConnType, peersWithoutTxsMap map[Peer]types.Transactions) {
   507  	typePeers := peers.TypePeersWithoutTx(tx.Hash(), nodeType)
   508  	for _, peer := range typePeers {
   509  		peersWithoutTxsMap[peer] = append(peersWithoutTxsMap[peer], tx)
   510  	}
   511  	logger.Trace("Broadcast transaction", "hash", tx.Hash(), "recipients", len(typePeers))
   512  }
   513  
   514  // RegisterSnapExtension unblocks an already connected `klay` peer waiting for its
   515  // `snap` extension, or if no such peer exists, tracks the extension for the time
   516  // being until the `eth` main protocol starts looking for it.
   517  func (peers *peerSet) RegisterSnapExtension(peer *snap.Peer) error {
   518  	// Reject the peer if it advertises `snap` without `klay` as `snap` is only a
   519  	// satellite protocol meaningful with the chain selection of `klay`
   520  	if !peer.RunningCap(backend.IstanbulProtocol.Name, backend.IstanbulProtocol.Versions) {
   521  		return errSnapWithoutIstanbul
   522  	}
   523  	// Ensure nobody can double connect
   524  	peers.lock.Lock()
   525  	defer peers.lock.Unlock()
   526  
   527  	id := peer.ID()
   528  	if _, ok := peers.peers[id]; ok {
   529  		return errPeerAlreadyRegistered // avoid connections with the same id as existing ones
   530  	}
   531  	if _, ok := peers.snapPend[id]; ok {
   532  		return errPeerAlreadyRegistered // avoid connections with the same id as pending ones
   533  	}
   534  	// Inject the peer into an `eth` counterpart is available, otherwise save for later
   535  	if wait, ok := peers.snapWait[id]; ok {
   536  		delete(peers.snapWait, id)
   537  		wait <- peer
   538  		return nil
   539  	}
   540  	peers.snapPend[id] = peer
   541  	return nil
   542  }
   543  
   544  // WaitSnapExtension blocks until all satellite protocols are connected and tracked
   545  // by the peerset.
   546  func (ps *peerSet) WaitSnapExtension(peer Peer) (*snap.Peer, error) {
   547  	// If the peer does not support a compatible `snap`, don't wait
   548  	if !peer.RunningCap(snap.ProtocolName, snap.ProtocolVersions) {
   549  		return nil, nil
   550  	}
   551  	// Ensure nobody can double connect
   552  	wait := make(chan *snap.Peer)
   553  	snap, err := ps.waitSnapExtension(peer, wait)
   554  	if err != nil {
   555  		return nil, err
   556  	}
   557  	if snap != nil {
   558  		return snap, nil
   559  	}
   560  
   561  	return <-wait, nil
   562  }
   563  
   564  func (ps *peerSet) waitSnapExtension(peer Peer, wait chan *snap.Peer) (*snap.Peer, error) {
   565  	ps.lock.Lock()
   566  	defer ps.lock.Unlock()
   567  
   568  	id := peer.GetID()
   569  	if _, ok := ps.peers[id]; ok {
   570  		return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones
   571  	}
   572  	if _, ok := ps.snapWait[id]; ok {
   573  		return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones
   574  	}
   575  	// If `snap` already connected, retrieve the peer from the pending set
   576  	if snap, ok := ps.snapPend[id]; ok {
   577  		delete(ps.snapPend, id)
   578  
   579  		return snap, nil
   580  	}
   581  	// Otherwise wait for `snap` to connect concurrently
   582  	ps.snapWait[id] = wait
   583  	return nil, nil
   584  }