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