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