github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/network/discovery.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package network
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"sync"
    23  
    24  	"github.com/ethereum/go-ethereum/swarm/pot"
    25  )
    26  
    27  // discovery bzz extension for requesting and relaying node address records
    28  
    29  var sortPeers = noSortPeers
    30  
    31  // Peer wraps BzzPeer and embeds Kademlia overlay connectivity driver
    32  type Peer struct {
    33  	*BzzPeer
    34  	kad       *Kademlia
    35  	sentPeers bool            // whether we already sent peer closer to this address
    36  	mtx       sync.RWMutex    //
    37  	peers     map[string]bool // tracks node records sent to the peer
    38  	depth     uint8           // the proximity order advertised by remote as depth of saturation
    39  }
    40  
    41  // NewPeer constructs a discovery peer
    42  func NewPeer(p *BzzPeer, kad *Kademlia) *Peer {
    43  	d := &Peer{
    44  		kad:     kad,
    45  		BzzPeer: p,
    46  		peers:   make(map[string]bool),
    47  	}
    48  	// record remote as seen so we never send a peer its own record
    49  	d.seen(p.BzzAddr)
    50  	return d
    51  }
    52  
    53  // HandleMsg is the message handler that delegates incoming messages
    54  func (d *Peer) HandleMsg(ctx context.Context, msg interface{}) error {
    55  	switch msg := msg.(type) {
    56  
    57  	case *peersMsg:
    58  		return d.handlePeersMsg(msg)
    59  
    60  	case *subPeersMsg:
    61  		return d.handleSubPeersMsg(msg)
    62  
    63  	default:
    64  		return fmt.Errorf("unknown message type: %T", msg)
    65  	}
    66  }
    67  
    68  // NotifyDepth sends a message to all connections if depth of saturation is changed
    69  func NotifyDepth(depth uint8, kad *Kademlia) {
    70  	f := func(val *Peer, po int) bool {
    71  		val.NotifyDepth(depth)
    72  		return true
    73  	}
    74  	kad.EachConn(nil, 255, f)
    75  }
    76  
    77  // NotifyPeer informs all peers about a newly added node
    78  func NotifyPeer(p *BzzAddr, k *Kademlia) {
    79  	f := func(val *Peer, po int) bool {
    80  		val.NotifyPeer(p, uint8(po))
    81  		return true
    82  	}
    83  	k.EachConn(p.Address(), 255, f)
    84  }
    85  
    86  // NotifyPeer notifies the remote node (recipient) about a peer if
    87  // the peer's PO is within the recipients advertised depth
    88  // OR the peer is closer to the recipient than self
    89  // unless already notified during the connection session
    90  func (d *Peer) NotifyPeer(a *BzzAddr, po uint8) {
    91  	// immediately return
    92  	if (po < d.getDepth() && pot.ProxCmp(d.kad.BaseAddr(), d, a) != 1) || d.seen(a) {
    93  		return
    94  	}
    95  	resp := &peersMsg{
    96  		Peers: []*BzzAddr{a},
    97  	}
    98  	go d.Send(context.TODO(), resp)
    99  }
   100  
   101  // NotifyDepth sends a subPeers Msg to the receiver notifying them about
   102  // a change in the depth of saturation
   103  func (d *Peer) NotifyDepth(po uint8) {
   104  	go d.Send(context.TODO(), &subPeersMsg{Depth: po})
   105  }
   106  
   107  /*
   108  peersMsg is the message to pass peer information
   109  It is always a response to a peersRequestMsg
   110  
   111  The encoding of a peer address is identical the devp2p base protocol peers
   112  messages: [IP, Port, NodeID],
   113  Note that a node's FileStore address is not the NodeID but the hash of the NodeID.
   114  
   115  TODO:
   116  To mitigate against spurious peers messages, requests should be remembered
   117  and correctness of responses should be checked
   118  
   119  If the proxBin of peers in the response is incorrect the sender should be
   120  disconnected
   121  */
   122  
   123  // peersMsg encapsulates an array of peer addresses
   124  // used for communicating about known peers
   125  // relevant for bootstrapping connectivity and updating peersets
   126  type peersMsg struct {
   127  	Peers []*BzzAddr
   128  }
   129  
   130  // String pretty prints a peersMsg
   131  func (msg peersMsg) String() string {
   132  	return fmt.Sprintf("%T: %v", msg, msg.Peers)
   133  }
   134  
   135  // handlePeersMsg called by the protocol when receiving peerset (for target address)
   136  // list of nodes ([]PeerAddr in peersMsg) is added to the overlay db using the
   137  // Register interface method
   138  func (d *Peer) handlePeersMsg(msg *peersMsg) error {
   139  	// register all addresses
   140  	if len(msg.Peers) == 0 {
   141  		return nil
   142  	}
   143  
   144  	for _, a := range msg.Peers {
   145  		d.seen(a)
   146  		NotifyPeer(a, d.kad)
   147  	}
   148  	return d.kad.Register(msg.Peers...)
   149  }
   150  
   151  // subPeers msg is communicating the depth of the overlay table of a peer
   152  type subPeersMsg struct {
   153  	Depth uint8
   154  }
   155  
   156  // String returns the pretty printer
   157  func (msg subPeersMsg) String() string {
   158  	return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth)
   159  }
   160  
   161  // handleSubPeersMsg handles incoming subPeersMsg
   162  // this message represents the saturation depth of the remote peer
   163  // saturation depth is the radius within which the peer subscribes to peers
   164  // the first time this is received we send peer info on all
   165  // our connected peers that fall within peers saturation depth
   166  // otherwise this depth is just recorded on the peer, so that
   167  // subsequent new connections are sent iff they fall within the radius
   168  func (d *Peer) handleSubPeersMsg(msg *subPeersMsg) error {
   169  	d.setDepth(msg.Depth)
   170  	// only send peers after the initial subPeersMsg
   171  	if !d.sentPeers {
   172  		var peers []*BzzAddr
   173  		// iterate connection in ascending order of disctance from the remote address
   174  		d.kad.EachConn(d.Over(), 255, func(p *Peer, po int) bool {
   175  			// terminate if we are beyond the radius
   176  			if uint8(po) < msg.Depth {
   177  				return false
   178  			}
   179  			if !d.seen(p.BzzAddr) { // here just records the peer sent
   180  				peers = append(peers, p.BzzAddr)
   181  			}
   182  			return true
   183  		})
   184  		// if useful  peers are found, send them over
   185  		if len(peers) > 0 {
   186  			go d.Send(context.TODO(), &peersMsg{Peers: sortPeers(peers)})
   187  		}
   188  	}
   189  	d.sentPeers = true
   190  	return nil
   191  }
   192  
   193  // seen takes a peer address and checks if it was sent to a peer already
   194  // if not, marks the peer as sent
   195  func (d *Peer) seen(p *BzzAddr) bool {
   196  	d.mtx.Lock()
   197  	defer d.mtx.Unlock()
   198  	k := string(p.Address())
   199  	if d.peers[k] {
   200  		return true
   201  	}
   202  	d.peers[k] = true
   203  	return false
   204  }
   205  
   206  func (d *Peer) getDepth() uint8 {
   207  	d.mtx.RLock()
   208  	defer d.mtx.RUnlock()
   209  	return d.depth
   210  }
   211  
   212  func (d *Peer) setDepth(depth uint8) {
   213  	d.mtx.Lock()
   214  	defer d.mtx.Unlock()
   215  	d.depth = depth
   216  }
   217  
   218  func noSortPeers(peers []*BzzAddr) []*BzzAddr {
   219  	return peers
   220  }