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 }