github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/discovery.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:43</date>
    10  //</624450113510576128>
    11  
    12  
    13  package network
    14  
    15  import (
    16  	"context"
    17  	"fmt"
    18  	"sync"
    19  
    20  	"github.com/ethereum/go-ethereum/swarm/pot"
    21  )
    22  
    23  //用于请求和中继节点地址记录的Discovery BZZ扩展
    24  
    25  //Peer包装BZZPeer并嵌入Kademlia覆盖连接驱动程序
    26  type Peer struct {
    27  	*BzzPeer
    28  	kad       *Kademlia
    29  sentPeers bool            //是否已将对等机发送到该地址附近
    30  mtx       sync.RWMutex    //
    31  peers     map[string]bool //跟踪发送到对等机的节点记录
    32  depth     uint8           //远程通知的接近顺序为饱和深度
    33  }
    34  
    35  //newpeer构造发现对等
    36  func NewPeer(p *BzzPeer, kad *Kademlia) *Peer {
    37  	d := &Peer{
    38  		kad:     kad,
    39  		BzzPeer: p,
    40  		peers:   make(map[string]bool),
    41  	}
    42  //记录所见的远程信息,因此我们从不向对等端发送自己的记录。
    43  	d.seen(p.BzzAddr)
    44  	return d
    45  }
    46  
    47  //handlemsg是委托传入消息的消息处理程序
    48  func (d *Peer) HandleMsg(ctx context.Context, msg interface{}) error {
    49  	switch msg := msg.(type) {
    50  
    51  	case *peersMsg:
    52  		return d.handlePeersMsg(msg)
    53  
    54  	case *subPeersMsg:
    55  		return d.handleSubPeersMsg(msg)
    56  
    57  	default:
    58  		return fmt.Errorf("unknown message type: %T", msg)
    59  	}
    60  }
    61  
    62  //如果饱和深度更改,notifydepth将向所有连接发送消息
    63  func NotifyDepth(depth uint8, kad *Kademlia) {
    64  	f := func(val *Peer, po int) bool {
    65  		val.NotifyDepth(depth)
    66  		return true
    67  	}
    68  	kad.EachConn(nil, 255, f)
    69  }
    70  
    71  //notifypeer通知所有对等方新添加的节点
    72  func NotifyPeer(p *BzzAddr, k *Kademlia) {
    73  	f := func(val *Peer, po int) bool {
    74  		val.NotifyPeer(p, uint8(po))
    75  		return true
    76  	}
    77  	k.EachConn(p.Address(), 255, f)
    78  }
    79  
    80  //如果出现以下情况,notifypeer将通知远程节点(收件人)有关对等机的信息:
    81  //对等方的采购订单在收件人的广告深度内
    82  //或者对方比自己更接近对方
    83  //除非在连接会话期间已通知
    84  func (d *Peer) NotifyPeer(a *BzzAddr, po uint8) {
    85  //立即返回
    86  	if (po < d.getDepth() && pot.ProxCmp(d.kad.BaseAddr(), d, a) != 1) || d.seen(a) {
    87  		return
    88  	}
    89  	resp := &peersMsg{
    90  		Peers: []*BzzAddr{a},
    91  	}
    92  	go d.Send(context.TODO(), resp)
    93  }
    94  
    95  //notifydepth向接收者发送一个子程序msg,通知他们
    96  //饱和深度的变化
    97  func (d *Peer) NotifyDepth(po uint8) {
    98  	go d.Send(context.TODO(), &subPeersMsg{Depth: po})
    99  }
   100  
   101  /*
   102  peersmsg是传递对等信息的消息
   103  它始终是对peersrequestmsg的响应
   104  
   105  对等地址的编码与DEVP2P基本协议对等机相同。
   106  消息:[IP,端口,节点ID],
   107  请注意,节点的文件存储地址不是nodeid,而是nodeid的哈希。
   108  
   109  TODO:
   110  为了减轻伪对等端消息的影响,请求应该被记住。
   111  应检查响应的正确性。
   112  
   113  如果响应中对等端的proxybin不正确,则发送方应
   114  断开的
   115  **/
   116  
   117  
   118  //peersmsg封装了一组对等地址
   119  //用于交流已知的对等点
   120  //与引导连接和更新对等集相关
   121  type peersMsg struct {
   122  	Peers []*BzzAddr
   123  }
   124  
   125  //字符串漂亮打印一个peersmsg
   126  func (msg peersMsg) String() string {
   127  	return fmt.Sprintf("%T: %v", msg, msg.Peers)
   128  }
   129  
   130  //接收对等集时协议调用的handlepeersmsg(用于目标地址)
   131  //节点列表([]peeraddr in peerasmsg)使用
   132  //寄存器接口方法
   133  func (d *Peer) handlePeersMsg(msg *peersMsg) error {
   134  //注册所有地址
   135  	if len(msg.Peers) == 0 {
   136  		return nil
   137  	}
   138  
   139  	for _, a := range msg.Peers {
   140  		d.seen(a)
   141  		NotifyPeer(a, d.kad)
   142  	}
   143  	return d.kad.Register(msg.Peers...)
   144  }
   145  
   146  //子进程消息正在通信对等进程覆盖表的深度。
   147  type subPeersMsg struct {
   148  	Depth uint8
   149  }
   150  
   151  //字符串返回漂亮的打印机
   152  func (msg subPeersMsg) String() string {
   153  	return fmt.Sprintf("%T: request peers > PO%02d. ", msg, msg.Depth)
   154  }
   155  
   156  func (d *Peer) handleSubPeersMsg(msg *subPeersMsg) error {
   157  	if !d.sentPeers {
   158  		d.setDepth(msg.Depth)
   159  		var peers []*BzzAddr
   160  		d.kad.EachConn(d.Over(), 255, func(p *Peer, po int) bool {
   161  			if pob, _ := Pof(d, d.kad.BaseAddr(), 0); pob > po {
   162  				return false
   163  			}
   164  			if !d.seen(p.BzzAddr) {
   165  				peers = append(peers, p.BzzAddr)
   166  			}
   167  			return true
   168  		})
   169  		if len(peers) > 0 {
   170  			go d.Send(context.TODO(), &peersMsg{Peers: peers})
   171  		}
   172  	}
   173  	d.sentPeers = true
   174  	return nil
   175  }
   176  
   177  //seen获取对等地址并检查是否已将其发送到对等。
   178  //如果没有,则将对等机标记为已发送
   179  func (d *Peer) seen(p *BzzAddr) bool {
   180  	d.mtx.Lock()
   181  	defer d.mtx.Unlock()
   182  	k := string(p.Address())
   183  	if d.peers[k] {
   184  		return true
   185  	}
   186  	d.peers[k] = true
   187  	return false
   188  }
   189  
   190  func (d *Peer) getDepth() uint8 {
   191  	d.mtx.RLock()
   192  	defer d.mtx.RUnlock()
   193  	return d.depth
   194  }
   195  
   196  func (d *Peer) setDepth(depth uint8) {
   197  	d.mtx.Lock()
   198  	defer d.mtx.Unlock()
   199  	d.depth = depth
   200  }
   201