github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/peer.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:41</date>
    10  //</624450105574952960>
    11  
    12  
    13  package p2p
    14  
    15  import (
    16  	"errors"
    17  	"fmt"
    18  	"io"
    19  	"net"
    20  	"sort"
    21  	"sync"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/common/mclock"
    25  	"github.com/ethereum/go-ethereum/event"
    26  	"github.com/ethereum/go-ethereum/log"
    27  	"github.com/ethereum/go-ethereum/p2p/enode"
    28  	"github.com/ethereum/go-ethereum/p2p/enr"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  var (
    33  	ErrShuttingDown = errors.New("shutting down")
    34  )
    35  
    36  const (
    37  	baseProtocolVersion    = 5
    38  	baseProtocolLength     = uint64(16)
    39  	baseProtocolMaxMsgSize = 2 * 1024
    40  
    41  	snappyProtocolVersion = 5
    42  
    43  	pingInterval = 15 * time.Second
    44  )
    45  
    46  const (
    47  //DEVP2P消息代码
    48  	handshakeMsg = 0x00
    49  	discMsg      = 0x01
    50  	pingMsg      = 0x02
    51  	pongMsg      = 0x03
    52  )
    53  
    54  //协议握手是协议握手的RLP结构。
    55  type protoHandshake struct {
    56  	Version    uint64
    57  	Name       string
    58  	Caps       []Cap
    59  	ListenPort uint64
    60  ID         []byte //secp256k1公钥
    61  
    62  //忽略其他字段(为了向前兼容)。
    63  	Rest []rlp.RawValue `rlp:"tail"`
    64  }
    65  
    66  //PeerEventType是P2P服务器发出的对等事件类型。
    67  type PeerEventType string
    68  
    69  const (
    70  //PeerEventTypeAdd是添加对等方时发出的事件类型
    71  //到P2P服务器
    72  	PeerEventTypeAdd PeerEventType = "add"
    73  
    74  //PeerEventTypeDrop是当对等机
    75  //从p2p服务器上删除
    76  	PeerEventTypeDrop PeerEventType = "drop"
    77  
    78  //PeerEventTypeMSGSEND是在
    79  //消息已成功发送到对等方
    80  	PeerEventTypeMsgSend PeerEventType = "msgsend"
    81  
    82  //PeerEventTypeMsgrecv是在
    83  //从对等端接收消息
    84  	PeerEventTypeMsgRecv PeerEventType = "msgrecv"
    85  )
    86  
    87  //PeerEvent是在添加或删除对等方时发出的事件
    88  //一个p2p服务器,或者当通过对等连接发送或接收消息时
    89  type PeerEvent struct {
    90  	Type     PeerEventType `json:"type"`
    91  	Peer     enode.ID      `json:"peer"`
    92  	Error    string        `json:"error,omitempty"`
    93  	Protocol string        `json:"protocol,omitempty"`
    94  	MsgCode  *uint64       `json:"msg_code,omitempty"`
    95  	MsgSize  *uint32       `json:"msg_size,omitempty"`
    96  }
    97  
    98  //对等表示已连接的远程节点。
    99  type Peer struct {
   100  	rw      *conn
   101  	running map[string]*protoRW
   102  	log     log.Logger
   103  	created mclock.AbsTime
   104  
   105  	wg       sync.WaitGroup
   106  	protoErr chan error
   107  	closed   chan struct{}
   108  	disc     chan DiscReason
   109  
   110  //事件接收消息发送/接收事件(如果设置)
   111  	events *event.Feed
   112  }
   113  
   114  //newpeer返回用于测试目的的对等机。
   115  func NewPeer(id enode.ID, name string, caps []Cap) *Peer {
   116  	pipe, _ := net.Pipe()
   117  	node := enode.SignNull(new(enr.Record), id)
   118  	conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name}
   119  	peer := newPeer(conn, nil)
   120  close(peer.closed) //确保断开连接不会阻塞
   121  	return peer
   122  }
   123  
   124  //ID返回节点的公钥。
   125  func (p *Peer) ID() enode.ID {
   126  	return p.rw.node.ID()
   127  }
   128  
   129  //node返回对等方的节点描述符。
   130  func (p *Peer) Node() *enode.Node {
   131  	return p.rw.node
   132  }
   133  
   134  //name返回远程节点公布的节点名。
   135  func (p *Peer) Name() string {
   136  	return p.rw.name
   137  }
   138  
   139  //caps返回远程对等机的功能(支持的子协议)。
   140  func (p *Peer) Caps() []Cap {
   141  //托多:也许还回副本
   142  	return p.rw.caps
   143  }
   144  
   145  //remoteaddr返回网络连接的远程地址。
   146  func (p *Peer) RemoteAddr() net.Addr {
   147  	return p.rw.fd.RemoteAddr()
   148  }
   149  
   150  //localaddr返回网络连接的本地地址。
   151  func (p *Peer) LocalAddr() net.Addr {
   152  	return p.rw.fd.LocalAddr()
   153  }
   154  
   155  //disconnect以给定的原因终止对等连接。
   156  //它会立即返回,并且不会等待连接关闭。
   157  func (p *Peer) Disconnect(reason DiscReason) {
   158  	select {
   159  	case p.disc <- reason:
   160  	case <-p.closed:
   161  	}
   162  }
   163  
   164  //字符串实现fmt.stringer。
   165  func (p *Peer) String() string {
   166  	id := p.ID()
   167  	return fmt.Sprintf("Peer %x %v", id[:8], p.RemoteAddr())
   168  }
   169  
   170  //如果对等端是入站连接,则inbound返回true
   171  func (p *Peer) Inbound() bool {
   172  	return p.rw.is(inboundConn)
   173  }
   174  
   175  func newPeer(conn *conn, protocols []Protocol) *Peer {
   176  	protomap := matchProtocols(protocols, conn.caps, conn)
   177  	p := &Peer{
   178  		rw:       conn,
   179  		running:  protomap,
   180  		created:  mclock.Now(),
   181  		disc:     make(chan DiscReason),
   182  protoErr: make(chan error, len(protomap)+1), //协议+PingLoop
   183  		closed:   make(chan struct{}),
   184  		log:      log.New("id", conn.node.ID(), "conn", conn.flags),
   185  	}
   186  	return p
   187  }
   188  
   189  func (p *Peer) Log() log.Logger {
   190  	return p.log
   191  }
   192  
   193  func (p *Peer) run() (remoteRequested bool, err error) {
   194  	var (
   195  		writeStart = make(chan struct{}, 1)
   196  		writeErr   = make(chan error, 1)
   197  		readErr    = make(chan error, 1)
   198  reason     DiscReason //发送给对等方
   199  	)
   200  	p.wg.Add(2)
   201  	go p.readLoop(readErr)
   202  	go p.pingLoop()
   203  
   204  //启动所有协议处理程序。
   205  	writeStart <- struct{}{}
   206  	p.startProtocols(writeStart, writeErr)
   207  
   208  //等待错误或断开连接。
   209  loop:
   210  	for {
   211  		select {
   212  		case err = <-writeErr:
   213  //已完成写入。允许在以下情况下开始下一次写入
   214  //没有错误。
   215  			if err != nil {
   216  				reason = DiscNetworkError
   217  				break loop
   218  			}
   219  			writeStart <- struct{}{}
   220  		case err = <-readErr:
   221  			if r, ok := err.(DiscReason); ok {
   222  				remoteRequested = true
   223  				reason = r
   224  			} else {
   225  				reason = DiscNetworkError
   226  			}
   227  			break loop
   228  		case err = <-p.protoErr:
   229  			reason = discReasonForError(err)
   230  			break loop
   231  		case err = <-p.disc:
   232  			reason = discReasonForError(err)
   233  			break loop
   234  		}
   235  	}
   236  
   237  	close(p.closed)
   238  	p.rw.close(reason)
   239  	p.wg.Wait()
   240  	return remoteRequested, err
   241  }
   242  
   243  func (p *Peer) pingLoop() {
   244  	ping := time.NewTimer(pingInterval)
   245  	defer p.wg.Done()
   246  	defer ping.Stop()
   247  	for {
   248  		select {
   249  		case <-ping.C:
   250  			if err := SendItems(p.rw, pingMsg); err != nil {
   251  				p.protoErr <- err
   252  				return
   253  			}
   254  			ping.Reset(pingInterval)
   255  		case <-p.closed:
   256  			return
   257  		}
   258  	}
   259  }
   260  
   261  func (p *Peer) readLoop(errc chan<- error) {
   262  	defer p.wg.Done()
   263  	for {
   264  		msg, err := p.rw.ReadMsg()
   265  		if err != nil {
   266  			errc <- err
   267  			return
   268  		}
   269  		msg.ReceivedAt = time.Now()
   270  		if err = p.handle(msg); err != nil {
   271  			errc <- err
   272  			return
   273  		}
   274  	}
   275  }
   276  
   277  func (p *Peer) handle(msg Msg) error {
   278  	switch {
   279  	case msg.Code == pingMsg:
   280  		msg.Discard()
   281  		go SendItems(p.rw, pongMsg)
   282  	case msg.Code == discMsg:
   283  		var reason [1]DiscReason
   284  //这是最后一条信息。我们不需要抛弃或
   285  //检查错误,因为连接之后将关闭。
   286  		rlp.Decode(msg.Payload, &reason)
   287  		return reason[0]
   288  	case msg.Code < baseProtocolLength:
   289  //忽略其他基本协议消息
   290  		return msg.Discard()
   291  	default:
   292  //这是一个子协议消息
   293  		proto, err := p.getProto(msg.Code)
   294  		if err != nil {
   295  			return fmt.Errorf("msg code out of range: %v", msg.Code)
   296  		}
   297  		select {
   298  		case proto.in <- msg:
   299  			return nil
   300  		case <-p.closed:
   301  			return io.EOF
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  func countMatchingProtocols(protocols []Protocol, caps []Cap) int {
   308  	n := 0
   309  	for _, cap := range caps {
   310  		for _, proto := range protocols {
   311  			if proto.Name == cap.Name && proto.Version == cap.Version {
   312  				n++
   313  			}
   314  		}
   315  	}
   316  	return n
   317  }
   318  
   319  //MatchProtocols为匹配命名的子协议创建结构。
   320  func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW {
   321  	sort.Sort(capsByNameAndVersion(caps))
   322  	offset := baseProtocolLength
   323  	result := make(map[string]*protoRW)
   324  
   325  outer:
   326  	for _, cap := range caps {
   327  		for _, proto := range protocols {
   328  			if proto.Name == cap.Name && proto.Version == cap.Version {
   329  //如果旧协议版本匹配,请将其还原
   330  				if old := result[cap.Name]; old != nil {
   331  					offset -= old.Length
   332  				}
   333  //分配新匹配项
   334  				result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw}
   335  				offset += proto.Length
   336  
   337  				continue outer
   338  			}
   339  		}
   340  	}
   341  	return result
   342  }
   343  
   344  func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) {
   345  	p.wg.Add(len(p.running))
   346  	for _, proto := range p.running {
   347  		proto := proto
   348  		proto.closed = p.closed
   349  		proto.wstart = writeStart
   350  		proto.werr = writeErr
   351  		var rw MsgReadWriter = proto
   352  		if p.events != nil {
   353  			rw = newMsgEventer(rw, p.events, p.ID(), proto.Name)
   354  		}
   355  		p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version))
   356  		go func() {
   357  			err := proto.Run(p, rw)
   358  			if err == nil {
   359  				p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version))
   360  				err = errProtocolReturned
   361  			} else if err != io.EOF {
   362  				p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err)
   363  			}
   364  			p.protoErr <- err
   365  			p.wg.Done()
   366  		}()
   367  	}
   368  }
   369  
   370  //getproto查找负责处理的协议
   371  //给定的消息代码。
   372  func (p *Peer) getProto(code uint64) (*protoRW, error) {
   373  	for _, proto := range p.running {
   374  		if code >= proto.offset && code < proto.offset+proto.Length {
   375  			return proto, nil
   376  		}
   377  	}
   378  	return nil, newPeerError(errInvalidMsgCode, "%d", code)
   379  }
   380  
   381  type protoRW struct {
   382  	Protocol
   383  in     chan Msg        //接收已读消息
   384  closed <-chan struct{} //对等机关闭时接收
   385  wstart <-chan struct{} //当写入可能开始时接收
   386  werr   chan<- error    //用于写入结果
   387  	offset uint64
   388  	w      MsgWriter
   389  }
   390  
   391  func (rw *protoRW) WriteMsg(msg Msg) (err error) {
   392  	if msg.Code >= rw.Length {
   393  		return newPeerError(errInvalidMsgCode, "not handled")
   394  	}
   395  	msg.Code += rw.offset
   396  	select {
   397  	case <-rw.wstart:
   398  		err = rw.w.WriteMsg(msg)
   399  //将写状态报告回peer.run。它将启动
   400  //如果错误为非零,则关闭并取消阻止下一次写入
   401  //否则。如果出现错误,调用协议代码应退出。
   402  //但我们不想依赖它。
   403  		rw.werr <- err
   404  	case <-rw.closed:
   405  		err = ErrShuttingDown
   406  	}
   407  	return err
   408  }
   409  
   410  func (rw *protoRW) ReadMsg() (Msg, error) {
   411  	select {
   412  	case msg := <-rw.in:
   413  		msg.Code -= rw.offset
   414  		return msg, nil
   415  	case <-rw.closed:
   416  		return Msg{}, io.EOF
   417  	}
   418  }
   419  
   420  //PeerInfo表示有关连接的
   421  //同龄人。子协议独立字段包含在此处并在此处初始化,使用
   422  //协议细节委托给所有连接的子协议。
   423  type PeerInfo struct {
   424  Enode   string   `json:"enode"` //节点URL
   425  ID      string   `json:"id"`    //唯一节点标识符
   426  Name    string   `json:"name"`  //节点的名称,包括客户端类型、版本、操作系统、自定义数据
   427  Caps    []string `json:"caps"`  //此对等方公布的协议
   428  	Network struct {
   429  LocalAddress  string `json:"localAddress"`  //TCP数据连接的本地终结点
   430  RemoteAddress string `json:"remoteAddress"` //TCP数据连接的远程终结点
   431  		Inbound       bool   `json:"inbound"`
   432  		Trusted       bool   `json:"trusted"`
   433  		Static        bool   `json:"static"`
   434  	} `json:"network"`
   435  Protocols map[string]interface{} `json:"protocols"` //子协议特定的元数据字段
   436  }
   437  
   438  //INFO收集并返回有关对等机的已知元数据集合。
   439  func (p *Peer) Info() *PeerInfo {
   440  //收集协议功能
   441  	var caps []string
   442  	for _, cap := range p.Caps() {
   443  		caps = append(caps, cap.String())
   444  	}
   445  //组装通用对等元数据
   446  	info := &PeerInfo{
   447  		Enode:     p.Node().String(),
   448  		ID:        p.ID().String(),
   449  		Name:      p.Name(),
   450  		Caps:      caps,
   451  		Protocols: make(map[string]interface{}),
   452  	}
   453  	info.Network.LocalAddress = p.LocalAddr().String()
   454  	info.Network.RemoteAddress = p.RemoteAddr().String()
   455  	info.Network.Inbound = p.rw.is(inboundConn)
   456  	info.Network.Trusted = p.rw.is(trustedConn)
   457  	info.Network.Static = p.rw.is(staticDialedConn)
   458  
   459  //收集所有正在运行的协议信息
   460  	for _, proto := range p.running {
   461  		protoInfo := interface{}("unknown")
   462  		if query := proto.Protocol.PeerInfo; query != nil {
   463  			if metadata := query(p.ID()); metadata != nil {
   464  				protoInfo = metadata
   465  			} else {
   466  				protoInfo = "handshake"
   467  			}
   468  		}
   469  		info.Protocols[proto.Name] = protoInfo
   470  	}
   471  	return info
   472  }
   473