github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/protocols/protocol.go (about)

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