github.com/codingfuture/orig-energi3@v0.8.4/swarm/network/discovery.go (about)

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