github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/p2p/peer.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package p2p 18 19 import ( 20 "errors" 21 "fmt" 22 "io" 23 "net" 24 "sort" 25 "sync" 26 "time" 27 28 "github.com/fff-chain/go-fff/common/gopool" 29 "github.com/fff-chain/go-fff/common/mclock" 30 "github.com/fff-chain/go-fff/event" 31 "github.com/fff-chain/go-fff/log" 32 "github.com/fff-chain/go-fff/metrics" 33 "github.com/fff-chain/go-fff/p2p/enode" 34 "github.com/fff-chain/go-fff/p2p/enr" 35 "github.com/fff-chain/go-fff/rlp" 36 ) 37 38 var ( 39 ErrShuttingDown = errors.New("shutting down") 40 ) 41 42 const ( 43 baseProtocolVersion = 5 44 baseProtocolLength = uint64(16) 45 baseProtocolMaxMsgSize = 2 * 1024 46 47 snappyProtocolVersion = 5 48 49 pingInterval = 15 * time.Second 50 ) 51 52 const ( 53 // devp2p message codes 54 handshakeMsg = 0x00 55 discMsg = 0x01 56 pingMsg = 0x02 57 pongMsg = 0x03 58 ) 59 60 // protoHandshake is the RLP structure of the protocol handshake. 61 type protoHandshake struct { 62 Version uint64 63 Name string 64 Caps []Cap 65 ListenPort uint64 66 ID []byte // secp256k1 public key 67 68 // Ignore additional fields (for forward compatibility). 69 Rest []rlp.RawValue `rlp:"tail"` 70 } 71 72 // PeerEventType is the type of peer events emitted by a p2p.Server 73 type PeerEventType string 74 75 const ( 76 // PeerEventTypeAdd is the type of event emitted when a peer is added 77 // to a p2p.Server 78 PeerEventTypeAdd PeerEventType = "add" 79 80 // PeerEventTypeDrop is the type of event emitted when a peer is 81 // dropped from a p2p.Server 82 PeerEventTypeDrop PeerEventType = "drop" 83 84 // PeerEventTypeMsgSend is the type of event emitted when a 85 // message is successfully sent to a peer 86 PeerEventTypeMsgSend PeerEventType = "msgsend" 87 88 // PeerEventTypeMsgRecv is the type of event emitted when a 89 // message is received from a peer 90 PeerEventTypeMsgRecv PeerEventType = "msgrecv" 91 ) 92 93 // PeerEvent is an event emitted when peers are either added or dropped from 94 // a p2p.Server or when a message is sent or received on a peer connection 95 type PeerEvent struct { 96 Type PeerEventType `json:"type"` 97 Peer enode.ID `json:"peer"` 98 Error string `json:"error,omitempty"` 99 Protocol string `json:"protocol,omitempty"` 100 MsgCode *uint64 `json:"msg_code,omitempty"` 101 MsgSize *uint32 `json:"msg_size,omitempty"` 102 LocalAddress string `json:"local,omitempty"` 103 RemoteAddress string `json:"remote,omitempty"` 104 } 105 106 // Peer represents a connected remote node. 107 type Peer struct { 108 rw *conn 109 running map[string]*protoRW 110 log log.Logger 111 created mclock.AbsTime 112 113 wg sync.WaitGroup 114 protoErr chan error 115 closed chan struct{} 116 disc chan DiscReason 117 118 // events receives message send / receive events if set 119 events *event.Feed 120 } 121 122 // NewPeer returns a peer for testing purposes. 123 func NewPeer(id enode.ID, name string, caps []Cap) *Peer { 124 pipe, _ := net.Pipe() 125 node := enode.SignNull(new(enr.Record), id) 126 conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} 127 peer := newPeer(log.Root(), conn, nil) 128 close(peer.closed) // ensures Disconnect doesn't block 129 return peer 130 } 131 132 // NewPeerWithProtocols returns a peer for testing purposes. 133 func NewPeerWithProtocols(id enode.ID, protocols []Protocol, name string, caps []Cap) *Peer { 134 pipe, _ := net.Pipe() 135 node := enode.SignNull(new(enr.Record), id) 136 conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} 137 peer := newPeer(log.Root(), conn, protocols) 138 close(peer.closed) // ensures Disconnect doesn't block 139 return peer 140 } 141 142 // ID returns the node's public key. 143 func (p *Peer) ID() enode.ID { 144 return p.rw.node.ID() 145 } 146 147 // Node returns the peer's node descriptor. 148 func (p *Peer) Node() *enode.Node { 149 return p.rw.node 150 } 151 152 // Name returns an abbreviated form of the name 153 func (p *Peer) Name() string { 154 s := p.rw.name 155 if len(s) > 20 { 156 return s[:20] + "..." 157 } 158 return s 159 } 160 161 // Fullname returns the node name that the remote node advertised. 162 func (p *Peer) Fullname() string { 163 return p.rw.name 164 } 165 166 // Caps returns the capabilities (supported subprotocols) of the remote peer. 167 func (p *Peer) Caps() []Cap { 168 // TODO: maybe return copy 169 return p.rw.caps 170 } 171 172 // RunningCap returns true if the peer is actively connected using any of the 173 // enumerated versions of a specific protocol, meaning that at least one of the 174 // versions is supported by both this node and the peer p. 175 func (p *Peer) RunningCap(protocol string, versions []uint) bool { 176 if proto, ok := p.running[protocol]; ok { 177 for _, ver := range versions { 178 if proto.Version == ver { 179 return true 180 } 181 } 182 } 183 return false 184 } 185 186 // RemoteAddr returns the remote address of the network connection. 187 func (p *Peer) RemoteAddr() net.Addr { 188 return p.rw.fd.RemoteAddr() 189 } 190 191 // LocalAddr returns the local address of the network connection. 192 func (p *Peer) LocalAddr() net.Addr { 193 return p.rw.fd.LocalAddr() 194 } 195 196 // Disconnect terminates the peer connection with the given reason. 197 // It returns immediately and does not wait until the connection is closed. 198 func (p *Peer) Disconnect(reason DiscReason) { 199 select { 200 case p.disc <- reason: 201 case <-p.closed: 202 } 203 } 204 205 // String implements fmt.Stringer. 206 func (p *Peer) String() string { 207 id := p.ID() 208 return fmt.Sprintf("Peer %x %v", id[:8], p.RemoteAddr()) 209 } 210 211 // Inbound returns true if the peer is an inbound connection 212 func (p *Peer) Inbound() bool { 213 return p.rw.is(inboundConn) 214 } 215 216 func newPeer(log log.Logger, conn *conn, protocols []Protocol) *Peer { 217 protomap := matchProtocols(protocols, conn.caps, conn) 218 p := &Peer{ 219 rw: conn, 220 running: protomap, 221 created: mclock.Now(), 222 disc: make(chan DiscReason), 223 protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop 224 closed: make(chan struct{}), 225 log: log.New("id", conn.node.ID(), "conn", conn.flags), 226 } 227 return p 228 } 229 230 func (p *Peer) Log() log.Logger { 231 return p.log 232 } 233 234 func (p *Peer) run() (remoteRequested bool, err error) { 235 var ( 236 writeStart = make(chan struct{}, 1) 237 writeErr = make(chan error, 1) 238 readErr = make(chan error, 1) 239 reason DiscReason // sent to the peer 240 ) 241 p.wg.Add(2) 242 go p.readLoop(readErr) 243 go p.pingLoop() 244 245 // Start all protocol handlers. 246 writeStart <- struct{}{} 247 p.startProtocols(writeStart, writeErr) 248 249 // Wait for an error or disconnect. 250 loop: 251 for { 252 select { 253 case err = <-writeErr: 254 // A write finished. Allow the next write to start if 255 // there was no error. 256 if err != nil { 257 reason = DiscNetworkError 258 break loop 259 } 260 writeStart <- struct{}{} 261 case err = <-readErr: 262 if r, ok := err.(DiscReason); ok { 263 remoteRequested = true 264 reason = r 265 } else { 266 reason = DiscNetworkError 267 } 268 break loop 269 case err = <-p.protoErr: 270 reason = discReasonForError(err) 271 break loop 272 case err = <-p.disc: 273 reason = discReasonForError(err) 274 break loop 275 } 276 } 277 278 close(p.closed) 279 p.rw.close(reason) 280 p.wg.Wait() 281 return remoteRequested, err 282 } 283 284 func (p *Peer) pingLoop() { 285 ping := time.NewTimer(pingInterval) 286 defer p.wg.Done() 287 defer ping.Stop() 288 for { 289 select { 290 case <-ping.C: 291 if err := SendItems(p.rw, pingMsg); err != nil { 292 p.protoErr <- err 293 return 294 } 295 ping.Reset(pingInterval) 296 case <-p.closed: 297 return 298 } 299 } 300 } 301 302 func (p *Peer) readLoop(errc chan<- error) { 303 defer p.wg.Done() 304 for { 305 msg, err := p.rw.ReadMsg() 306 if err != nil { 307 errc <- err 308 return 309 } 310 msg.ReceivedAt = time.Now() 311 if err = p.handle(msg); err != nil { 312 errc <- err 313 return 314 } 315 } 316 } 317 318 func (p *Peer) handle(msg Msg) error { 319 switch { 320 case msg.Code == pingMsg: 321 msg.Discard() 322 gopool.Submit(func() { 323 SendItems(p.rw, pongMsg) 324 }) 325 case msg.Code == discMsg: 326 var reason [1]DiscReason 327 // This is the last message. We don't need to discard or 328 // check errors because, the connection will be closed after it. 329 rlp.Decode(msg.Payload, &reason) 330 return reason[0] 331 case msg.Code < baseProtocolLength: 332 // ignore other base protocol messages 333 return msg.Discard() 334 default: 335 // it's a subprotocol message 336 proto, err := p.getProto(msg.Code) 337 if err != nil { 338 return fmt.Errorf("msg code out of range: %v", msg.Code) 339 } 340 if metrics.Enabled { 341 m := fmt.Sprintf("%s/%s/%d/%#02x", ingressMeterName, proto.Name, proto.Version, msg.Code-proto.offset) 342 metrics.GetOrRegisterMeter(m, nil).Mark(int64(msg.meterSize)) 343 metrics.GetOrRegisterMeter(m+"/packets", nil).Mark(1) 344 } 345 select { 346 case proto.in <- msg: 347 return nil 348 case <-p.closed: 349 return io.EOF 350 } 351 } 352 return nil 353 } 354 355 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 356 n := 0 357 for _, cap := range caps { 358 for _, proto := range protocols { 359 if proto.Name == cap.Name && proto.Version == cap.Version { 360 n++ 361 } 362 } 363 } 364 return n 365 } 366 367 // matchProtocols creates structures for matching named subprotocols. 368 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 369 sort.Sort(capsByNameAndVersion(caps)) 370 offset := baseProtocolLength 371 result := make(map[string]*protoRW) 372 373 outer: 374 for _, cap := range caps { 375 for _, proto := range protocols { 376 if proto.Name == cap.Name && proto.Version == cap.Version { 377 // If an old protocol version matched, revert it 378 if old := result[cap.Name]; old != nil { 379 offset -= old.Length 380 } 381 // Assign the new match 382 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 383 offset += proto.Length 384 385 continue outer 386 } 387 } 388 } 389 return result 390 } 391 392 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 393 p.wg.Add(len(p.running)) 394 for _, proto := range p.running { 395 proto := proto 396 proto.closed = p.closed 397 proto.wstart = writeStart 398 proto.werr = writeErr 399 var rw MsgReadWriter = proto 400 if p.events != nil { 401 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name, p.Info().Network.RemoteAddress, p.Info().Network.LocalAddress) 402 } 403 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 404 go func() { 405 defer p.wg.Done() 406 err := proto.Run(p, rw) 407 if err == nil { 408 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 409 err = errProtocolReturned 410 } else if err != io.EOF { 411 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 412 } 413 p.protoErr <- err 414 }() 415 } 416 } 417 418 // getProto finds the protocol responsible for handling 419 // the given message code. 420 func (p *Peer) getProto(code uint64) (*protoRW, error) { 421 for _, proto := range p.running { 422 if code >= proto.offset && code < proto.offset+proto.Length { 423 return proto, nil 424 } 425 } 426 return nil, newPeerError(errInvalidMsgCode, "%d", code) 427 } 428 429 type protoRW struct { 430 Protocol 431 in chan Msg // receives read messages 432 closed <-chan struct{} // receives when peer is shutting down 433 wstart <-chan struct{} // receives when write may start 434 werr chan<- error // for write results 435 offset uint64 436 w MsgWriter 437 } 438 439 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 440 if msg.Code >= rw.Length { 441 return newPeerError(errInvalidMsgCode, "not handled") 442 } 443 msg.meterCap = rw.cap() 444 msg.meterCode = msg.Code 445 446 msg.Code += rw.offset 447 448 select { 449 case <-rw.wstart: 450 err = rw.w.WriteMsg(msg) 451 // Report write status back to Peer.run. It will initiate 452 // shutdown if the error is non-nil and unblock the next write 453 // otherwise. The calling protocol code should exit for errors 454 // as well but we don't want to rely on that. 455 rw.werr <- err 456 case <-rw.closed: 457 err = ErrShuttingDown 458 } 459 return err 460 } 461 462 func (rw *protoRW) ReadMsg() (Msg, error) { 463 select { 464 case msg := <-rw.in: 465 msg.Code -= rw.offset 466 return msg, nil 467 case <-rw.closed: 468 return Msg{}, io.EOF 469 } 470 } 471 472 // PeerInfo represents a short summary of the information known about a connected 473 // peer. Sub-protocol independent fields are contained and initialized here, with 474 // protocol specifics delegated to all connected sub-protocols. 475 type PeerInfo struct { 476 ENR string `json:"enr,omitempty"` // Ethereum Node Record 477 Enode string `json:"enode"` // Node URL 478 ID string `json:"id"` // Unique node identifier 479 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 480 Caps []string `json:"caps"` // Protocols advertised by this peer 481 Network struct { 482 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 483 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 484 Inbound bool `json:"inbound"` 485 Trusted bool `json:"trusted"` 486 Static bool `json:"static"` 487 } `json:"network"` 488 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 489 } 490 491 // Info gathers and returns a collection of metadata known about a peer. 492 func (p *Peer) Info() *PeerInfo { 493 // Gather the protocol capabilities 494 var caps []string 495 for _, cap := range p.Caps() { 496 caps = append(caps, cap.String()) 497 } 498 // Assemble the generic peer metadata 499 info := &PeerInfo{ 500 Enode: p.Node().URLv4(), 501 ID: p.ID().String(), 502 Name: p.Fullname(), 503 Caps: caps, 504 Protocols: make(map[string]interface{}), 505 } 506 if p.Node().Seq() > 0 { 507 info.ENR = p.Node().String() 508 } 509 info.Network.LocalAddress = p.LocalAddr().String() 510 info.Network.RemoteAddress = p.RemoteAddr().String() 511 info.Network.Inbound = p.rw.is(inboundConn) 512 info.Network.Trusted = p.rw.is(trustedConn) 513 info.Network.Static = p.rw.is(staticDialedConn) 514 515 // Gather all the running protocol infos 516 for _, proto := range p.running { 517 protoInfo := interface{}("unknown") 518 if query := proto.Protocol.PeerInfo; query != nil { 519 if metadata := query(p.ID()); metadata != nil { 520 protoInfo = metadata 521 } else { 522 protoInfo = "handshake" 523 } 524 } 525 info.Protocols[proto.Name] = protoInfo 526 } 527 return info 528 }