github.com/number571/tendermint@v0.34.11-gost/internal/p2p/pex/pex_reactor.go (about) 1 package pex 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "sync" 8 "time" 9 10 "github.com/gogo/protobuf/proto" 11 12 "github.com/number571/tendermint/internal/p2p" 13 "github.com/number571/tendermint/internal/p2p/conn" 14 "github.com/number571/tendermint/libs/cmap" 15 tmmath "github.com/number571/tendermint/libs/math" 16 tmrand "github.com/number571/tendermint/libs/rand" 17 "github.com/number571/tendermint/libs/service" 18 tmp2p "github.com/number571/tendermint/proto/tendermint/p2p" 19 "github.com/number571/tendermint/types" 20 ) 21 22 type Peer = p2p.Peer 23 24 const ( 25 // PexChannel is a channel for PEX messages 26 PexChannel = byte(0x00) 27 28 // over-estimate of max NetAddress size 29 // hexID (40) + IP (16) + Port (2) + Name (100) ... 30 // NOTE: dont use massive DNS name .. 31 maxAddressSize = 256 32 33 // NOTE: amplificaiton factor! 34 // small request results in up to maxMsgSize response 35 maxMsgSize = maxAddressSize * maxGetSelection 36 37 // ensure we have enough peers 38 defaultEnsurePeersPeriod = 30 * time.Second 39 40 // Seed/Crawler constants 41 42 // minTimeBetweenCrawls is a minimum time between attempts to crawl a peer. 43 minTimeBetweenCrawls = 2 * time.Minute 44 45 // check some peers every this 46 crawlPeerPeriod = 30 * time.Second 47 48 maxAttemptsToDial = 16 // ~ 35h in total (last attempt - 18h) 49 50 // if node connects to seed, it does not have any trusted peers. 51 // Especially in the beginning, node should have more trusted peers than 52 // untrusted. 53 biasToSelectNewPeers = 30 // 70 to select good peers 54 55 // if a peer is marked bad, it will be banned for at least this time period 56 defaultBanTime = 24 * time.Hour 57 ) 58 59 type errMaxAttemptsToDial struct { 60 } 61 62 func (e errMaxAttemptsToDial) Error() string { 63 return fmt.Sprintf("reached max attempts %d to dial", maxAttemptsToDial) 64 } 65 66 type errTooEarlyToDial struct { 67 backoffDuration time.Duration 68 lastDialed time.Time 69 } 70 71 func (e errTooEarlyToDial) Error() string { 72 return fmt.Sprintf( 73 "too early to dial (backoff duration: %d, last dialed: %v, time since: %v)", 74 e.backoffDuration, e.lastDialed, time.Since(e.lastDialed)) 75 } 76 77 // Reactor handles PEX (peer exchange) and ensures that an 78 // adequate number of peers are connected to the switch. 79 // 80 // It uses `AddrBook` (address book) to store `NetAddress`es of the peers. 81 // 82 // ## Preventing abuse 83 // 84 // Only accept pexAddrsMsg from peers we sent a corresponding pexRequestMsg too. 85 // Only accept one pexRequestMsg every ~defaultEnsurePeersPeriod. 86 type Reactor struct { 87 p2p.BaseReactor 88 89 book AddrBook 90 config *ReactorConfig 91 ensurePeersPeriod time.Duration // TODO: should go in the config 92 93 // maps to prevent abuse 94 requestsSent *cmap.CMap // ID->struct{}: unanswered send requests 95 lastReceivedRequests *cmap.CMap // ID->time.Time: last time peer requested from us 96 97 seedAddrs []*p2p.NetAddress 98 99 attemptsToDial sync.Map // address (string) -> {number of attempts (int), last time dialed (time.Time)} 100 101 // seed/crawled mode fields 102 crawlPeerInfos map[types.NodeID]crawlPeerInfo 103 } 104 105 func (r *Reactor) minReceiveRequestInterval() time.Duration { 106 // NOTE: must be less than ensurePeersPeriod, otherwise we'll request 107 // peers too quickly from others and they'll think we're bad! 108 return r.ensurePeersPeriod / 3 109 } 110 111 // ReactorConfig holds reactor specific configuration data. 112 type ReactorConfig struct { 113 // Seed/Crawler mode 114 SeedMode bool 115 116 // We want seeds to only advertise good peers. Therefore they should wait at 117 // least as long as we expect it to take for a peer to become good before 118 // disconnecting. 119 SeedDisconnectWaitPeriod time.Duration 120 121 // Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) 122 PersistentPeersMaxDialPeriod time.Duration 123 124 // Seeds is a list of addresses reactor may use 125 // if it can't connect to peers in the addrbook. 126 Seeds []string 127 } 128 129 type _attemptsToDial struct { 130 number int 131 lastDialed time.Time 132 } 133 134 // NewReactor creates new PEX reactor. 135 func NewReactor(b AddrBook, config *ReactorConfig) *Reactor { 136 r := &Reactor{ 137 book: b, 138 config: config, 139 ensurePeersPeriod: defaultEnsurePeersPeriod, 140 requestsSent: cmap.NewCMap(), 141 lastReceivedRequests: cmap.NewCMap(), 142 crawlPeerInfos: make(map[types.NodeID]crawlPeerInfo), 143 } 144 r.BaseReactor = *p2p.NewBaseReactor("PEX", r) 145 return r 146 } 147 148 // OnStart implements BaseService 149 func (r *Reactor) OnStart() error { 150 err := r.book.Start() 151 if err != nil && err != service.ErrAlreadyStarted { 152 return err 153 } 154 155 numOnline, seedAddrs, err := r.checkSeeds() 156 if err != nil { 157 return err 158 } else if numOnline == 0 && r.book.Empty() { 159 return errors.New("address book is empty and couldn't resolve any seed nodes") 160 } 161 162 r.seedAddrs = seedAddrs 163 164 // Check if this node should run 165 // in seed/crawler mode 166 if r.config.SeedMode { 167 go r.crawlPeersRoutine() 168 } else { 169 go r.ensurePeersRoutine() 170 } 171 return nil 172 } 173 174 // OnStop implements BaseService 175 func (r *Reactor) OnStop() { 176 if err := r.book.Stop(); err != nil { 177 r.Logger.Error("Error stopping address book", "err", err) 178 } 179 } 180 181 // GetChannels implements Reactor 182 func (r *Reactor) GetChannels() []*conn.ChannelDescriptor { 183 return []*conn.ChannelDescriptor{ 184 { 185 ID: PexChannel, 186 Priority: 1, 187 SendQueueCapacity: 10, 188 RecvMessageCapacity: maxMsgSize, 189 190 MaxSendBytes: 200, 191 }, 192 } 193 } 194 195 // AddPeer implements Reactor by adding peer to the address book (if inbound) 196 // or by requesting more addresses (if outbound). 197 func (r *Reactor) AddPeer(p Peer) { 198 if p.IsOutbound() { 199 // For outbound peers, the address is already in the books - 200 // either via DialPeersAsync or r.Receive. 201 // Ask it for more peers if we need. 202 if r.book.NeedMoreAddrs() { 203 r.RequestAddrs(p) 204 } 205 } else { 206 // inbound peer is its own source 207 addr, err := p.NodeInfo().NetAddress() 208 if err != nil { 209 r.Logger.Error("Failed to get peer NetAddress", "err", err, "peer", p) 210 return 211 } 212 213 // Make it explicit that addr and src are the same for an inbound peer. 214 src := addr 215 216 // add to book. dont RequestAddrs right away because 217 // we don't trust inbound as much - let ensurePeersRoutine handle it. 218 err = r.book.AddAddress(addr, src) 219 r.logErrAddrBook(err) 220 } 221 } 222 223 // RemovePeer implements Reactor by resetting peer's requests info. 224 func (r *Reactor) RemovePeer(p Peer, reason interface{}) { 225 id := string(p.ID()) 226 r.requestsSent.Delete(id) 227 r.lastReceivedRequests.Delete(id) 228 } 229 230 func (r *Reactor) logErrAddrBook(err error) { 231 if err != nil { 232 switch err.(type) { 233 case ErrAddrBookNilAddr: 234 r.Logger.Error("Failed to add new address", "err", err) 235 default: 236 // non-routable, self, full book, private, etc. 237 r.Logger.Debug("Failed to add new address", "err", err) 238 } 239 } 240 } 241 242 // Receive implements Reactor by handling incoming PEX messages. 243 // XXX: do not call any methods that can block or incur heavy processing. 244 // https://github.com/number571/tendermint/issues/2888 245 func (r *Reactor) Receive(chID byte, src Peer, msgBytes []byte) { 246 msg, err := decodeMsg(msgBytes) 247 if err != nil { 248 r.Logger.Error("Error decoding message", "src", src, "chId", chID, "err", err) 249 r.Switch.StopPeerForError(src, err) 250 return 251 } 252 r.Logger.Debug("Received message", "src", src, "chId", chID, "msg", msg) 253 254 switch msg := msg.(type) { 255 case *tmp2p.PexRequest: 256 257 // NOTE: this is a prime candidate for amplification attacks, 258 // so it's important we 259 // 1) restrict how frequently peers can request 260 // 2) limit the output size 261 262 // If we're a seed and this is an inbound peer, 263 // respond once and disconnect. 264 if r.config.SeedMode && !src.IsOutbound() { 265 id := string(src.ID()) 266 v := r.lastReceivedRequests.Get(id) 267 if v != nil { 268 // FlushStop/StopPeer are already 269 // running in a go-routine. 270 return 271 } 272 r.lastReceivedRequests.Set(id, time.Now()) 273 274 // Send addrs and disconnect 275 r.SendAddrs(src, r.book.GetSelectionWithBias(biasToSelectNewPeers)) 276 go func() { 277 // In a go-routine so it doesn't block .Receive. 278 src.FlushStop() 279 r.Switch.StopPeerGracefully(src) 280 }() 281 282 } else { 283 // Check we're not receiving requests too frequently. 284 if err := r.receiveRequest(src); err != nil { 285 r.Switch.StopPeerForError(src, err) 286 r.book.MarkBad(src.SocketAddr(), defaultBanTime) 287 return 288 } 289 r.SendAddrs(src, r.book.GetSelection()) 290 } 291 292 case *tmp2p.PexResponse: 293 // If we asked for addresses, add them to the book 294 addrs, err := NetAddressesFromProto(msg.Addresses) 295 if err != nil { 296 r.Switch.StopPeerForError(src, err) 297 r.book.MarkBad(src.SocketAddr(), defaultBanTime) 298 return 299 } 300 err = r.ReceiveAddrs(addrs, src) 301 if err != nil { 302 r.Switch.StopPeerForError(src, err) 303 if err == ErrUnsolicitedList { 304 r.book.MarkBad(src.SocketAddr(), defaultBanTime) 305 } 306 return 307 } 308 309 default: 310 r.Logger.Error(fmt.Sprintf("Unknown message type %T", msg)) 311 } 312 } 313 314 // enforces a minimum amount of time between requests 315 func (r *Reactor) receiveRequest(src Peer) error { 316 id := string(src.ID()) 317 v := r.lastReceivedRequests.Get(id) 318 if v == nil { 319 // initialize with empty time 320 lastReceived := time.Time{} 321 r.lastReceivedRequests.Set(id, lastReceived) 322 return nil 323 } 324 325 lastReceived := v.(time.Time) 326 if lastReceived.Equal(time.Time{}) { 327 // first time gets a free pass. then we start tracking the time 328 lastReceived = time.Now() 329 r.lastReceivedRequests.Set(id, lastReceived) 330 return nil 331 } 332 333 now := time.Now() 334 minInterval := r.minReceiveRequestInterval() 335 if now.Sub(lastReceived) < minInterval { 336 return fmt.Errorf( 337 "peer (%v) sent next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting", 338 src.ID(), 339 lastReceived, 340 now, 341 minInterval, 342 ) 343 } 344 r.lastReceivedRequests.Set(id, now) 345 return nil 346 } 347 348 // RequestAddrs asks peer for more addresses if we do not already have a 349 // request out for this peer. 350 func (r *Reactor) RequestAddrs(p Peer) { 351 id := string(p.ID()) 352 if r.requestsSent.Has(id) { 353 return 354 } 355 r.Logger.Debug("Request addrs", "from", p) 356 r.requestsSent.Set(id, struct{}{}) 357 p.Send(PexChannel, mustEncode(&tmp2p.PexRequest{})) 358 } 359 360 // ReceiveAddrs adds the given addrs to the addrbook if theres an open 361 // request for this peer and deletes the open request. 362 // If there's no open request for the src peer, it returns an error. 363 func (r *Reactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error { 364 id := string(src.ID()) 365 if !r.requestsSent.Has(id) { 366 return ErrUnsolicitedList 367 } 368 r.requestsSent.Delete(id) 369 370 srcAddr, err := src.NodeInfo().NetAddress() 371 if err != nil { 372 return err 373 } 374 375 srcIsSeed := false 376 for _, seedAddr := range r.seedAddrs { 377 if seedAddr.Equals(srcAddr) { 378 srcIsSeed = true 379 break 380 } 381 } 382 383 for _, netAddr := range addrs { 384 // NOTE: we check netAddr validity and routability in book#AddAddress. 385 err = r.book.AddAddress(netAddr, srcAddr) 386 if err != nil { 387 r.logErrAddrBook(err) 388 // XXX: should we be strict about incoming data and disconnect from a 389 // peer here too? 390 continue 391 } 392 393 // If this address came from a seed node, try to connect to it without 394 // waiting (#2093) 395 if srcIsSeed { 396 r.Logger.Info("Will dial address, which came from seed", "addr", netAddr, "seed", srcAddr) 397 go func(addr *p2p.NetAddress) { 398 err := r.dialPeer(addr) 399 if err != nil { 400 switch err.(type) { 401 case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress: 402 r.Logger.Debug(err.Error(), "addr", addr) 403 default: 404 r.Logger.Error(err.Error(), "addr", addr) 405 } 406 } 407 }(netAddr) 408 } 409 } 410 411 return nil 412 } 413 414 // SendAddrs sends addrs to the peer. 415 func (r *Reactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) { 416 p.Send(PexChannel, mustEncode(&tmp2p.PexResponse{Addresses: NetAddressesToProto(netAddrs)})) 417 } 418 419 // SetEnsurePeersPeriod sets period to ensure peers connected. 420 func (r *Reactor) SetEnsurePeersPeriod(d time.Duration) { 421 r.ensurePeersPeriod = d 422 } 423 424 // Ensures that sufficient peers are connected. (continuous) 425 func (r *Reactor) ensurePeersRoutine() { 426 var ( 427 seed = tmrand.NewRand() 428 jitter = seed.Int63n(r.ensurePeersPeriod.Nanoseconds()) 429 ) 430 431 // Randomize first round of communication to avoid thundering herd. 432 // If no peers are present directly start connecting so we guarantee swift 433 // setup with the help of configured seeds. 434 if r.nodeHasSomePeersOrDialingAny() { 435 time.Sleep(time.Duration(jitter)) 436 } 437 438 // fire once immediately. 439 // ensures we dial the seeds right away if the book is empty 440 r.ensurePeers() 441 442 // fire periodically 443 ticker := time.NewTicker(r.ensurePeersPeriod) 444 for { 445 select { 446 case <-ticker.C: 447 r.ensurePeers() 448 case <-r.Quit(): 449 ticker.Stop() 450 return 451 } 452 } 453 } 454 455 // ensurePeers ensures that sufficient peers are connected. (once) 456 // 457 // heuristic that we haven't perfected yet, or, perhaps is manually edited by 458 // the node operator. It should not be used to compute what addresses are 459 // already connected or not. 460 func (r *Reactor) ensurePeers() { 461 var ( 462 out, in, dial = r.Switch.NumPeers() 463 numToDial = r.Switch.MaxNumOutboundPeers() - (out + dial) 464 ) 465 r.Logger.Info( 466 "Ensure peers", 467 "numOutPeers", out, 468 "numInPeers", in, 469 "numDialing", dial, 470 "numToDial", numToDial, 471 ) 472 473 if numToDial <= 0 { 474 return 475 } 476 477 // bias to prefer more vetted peers when we have fewer connections. 478 // not perfect, but somewhate ensures that we prioritize connecting to more-vetted 479 // NOTE: range here is [10, 90]. Too high ? 480 newBias := tmmath.MinInt(out, 8)*10 + 10 481 482 toDial := make(map[types.NodeID]*p2p.NetAddress) 483 // Try maxAttempts times to pick numToDial addresses to dial 484 maxAttempts := numToDial * 3 485 486 for i := 0; i < maxAttempts && len(toDial) < numToDial; i++ { 487 try := r.book.PickAddress(newBias) 488 if try == nil { 489 continue 490 } 491 if _, selected := toDial[try.ID]; selected { 492 continue 493 } 494 if r.Switch.IsDialingOrExistingAddress(try) { 495 continue 496 } 497 // TODO: consider moving some checks from toDial into here 498 // so we don't even consider dialing peers that we want to wait 499 // before dialing again, or have dialed too many times already 500 r.Logger.Info("Will dial address", "addr", try) 501 toDial[try.ID] = try 502 } 503 504 // Dial picked addresses 505 for _, addr := range toDial { 506 go func(addr *p2p.NetAddress) { 507 err := r.dialPeer(addr) 508 if err != nil { 509 switch err.(type) { 510 case errMaxAttemptsToDial, errTooEarlyToDial: 511 r.Logger.Debug(err.Error(), "addr", addr) 512 default: 513 r.Logger.Error(err.Error(), "addr", addr) 514 } 515 } 516 }(addr) 517 } 518 519 if r.book.NeedMoreAddrs() { 520 // Check if banned nodes can be reinstated 521 r.book.ReinstateBadPeers() 522 } 523 524 if r.book.NeedMoreAddrs() { 525 526 // 1) Pick a random peer and ask for more. 527 peers := r.Switch.Peers().List() 528 peersCount := len(peers) 529 if peersCount > 0 { 530 rand := tmrand.NewRand() 531 peer := peers[rand.Int()%peersCount] 532 r.Logger.Info("We need more addresses. Sending pexRequest to random peer", "peer", peer) 533 r.RequestAddrs(peer) 534 } 535 536 // 2) Dial seeds if we are not dialing anyone. 537 // This is done in addition to asking a peer for addresses to work-around 538 // peers not participating in PEX. 539 if len(toDial) == 0 { 540 r.Logger.Info("No addresses to dial. Falling back to seeds") 541 r.dialSeeds() 542 } 543 } 544 } 545 546 func (r *Reactor) dialAttemptsInfo(addr *p2p.NetAddress) (attempts int, lastDialed time.Time) { 547 _attempts, ok := r.attemptsToDial.Load(addr.DialString()) 548 if !ok { 549 return 550 } 551 atd := _attempts.(_attemptsToDial) 552 return atd.number, atd.lastDialed 553 } 554 555 func (r *Reactor) dialPeer(addr *p2p.NetAddress) error { 556 attempts, lastDialed := r.dialAttemptsInfo(addr) 557 if !r.Switch.IsPeerPersistent(addr) && attempts > maxAttemptsToDial { 558 r.book.MarkBad(addr, defaultBanTime) 559 return errMaxAttemptsToDial{} 560 } 561 562 // exponential backoff if it's not our first attempt to dial given address 563 if attempts > 0 { 564 rand := tmrand.NewRand() 565 jitter := time.Duration(rand.Float64() * float64(time.Second)) // 1s == (1e9 ns) 566 backoffDuration := jitter + ((1 << uint(attempts)) * time.Second) 567 backoffDuration = r.maxBackoffDurationForPeer(addr, backoffDuration) 568 sinceLastDialed := time.Since(lastDialed) 569 if sinceLastDialed < backoffDuration { 570 return errTooEarlyToDial{backoffDuration, lastDialed} 571 } 572 } 573 574 err := r.Switch.DialPeerWithAddress(addr) 575 if err != nil { 576 if _, ok := err.(p2p.ErrCurrentlyDialingOrExistingAddress); ok { 577 return err 578 } 579 580 markAddrInBookBasedOnErr(addr, r.book, err) 581 switch err.(type) { 582 case p2p.ErrSwitchAuthenticationFailure: 583 // NOTE: addr is removed from addrbook in markAddrInBookBasedOnErr 584 r.attemptsToDial.Delete(addr.DialString()) 585 default: 586 r.attemptsToDial.Store(addr.DialString(), _attemptsToDial{attempts + 1, time.Now()}) 587 } 588 return fmt.Errorf("dialing failed (attempts: %d): %w", attempts+1, err) 589 } 590 591 // cleanup any history 592 r.attemptsToDial.Delete(addr.DialString()) 593 return nil 594 } 595 596 // maxBackoffDurationForPeer caps the backoff duration for persistent peers. 597 func (r *Reactor) maxBackoffDurationForPeer(addr *p2p.NetAddress, planned time.Duration) time.Duration { 598 if r.config.PersistentPeersMaxDialPeriod > 0 && 599 planned > r.config.PersistentPeersMaxDialPeriod && 600 r.Switch.IsPeerPersistent(addr) { 601 return r.config.PersistentPeersMaxDialPeriod 602 } 603 return planned 604 } 605 606 // checkSeeds checks that addresses are well formed. 607 // Returns number of seeds we can connect to, along with all seeds addrs. 608 // return err if user provided any badly formatted seed addresses. 609 // Doesn't error if the seed node can't be reached. 610 // numOnline returns -1 if no seed nodes were in the initial configuration. 611 func (r *Reactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, err error) { 612 lSeeds := len(r.config.Seeds) 613 if lSeeds == 0 { 614 return -1, nil, nil 615 } 616 netAddrs, errs := p2p.NewNetAddressStrings(r.config.Seeds) 617 numOnline = lSeeds - len(errs) 618 for _, err := range errs { 619 switch e := err.(type) { 620 case types.ErrNetAddressLookup: 621 r.Logger.Error("Connecting to seed failed", "err", e) 622 default: 623 return 0, nil, fmt.Errorf("seed node configuration has error: %w", e) 624 } 625 } 626 return numOnline, netAddrs, nil 627 } 628 629 // randomly dial seeds until we connect to one or exhaust them 630 func (r *Reactor) dialSeeds() { 631 rand := tmrand.NewRand() 632 perm := rand.Perm(len(r.seedAddrs)) 633 // perm := r.Switch.rng.Perm(lSeeds) 634 for _, i := range perm { 635 // dial a random seed 636 seedAddr := r.seedAddrs[i] 637 err := r.Switch.DialPeerWithAddress(seedAddr) 638 639 switch err.(type) { 640 case nil, p2p.ErrCurrentlyDialingOrExistingAddress: 641 return 642 } 643 r.Switch.Logger.Error("Error dialing seed", "err", err, "seed", seedAddr) 644 } 645 // do not write error message if there were no seeds specified in config 646 if len(r.seedAddrs) > 0 { 647 r.Switch.Logger.Error("Couldn't connect to any seeds") 648 } 649 } 650 651 // AttemptsToDial returns the number of attempts to dial specific address. It 652 // returns 0 if never attempted or successfully connected. 653 func (r *Reactor) AttemptsToDial(addr *p2p.NetAddress) int { 654 lAttempts, attempted := r.attemptsToDial.Load(addr.DialString()) 655 if attempted { 656 return lAttempts.(_attemptsToDial).number 657 } 658 return 0 659 } 660 661 //---------------------------------------------------------- 662 663 // Explores the network searching for more peers. (continuous) 664 // Seed/Crawler Mode causes this node to quickly disconnect 665 // from peers, except other seed nodes. 666 func (r *Reactor) crawlPeersRoutine() { 667 // If we have any seed nodes, consult them first 668 if len(r.seedAddrs) > 0 { 669 r.dialSeeds() 670 } else { 671 // Do an initial crawl 672 r.crawlPeers(r.book.GetSelection()) 673 } 674 675 // Fire periodically 676 ticker := time.NewTicker(crawlPeerPeriod) 677 678 for { 679 select { 680 case <-ticker.C: 681 r.attemptDisconnects() 682 r.crawlPeers(r.book.GetSelection()) 683 r.cleanupCrawlPeerInfos() 684 case <-r.Quit(): 685 return 686 } 687 } 688 } 689 690 // nodeHasSomePeersOrDialingAny returns true if the node is connected to some 691 // peers or dialing them currently. 692 func (r *Reactor) nodeHasSomePeersOrDialingAny() bool { 693 out, in, dial := r.Switch.NumPeers() 694 return out+in+dial > 0 695 } 696 697 // crawlPeerInfo handles temporary data needed for the network crawling 698 // performed during seed/crawler mode. 699 type crawlPeerInfo struct { 700 Addr *p2p.NetAddress `json:"addr"` 701 // The last time we crawled the peer or attempted to do so. 702 LastCrawled time.Time `json:"last_crawled"` 703 } 704 705 // crawlPeers will crawl the network looking for new peer addresses. 706 func (r *Reactor) crawlPeers(addrs []*p2p.NetAddress) { 707 now := time.Now() 708 709 for _, addr := range addrs { 710 peerInfo, ok := r.crawlPeerInfos[addr.ID] 711 712 // Do not attempt to connect with peers we recently crawled. 713 if ok && now.Sub(peerInfo.LastCrawled) < minTimeBetweenCrawls { 714 continue 715 } 716 717 // Record crawling attempt. 718 r.crawlPeerInfos[addr.ID] = crawlPeerInfo{ 719 Addr: addr, 720 LastCrawled: now, 721 } 722 723 err := r.dialPeer(addr) 724 if err != nil { 725 switch err.(type) { 726 case errMaxAttemptsToDial, errTooEarlyToDial, p2p.ErrCurrentlyDialingOrExistingAddress: 727 r.Logger.Debug(err.Error(), "addr", addr) 728 default: 729 r.Logger.Error(err.Error(), "addr", addr) 730 } 731 continue 732 } 733 734 peer := r.Switch.Peers().Get(addr.ID) 735 if peer != nil { 736 r.RequestAddrs(peer) 737 } 738 } 739 } 740 741 func (r *Reactor) cleanupCrawlPeerInfos() { 742 for id, info := range r.crawlPeerInfos { 743 // If we did not crawl a peer for 24 hours, it means the peer was removed 744 // from the addrbook => remove 745 // 746 // 10000 addresses / maxGetSelection = 40 cycles to get all addresses in 747 // the ideal case, 748 // 40 * crawlPeerPeriod ~ 20 minutes 749 if time.Since(info.LastCrawled) > 24*time.Hour { 750 delete(r.crawlPeerInfos, id) 751 } 752 } 753 } 754 755 // attemptDisconnects checks if we've been with each peer long enough to disconnect 756 func (r *Reactor) attemptDisconnects() { 757 for _, peer := range r.Switch.Peers().List() { 758 if peer.Status().Duration < r.config.SeedDisconnectWaitPeriod { 759 continue 760 } 761 if peer.IsPersistent() { 762 continue 763 } 764 r.Switch.StopPeerGracefully(peer) 765 } 766 } 767 768 func markAddrInBookBasedOnErr(addr *p2p.NetAddress, book AddrBook, err error) { 769 // TODO: detect more "bad peer" scenarios 770 switch err.(type) { 771 case p2p.ErrSwitchAuthenticationFailure: 772 book.MarkBad(addr, defaultBanTime) 773 default: 774 book.MarkAttempt(addr) 775 } 776 } 777 778 //----------------------------------------------------------------------------- 779 // Messages 780 781 // mustEncode proto encodes a tmp2p.Message 782 func mustEncode(pb proto.Message) []byte { 783 msg := tmp2p.PexMessage{} 784 switch pb := pb.(type) { 785 case *tmp2p.PexRequest: 786 msg.Sum = &tmp2p.PexMessage_PexRequest{PexRequest: pb} 787 case *tmp2p.PexResponse: 788 msg.Sum = &tmp2p.PexMessage_PexResponse{PexResponse: pb} 789 default: 790 panic(fmt.Sprintf("Unknown message type %T", pb)) 791 } 792 793 bz, err := msg.Marshal() 794 if err != nil { 795 panic(fmt.Errorf("unable to marshal %T: %w", pb, err)) 796 } 797 return bz 798 } 799 800 func decodeMsg(bz []byte) (proto.Message, error) { 801 pb := &tmp2p.PexMessage{} 802 803 err := pb.Unmarshal(bz) 804 if err != nil { 805 return nil, err 806 } 807 808 switch msg := pb.Sum.(type) { 809 case *tmp2p.PexMessage_PexRequest: 810 return msg.PexRequest, nil 811 case *tmp2p.PexMessage_PexResponse: 812 return msg.PexResponse, nil 813 default: 814 return nil, fmt.Errorf("unknown message: %T", msg) 815 } 816 } 817 818 //----------------------------------------------------------------------------- 819 // address converters 820 821 // NetAddressFromProto converts a Protobuf PexAddress into a native struct. 822 func NetAddressFromProto(pb tmp2p.PexAddress) (*types.NetAddress, error) { 823 ip := net.ParseIP(pb.IP) 824 if ip == nil { 825 return nil, fmt.Errorf("invalid IP address %v", pb.IP) 826 } 827 if pb.Port >= 1<<16 { 828 return nil, fmt.Errorf("invalid port number %v", pb.Port) 829 } 830 return &types.NetAddress{ 831 ID: types.NodeID(pb.ID), 832 IP: ip, 833 Port: uint16(pb.Port), 834 }, nil 835 } 836 837 // NetAddressesFromProto converts a slice of Protobuf PexAddresses into a native slice. 838 func NetAddressesFromProto(pbs []tmp2p.PexAddress) ([]*types.NetAddress, error) { 839 nas := make([]*types.NetAddress, 0, len(pbs)) 840 for _, pb := range pbs { 841 na, err := NetAddressFromProto(pb) 842 if err != nil { 843 return nil, err 844 } 845 nas = append(nas, na) 846 } 847 return nas, nil 848 } 849 850 // NetAddressesToProto converts a slice of NetAddresses into a Protobuf PexAddress slice. 851 func NetAddressesToProto(nas []*types.NetAddress) []tmp2p.PexAddress { 852 pbs := make([]tmp2p.PexAddress, 0, len(nas)) 853 for _, na := range nas { 854 if na != nil { 855 pbs = append(pbs, tmp2p.PexAddress{ 856 ID: string(na.ID), 857 IP: na.IP.String(), 858 Port: uint32(na.Port), 859 }) 860 } 861 } 862 return pbs 863 }