github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/protocols/protocol.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 12:09:44</date>
    10  //</624342659992915968>
    11  
    12  
    13  /*
    14  包协议是对p2p的扩展,它提供了一种用户友好的简单定义方法
    15  通过抽象协议标准共享的代码来开发子协议。
    16  
    17  *自动将代码索引分配给消息
    18  *基于反射自动RLP解码/编码
    19  *提供永久循环以读取传入消息
    20  *标准化与通信相关的错误处理
    21  *标准化握手谈判
    22  *TODO:自动生成对等机的有线协议规范
    23  
    24  **/
    25  
    26  package protocols
    27  
    28  import (
    29  	"bufio"
    30  	"bytes"
    31  	"context"
    32  	"fmt"
    33  	"io"
    34  	"reflect"
    35  	"sync"
    36  	"time"
    37  
    38  	"github.com/ethereum/go-ethereum/log"
    39  	"github.com/ethereum/go-ethereum/metrics"
    40  	"github.com/ethereum/go-ethereum/p2p"
    41  	"github.com/ethereum/go-ethereum/rlp"
    42  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    43  	"github.com/ethereum/go-ethereum/swarm/tracing"
    44  	opentracing "github.com/opentracing/opentracing-go"
    45  )
    46  
    47  //此协议方案使用的错误代码
    48  const (
    49  	ErrMsgTooLong = iota
    50  	ErrDecode
    51  	ErrWrite
    52  	ErrInvalidMsgCode
    53  	ErrInvalidMsgType
    54  	ErrHandshake
    55  	ErrNoHandler
    56  	ErrHandler
    57  )
    58  
    59  //与代码关联的错误描述字符串
    60  var errorToString = map[int]string{
    61  	ErrMsgTooLong:     "Message too long",
    62  	ErrDecode:         "Invalid message (RLP error)",
    63  	ErrWrite:          "Error sending message",
    64  	ErrInvalidMsgCode: "Invalid message code",
    65  	ErrInvalidMsgType: "Invalid message type",
    66  	ErrHandshake:      "Handshake error",
    67  	ErrNoHandler:      "No handler registered error",
    68  	ErrHandler:        "Message handler error",
    69  }
    70  
    71  /*
    72  错误实现标准Go错误接口。
    73  用途:
    74  
    75    错误F(代码、格式、参数…接口)
    76  
    77  打印为:
    78  
    79   <description>:<details>
    80  
    81  其中由ErrorToString中的代码给出描述
    82  详细信息是fmt.sprintf(格式,参数…)
    83  
    84  可以检查导出的字段代码
    85  **/
    86  
    87  type Error struct {
    88  	Code    int
    89  	message string
    90  	format  string
    91  	params  []interface{}
    92  }
    93  
    94  func (e Error) Error() (message string) {
    95  	if len(e.message) == 0 {
    96  		name, ok := errorToString[e.Code]
    97  		if !ok {
    98  			panic("invalid message code")
    99  		}
   100  		e.message = name
   101  		if e.format != "" {
   102  			e.message += ": " + fmt.Sprintf(e.format, e.params...)
   103  		}
   104  	}
   105  	return e.message
   106  }
   107  
   108  func errorf(code int, format string, params ...interface{}) *Error {
   109  	return &Error{
   110  		Code:   code,
   111  		format: format,
   112  		params: params,
   113  	}
   114  }
   115  
   116  //wrappedmsg用于在消息有效负载旁边传播已封送的上下文
   117  type WrappedMsg struct {
   118  	Context []byte
   119  	Size    uint32
   120  	Payload []byte
   121  }
   122  
   123  //规范是一种协议规范,包括其名称和版本以及
   124  //交换的消息类型
   125  type Spec struct {
   126  //名称是协议的名称,通常是三个字母的单词
   127  	Name string
   128  
   129  //version是协议的版本号
   130  	Version uint
   131  
   132  //maxmsgsize是消息有效负载的最大可接受长度
   133  	MaxMsgSize uint32
   134  
   135  //messages是此协议使用的消息数据类型的列表,
   136  //发送的每个消息类型及其数组索引作为代码(因此
   137  //[&foo,&bar,&baz]将发送带有代码的foo、bar和baz
   138  //分别为0、1和2)
   139  //每条消息必须有一个唯一的数据类型
   140  	Messages []interface{}
   141  
   142  	initOnce sync.Once
   143  	codes    map[reflect.Type]uint64
   144  	types    map[uint64]reflect.Type
   145  }
   146  
   147  func (s *Spec) init() {
   148  	s.initOnce.Do(func() {
   149  		s.codes = make(map[reflect.Type]uint64, len(s.Messages))
   150  		s.types = make(map[uint64]reflect.Type, len(s.Messages))
   151  		for i, msg := range s.Messages {
   152  			code := uint64(i)
   153  			typ := reflect.TypeOf(msg)
   154  			if typ.Kind() == reflect.Ptr {
   155  				typ = typ.Elem()
   156  			}
   157  			s.codes[typ] = code
   158  			s.types[code] = typ
   159  		}
   160  	})
   161  }
   162  
   163  //length返回协议中的消息类型数
   164  func (s *Spec) Length() uint64 {
   165  	return uint64(len(s.Messages))
   166  }
   167  
   168  //getcode返回一个类型的消息代码,Boolean第二个参数是
   169  //如果未找到消息类型,则为false
   170  func (s *Spec) GetCode(msg interface{}) (uint64, bool) {
   171  	s.init()
   172  	typ := reflect.TypeOf(msg)
   173  	if typ.Kind() == reflect.Ptr {
   174  		typ = typ.Elem()
   175  	}
   176  	code, ok := s.codes[typ]
   177  	return code, ok
   178  }
   179  
   180  //newmsg构造给定代码的新消息类型
   181  func (s *Spec) NewMsg(code uint64) (interface{}, bool) {
   182  	s.init()
   183  	typ, ok := s.types[code]
   184  	if !ok {
   185  		return nil, false
   186  	}
   187  	return reflect.New(typ).Interface(), true
   188  }
   189  
   190  //对等机表示在与的对等连接上运行的远程对等机或协议实例
   191  //远程对等体
   192  type Peer struct {
   193  *p2p.Peer                   //代表远程的p2p.peer对象
   194  rw        p2p.MsgReadWriter //p2p.msgreadwriter,用于向发送消息和从中读取消息
   195  	spec      *Spec
   196  }
   197  
   198  //new peer构造新的peer
   199  //此构造函数由p2p.protocol run函数调用
   200  //前两个参数是传递给p2p.protocol.run函数的参数
   201  //第三个参数是描述协议的规范
   202  func NewPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *Spec) *Peer {
   203  	return &Peer{
   204  		Peer: p,
   205  		rw:   rw,
   206  		spec: spec,
   207  	}
   208  }
   209  
   210  //运行启动处理传入消息的Forever循环
   211  //在p2p.protocol run函数中调用
   212  //handler参数是为接收到的每个消息调用的函数。
   213  //从远程对等机返回的错误导致循环退出
   214  //导致断开
   215  func (p *Peer) Run(handler func(ctx context.Context, msg interface{}) error) error {
   216  	for {
   217  		if err := p.handleIncoming(handler); err != nil {
   218  			if err != io.EOF {
   219  				metrics.GetOrRegisterCounter("peer.handleincoming.error", nil).Inc(1)
   220  				log.Error("peer.handleIncoming", "err", err)
   221  			}
   222  
   223  			return err
   224  		}
   225  	}
   226  }
   227  
   228  //DROP断开对等机的连接。
   229  //TODO:可能只需要实现协议删除?不想把同伴踢开
   230  //如果它们对其他协议有用
   231  func (p *Peer) Drop(err error) {
   232  	p.Disconnect(p2p.DiscSubprotocolError)
   233  }
   234  
   235  //send接收一条消息,将其编码为rlp,找到正确的消息代码并发送
   236  //向对等端发送消息
   237  //这个低级调用将由提供路由或广播发送的库包装。
   238  //但通常只用于转发和将消息推送到直接连接的对等端
   239  func (p *Peer) Send(ctx context.Context, msg interface{}) error {
   240  	defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now())
   241  	metrics.GetOrRegisterCounter("peer.send", nil).Inc(1)
   242  
   243  	var b bytes.Buffer
   244  	if tracing.Enabled {
   245  		writer := bufio.NewWriter(&b)
   246  
   247  		tracer := opentracing.GlobalTracer()
   248  
   249  		sctx := spancontext.FromContext(ctx)
   250  
   251  		if sctx != nil {
   252  			err := tracer.Inject(
   253  				sctx,
   254  				opentracing.Binary,
   255  				writer)
   256  			if err != nil {
   257  				return err
   258  			}
   259  		}
   260  
   261  		writer.Flush()
   262  	}
   263  
   264  	r, err := rlp.EncodeToBytes(msg)
   265  	if err != nil {
   266  		return err
   267  	}
   268  
   269  	wmsg := WrappedMsg{
   270  		Context: b.Bytes(),
   271  		Size:    uint32(len(r)),
   272  		Payload: r,
   273  	}
   274  
   275  	code, found := p.spec.GetCode(msg)
   276  	if !found {
   277  		return errorf(ErrInvalidMsgType, "%v", code)
   278  	}
   279  	return p2p.Send(p.rw, code, wmsg)
   280  }
   281  
   282  //手工编码(代码)
   283  //在发送传入消息的主永久循环的每个循环中调用
   284  //如果返回错误,则循环将返回,并且对等端将与错误断开连接。
   285  //此通用处理程序
   286  //*检查邮件大小,
   287  //*检查超出范围的消息代码,
   288  //*处理带反射的解码,
   289  //*作为回调的调用处理程序
   290  func (p *Peer) handleIncoming(handle func(ctx context.Context, msg interface{}) error) error {
   291  	msg, err := p.rw.ReadMsg()
   292  	if err != nil {
   293  		return err
   294  	}
   295  //确保有效载荷已被完全消耗。
   296  	defer msg.Discard()
   297  
   298  	if msg.Size > p.spec.MaxMsgSize {
   299  		return errorf(ErrMsgTooLong, "%v > %v", msg.Size, p.spec.MaxMsgSize)
   300  	}
   301  
   302  //取消标记包装的邮件,其中可能包含上下文
   303  	var wmsg WrappedMsg
   304  	err = msg.Decode(&wmsg)
   305  	if err != nil {
   306  		log.Error(err.Error())
   307  		return err
   308  	}
   309  
   310  	ctx := context.Background()
   311  
   312  //如果启用了跟踪,并且请求中的上下文是
   313  //不是空的,试着解开它
   314  	if tracing.Enabled && len(wmsg.Context) > 0 {
   315  		var sctx opentracing.SpanContext
   316  
   317  		tracer := opentracing.GlobalTracer()
   318  		sctx, err = tracer.Extract(
   319  			opentracing.Binary,
   320  			bytes.NewReader(wmsg.Context))
   321  		if err != nil {
   322  			log.Error(err.Error())
   323  			return err
   324  		}
   325  
   326  		ctx = spancontext.WithContext(ctx, sctx)
   327  	}
   328  
   329  	val, ok := p.spec.NewMsg(msg.Code)
   330  	if !ok {
   331  		return errorf(ErrInvalidMsgCode, "%v", msg.Code)
   332  	}
   333  	if err := rlp.DecodeBytes(wmsg.Payload, val); err != nil {
   334  		return errorf(ErrDecode, "<= %v: %v", msg, err)
   335  	}
   336  
   337  //调用已注册的处理程序回调
   338  //注册的回调将解码后的消息作为参数作为接口
   339  //应该将处理程序强制转换为适当的类型
   340  //不检查处理程序中的强制转换是完全安全的,因为处理程序是
   341  //首先根据正确的类型选择
   342  	if err := handle(ctx, val); err != nil {
   343  		return errorf(ErrHandler, "(msg code %v): %v", msg.Code, err)
   344  	}
   345  	return nil
   346  }
   347  
   348  //握手在对等连接上协商握手
   349  //*参数
   350  //*上下文
   351  //*要发送到远程对等机的本地握手
   352  //*远程握手时要调用的函数(可以为零)
   353  //*需要相同类型的远程握手
   354  //*拨号对等端需要先发送握手,然后等待远程
   355  //*侦听对等机等待远程握手,然后发送它
   356  //返回远程握手和错误
   357  func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interface{}) error) (rhs interface{}, err error) {
   358  	if _, ok := p.spec.GetCode(hs); !ok {
   359  		return nil, errorf(ErrHandshake, "unknown handshake message type: %T", hs)
   360  	}
   361  	errc := make(chan error, 2)
   362  	handle := func(ctx context.Context, msg interface{}) error {
   363  		rhs = msg
   364  		if verify != nil {
   365  			return verify(rhs)
   366  		}
   367  		return nil
   368  	}
   369  	send := func() { errc <- p.Send(ctx, hs) }
   370  	receive := func() { errc <- p.handleIncoming(handle) }
   371  
   372  	go func() {
   373  		if p.Inbound() {
   374  			receive()
   375  			send()
   376  		} else {
   377  			send()
   378  			receive()
   379  		}
   380  	}()
   381  
   382  	for i := 0; i < 2; i++ {
   383  		select {
   384  		case err = <-errc:
   385  		case <-ctx.Done():
   386  			err = ctx.Err()
   387  		}
   388  		if err != nil {
   389  			return nil, errorf(ErrHandshake, err.Error())
   390  		}
   391  	}
   392  	return rhs, nil
   393  }
   394