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