github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/swarm/network/discovery.go (about)

     1  // Copyright 2016 The go-athereum Authors
     2  // This file is part of the go-athereum library.
     3  //
     4  // The go-athereum 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-athereum 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-athereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package network
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  
    23  	"github.com/athereum/go-athereum/swarm/pot"
    24  )
    25  
    26  // discovery bzz extension for requesting and relaying node address records
    27  
    28  // discPeer wraps BzzPeer and embeds an Overlay connectivity driver
    29  type discPeer struct {
    30  	*BzzPeer
    31  	overlay   Overlay
    32  	sentPeers bool // whather we already sent peer closer to this address
    33  	mtx       sync.RWMutex
    34  	peers     map[string]bool // tracks node records sent to the peer
    35  	depth     uint8           // the proximity order advertised by remote as depth of saturation
    36  }
    37  
    38  // NewDiscovery constructs a discovery peer
    39  func newDiscovery(p *BzzPeer, o Overlay) *discPeer {
    40  	d := &discPeer{
    41  		overlay: o,
    42  		BzzPeer: p,
    43  		peers:   make(map[string]bool),
    44  	}
    45  	// record remote as seen so we never send a peer its own record
    46  	d.seen(d)
    47  	return d
    48  }
    49  
    50  // HandleMsg is the message handler that delegates incoming messages
    51  func (d *discPeer) HandleMsg(msg interface{}) error {
    52  	switch msg := msg.(type) {
    53  
    54  	case *peersMsg:
    55  		return d.handlePeersMsg(msg)
    56  
    57  	case *subPeersMsg:
    58  		return d.handleSubPeersMsg(msg)
    59  
    60  	default:
    61  		return fmt.Errorf("unknown message type: %T", msg)
    62  	}
    63  }
    64  
    65  // NotifyDepth sends a message to all connections if depth of saturation is changed
    66  func NotifyDepth(depth uint8, h Overlay) {
    67  	f := func(val OverlayConn, po int, _ bool) bool {
    68  		dp, ok := val.(*discPeer)
    69  		if ok {
    70  			dp.NotifyDepth(depth)
    71  		}
    72  		return true
    73  	}
    74  	h.EachConn(nil, 255, f)
    75  }
    76  
    77  // NotifyPeer informs all peers about a newly added node
    78  func NotifyPeer(p OverlayAddr, k Overlay) {
    79  	f := func(val OverlayConn, po int, _ bool) bool {
    80  		dp, ok := val.(*discPeer)
    81  		if ok {
    82  			dp.NotifyPeer(p, uint8(po))
    83  		}
    84  		return true
    85  	}
    86  	k.EachConn(p.Address(), 255, f)
    87  }
    88  
    89  // NotifyPeer notifies the remote node (recipient) about a peer if
    90  // the peer's PO is within the recipients advertised depth
    91  // OR the peer is closer to the recipient than self
    92  // unless already notified during the connection session
    93  func (d *discPeer) NotifyPeer(a OverlayAddr, po uint8) {
    94  	// immediately return
    95  	if (po < d.getDepth() && pot.ProxCmp(d.localAddr, d, a) != 1) || d.seen(a) {
    96  		return
    97  	}
    98  	// log.Trace(fmt.Sprintf("%08x peer %08x notified of peer %08x", d.localAddr.Over()[:4], d.Address()[:4], a.Address()[:4]))
    99  	resp := &peersMsg{
   100  		Peers: []*BzzAddr{ToAddr(a)},
   101  	}
   102  	go d.Send(resp)
   103  }
   104  
   105  // NotifyDepth sends a subPeers Msg to the receiver notifying them about
   106  // a change in the depth of saturation
   107  func (d *discPeer) NotifyDepth(po uint8) {
   108  	// log.Trace(fmt.Sprintf("%08x peer %08x notified of new depth %v", d.localAddr.Over()[:4], d.Address()[:4], po))
   109  	go d.Send(&subPeersMsg{Depth: po})
   110  }
   111  
   112  /*
   113  peersMsg is the message to pass peer information
   114  It is always a response to a peersRequestMsg
   115  
   116  The encoding of a peer address is identical the devp2p base protocol peers
   117  messages: [IP, Port, NodeID],
   118  Note that a node's FileStore address is not the NodeID but the hash of the NodeID.
   119  
   120  TODO:
   121  To mitigate against spurious peers messages, requests should be remembered
   122  and correctness of responses should be checked
   123  
   124  If the proxBin of peers in the response is incorrect the sender should be
   125  disconnected
   126  */
   127  
   128  // peersMsg encapsulates an array of peer addresses
   129  // used for communicating about known peers
   130  // relevant for bootstrapping connectivity and updating peersets
   131  type peersMsg struct {
   132  	Peers []*BzzAddr
   133  }
   134  
   135  // String pretty prints a peersMsg
   136  func (msg peersMsg) String() string {
   137  	return fmt.Sprintf("%T: %v", msg, msg.Peers)
   138  }
   139  
   140  // handlePeersMsg called by the protocol when receiving peerset (for target address)
   141  // list of nodes ([]PeerAddr in peersMsg) is added to the overlay db using the
   142  // Register interface method
   143  func (d *discPeer) handlePeersMsg(msg *peersMsg) error {
   144  	// register all addresses
   145  	if len(msg.Peers) == 0 {
   146  		return nil
   147  	}
   148  
   149  	for _, a := range msg.Peers {
   150  		d.seen(a)
   151  		NotifyPeer(a, d.overlay)
   152  	}
   153  	return d.overlay.Register(toOverlayAddrs(msg.Peers...))
   154  }
   155  
   156  // subPeers msg is communicating the depth/sharpness/focus of the overlay table of a peer
   157  type subPeersMsg struct {
   158  	Depth uint8
   159  }
   160  
   161  // String returns the pretty printer
   162  func (msg subPeersMsg) String() string {
   163  	return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth)
   164  }
   165  
   166  func (d *discPeer) handleSubPeersMsg(msg *subPeersMsg) error {
   167  	if !d.sentPeers {
   168  		d.setDepth(msg.Depth)
   169  		var peers []*BzzAddr
   170  		d.overlay.EachConn(d.Over(), 255, func(p OverlayConn, po int, isproxbin bool) bool {
   171  			if pob, _ := pof(d, d.localAddr, 0); pob > po {
   172  				return false
   173  			}
   174  			if !d.seen(p) {
   175  				peers = append(peers, ToAddr(p.Off()))
   176  			}
   177  			return true
   178  		})
   179  		if len(peers) > 0 {
   180  			// log.Debug(fmt.Sprintf("%08x: %v peers sent to %v", d.overlay.BaseAddr(), len(peers), d))
   181  			go d.Send(&peersMsg{Peers: peers})
   182  		}
   183  	}
   184  	d.sentPeers = true
   185  	return nil
   186  }
   187  
   188  // seen takes an Overlay peer and checks if it was sent to a peer already
   189  // if not, marks the peer as sent
   190  func (d *discPeer) seen(p OverlayPeer) bool {
   191  	d.mtx.Lock()
   192  	defer d.mtx.Unlock()
   193  	k := string(p.Address())
   194  	if d.peers[k] {
   195  		return true
   196  	}
   197  	d.peers[k] = true
   198  	return false
   199  }
   200  
   201  func (d *discPeer) getDepth() uint8 {
   202  	d.mtx.RLock()
   203  	defer d.mtx.RUnlock()
   204  	return d.depth
   205  }
   206  func (d *discPeer) setDepth(depth uint8) {
   207  	d.mtx.Lock()
   208  	defer d.mtx.Unlock()
   209  	d.depth = depth
   210  }