github.com/phillinzzz/newBsc@v1.1.6/p2p/discover/table.go (about) 1 // Copyright 2015 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 discover implements the Node Discovery Protocol. 18 // 19 // The Node Discovery protocol provides a way to find RLPx nodes that 20 // can be connected to. It uses a Kademlia-like protocol to maintain a 21 // distributed database of the IDs and endpoints of all listening 22 // nodes. 23 package discover 24 25 import ( 26 crand "crypto/rand" 27 "encoding/binary" 28 "fmt" 29 mrand "math/rand" 30 "net" 31 "sort" 32 "sync" 33 "time" 34 35 "github.com/phillinzzz/newBsc/common" 36 "github.com/phillinzzz/newBsc/common/gopool" 37 "github.com/phillinzzz/newBsc/log" 38 "github.com/phillinzzz/newBsc/p2p/enode" 39 "github.com/phillinzzz/newBsc/p2p/netutil" 40 ) 41 42 const ( 43 alpha = 3 // Kademlia concurrency factor 44 bucketSize = 16 // Kademlia bucket size 45 maxReplacements = 10 // Size of per-bucket replacement list 46 47 // We keep buckets for the upper 1/15 of distances because 48 // it's very unlikely we'll ever encounter a node that's closer. 49 hashBits = len(common.Hash{}) * 8 50 nBuckets = hashBits / 15 // Number of buckets 51 bucketMinDistance = hashBits - nBuckets // Log distance of closest bucket 52 53 // IP address limits. 54 bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24 55 tableIPLimit, tableSubnet = 10, 24 56 57 refreshInterval = 30 * time.Minute 58 revalidateInterval = 10 * time.Second 59 copyNodesInterval = 30 * time.Second 60 seedMinTableTime = 5 * time.Minute 61 seedCount = 30 62 seedMaxAge = 5 * 24 * time.Hour 63 ) 64 65 // Table is the 'node table', a Kademlia-like index of neighbor nodes. The table keeps 66 // itself up-to-date by verifying the liveness of neighbors and requesting their node 67 // records when announcements of a new record version are received. 68 type Table struct { 69 mutex sync.Mutex // protects buckets, bucket content, nursery, rand 70 buckets [nBuckets]*bucket // index of known nodes by distance 71 nursery []*node // bootstrap nodes 72 rand *mrand.Rand // source of randomness, periodically reseeded 73 ips netutil.DistinctNetSet 74 75 log log.Logger 76 db *enode.DB // database of known nodes 77 net transport 78 refreshReq chan chan struct{} 79 initDone chan struct{} 80 closeReq chan struct{} 81 closed chan struct{} 82 83 nodeAddedHook func(*node) // for testing 84 } 85 86 // transport is implemented by the UDP transports. 87 type transport interface { 88 Self() *enode.Node 89 RequestENR(*enode.Node) (*enode.Node, error) 90 lookupRandom() []*enode.Node 91 lookupSelf() []*enode.Node 92 ping(*enode.Node) (seq uint64, err error) 93 } 94 95 // bucket contains nodes, ordered by their last activity. the entry 96 // that was most recently active is the first element in entries. 97 type bucket struct { 98 entries []*node // live entries, sorted by time of last contact 99 replacements []*node // recently seen nodes to be used if revalidation fails 100 ips netutil.DistinctNetSet 101 } 102 103 func newTable(t transport, db *enode.DB, bootnodes []*enode.Node, log log.Logger) (*Table, error) { 104 tab := &Table{ 105 net: t, 106 db: db, 107 refreshReq: make(chan chan struct{}), 108 initDone: make(chan struct{}), 109 closeReq: make(chan struct{}), 110 closed: make(chan struct{}), 111 rand: mrand.New(mrand.NewSource(0)), 112 ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, 113 log: log, 114 } 115 if err := tab.setFallbackNodes(bootnodes); err != nil { 116 return nil, err 117 } 118 for i := range tab.buckets { 119 tab.buckets[i] = &bucket{ 120 ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, 121 } 122 } 123 tab.seedRand() 124 tab.loadSeedNodes() 125 126 return tab, nil 127 } 128 129 func (tab *Table) self() *enode.Node { 130 return tab.net.Self() 131 } 132 133 func (tab *Table) seedRand() { 134 var b [8]byte 135 crand.Read(b[:]) 136 137 tab.mutex.Lock() 138 tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) 139 tab.mutex.Unlock() 140 } 141 142 // ReadRandomNodes fills the given slice with random nodes from the table. The results 143 // are guaranteed to be unique for a single invocation, no node will appear twice. 144 func (tab *Table) ReadRandomNodes(buf []*enode.Node) (n int) { 145 if !tab.isInitDone() { 146 return 0 147 } 148 tab.mutex.Lock() 149 defer tab.mutex.Unlock() 150 151 var nodes []*enode.Node 152 for _, b := range &tab.buckets { 153 for _, n := range b.entries { 154 nodes = append(nodes, unwrapNode(n)) 155 } 156 } 157 // Shuffle. 158 for i := 0; i < len(nodes); i++ { 159 j := tab.rand.Intn(len(nodes)) 160 nodes[i], nodes[j] = nodes[j], nodes[i] 161 } 162 return copy(buf, nodes) 163 } 164 165 // getNode returns the node with the given ID or nil if it isn't in the table. 166 func (tab *Table) getNode(id enode.ID) *enode.Node { 167 tab.mutex.Lock() 168 defer tab.mutex.Unlock() 169 170 b := tab.bucket(id) 171 for _, e := range b.entries { 172 if e.ID() == id { 173 return unwrapNode(e) 174 } 175 } 176 return nil 177 } 178 179 // close terminates the network listener and flushes the node database. 180 func (tab *Table) close() { 181 close(tab.closeReq) 182 <-tab.closed 183 } 184 185 // setFallbackNodes sets the initial points of contact. These nodes 186 // are used to connect to the network if the table is empty and there 187 // are no known nodes in the database. 188 func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { 189 for _, n := range nodes { 190 if err := n.ValidateComplete(); err != nil { 191 return fmt.Errorf("bad bootstrap node %q: %v", n, err) 192 } 193 } 194 tab.nursery = wrapNodes(nodes) 195 return nil 196 } 197 198 // isInitDone returns whether the table's initial seeding procedure has completed. 199 func (tab *Table) isInitDone() bool { 200 select { 201 case <-tab.initDone: 202 return true 203 default: 204 return false 205 } 206 } 207 208 func (tab *Table) refresh() <-chan struct{} { 209 done := make(chan struct{}) 210 select { 211 case tab.refreshReq <- done: 212 case <-tab.closeReq: 213 close(done) 214 } 215 return done 216 } 217 218 // loop schedules runs of doRefresh, doRevalidate and copyLiveNodes. 219 func (tab *Table) loop() { 220 var ( 221 revalidate = time.NewTimer(tab.nextRevalidateTime()) 222 refresh = time.NewTicker(refreshInterval) 223 copyNodes = time.NewTicker(copyNodesInterval) 224 refreshDone = make(chan struct{}) // where doRefresh reports completion 225 revalidateDone chan struct{} // where doRevalidate reports completion 226 waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs 227 ) 228 defer refresh.Stop() 229 defer revalidate.Stop() 230 defer copyNodes.Stop() 231 232 // Start initial refresh. 233 gopool.Submit(func() { 234 tab.doRefresh(refreshDone) 235 }) 236 loop: 237 for { 238 select { 239 case <-refresh.C: 240 tab.seedRand() 241 if refreshDone == nil { 242 refreshDone = make(chan struct{}) 243 gopool.Submit(func() { 244 tab.doRefresh(refreshDone) 245 }) 246 } 247 case req := <-tab.refreshReq: 248 waiting = append(waiting, req) 249 if refreshDone == nil { 250 refreshDone = make(chan struct{}) 251 gopool.Submit( 252 func() { 253 tab.doRefresh(refreshDone) 254 }) 255 } 256 case <-refreshDone: 257 for _, ch := range waiting { 258 close(ch) 259 } 260 waiting, refreshDone = nil, nil 261 case <-revalidate.C: 262 revalidateDone = make(chan struct{}) 263 gopool.Submit(func() { 264 tab.doRevalidate(revalidateDone) 265 }) 266 case <-revalidateDone: 267 revalidate.Reset(tab.nextRevalidateTime()) 268 revalidateDone = nil 269 case <-copyNodes.C: 270 gopool.Submit(func() { 271 tab.copyLiveNodes() 272 }) 273 274 case <-tab.closeReq: 275 break loop 276 } 277 } 278 279 if refreshDone != nil { 280 <-refreshDone 281 } 282 for _, ch := range waiting { 283 close(ch) 284 } 285 if revalidateDone != nil { 286 <-revalidateDone 287 } 288 close(tab.closed) 289 } 290 291 // doRefresh performs a lookup for a random target to keep buckets full. seed nodes are 292 // inserted if the table is empty (initial bootstrap or discarded faulty peers). 293 func (tab *Table) doRefresh(done chan struct{}) { 294 defer close(done) 295 296 // Load nodes from the database and insert 297 // them. This should yield a few previously seen nodes that are 298 // (hopefully) still alive. 299 tab.loadSeedNodes() 300 301 // Run self lookup to discover new neighbor nodes. 302 tab.net.lookupSelf() 303 304 // The Kademlia paper specifies that the bucket refresh should 305 // perform a lookup in the least recently used bucket. We cannot 306 // adhere to this because the findnode target is a 512bit value 307 // (not hash-sized) and it is not easily possible to generate a 308 // sha3 preimage that falls into a chosen bucket. 309 // We perform a few lookups with a random target instead. 310 for i := 0; i < 3; i++ { 311 tab.net.lookupRandom() 312 } 313 } 314 315 func (tab *Table) loadSeedNodes() { 316 seeds := wrapNodes(tab.db.QuerySeeds(seedCount, seedMaxAge)) 317 seeds = append(seeds, tab.nursery...) 318 for i := range seeds { 319 seed := seeds[i] 320 age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) }} 321 tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) 322 tab.addSeenNode(seed) 323 } 324 } 325 326 // doRevalidate checks that the last node in a random bucket is still live and replaces or 327 // deletes the node if it isn't. 328 func (tab *Table) doRevalidate(done chan<- struct{}) { 329 defer func() { done <- struct{}{} }() 330 331 last, bi := tab.nodeToRevalidate() 332 if last == nil { 333 // No non-empty bucket found. 334 return 335 } 336 337 // Ping the selected node and wait for a pong. 338 remoteSeq, err := tab.net.ping(unwrapNode(last)) 339 340 // Also fetch record if the node replied and returned a higher sequence number. 341 if last.Seq() < remoteSeq { 342 n, err := tab.net.RequestENR(unwrapNode(last)) 343 if err != nil { 344 tab.log.Debug("ENR request failed", "id", last.ID(), "addr", last.addr(), "err", err) 345 } else { 346 last = &node{Node: *n, addedAt: last.addedAt, livenessChecks: last.livenessChecks} 347 } 348 } 349 350 tab.mutex.Lock() 351 defer tab.mutex.Unlock() 352 b := tab.buckets[bi] 353 if err == nil { 354 // The node responded, move it to the front. 355 last.livenessChecks++ 356 tab.log.Debug("Revalidated node", "b", bi, "id", last.ID(), "checks", last.livenessChecks) 357 tab.bumpInBucket(b, last) 358 return 359 } 360 // No reply received, pick a replacement or delete the node if there aren't 361 // any replacements. 362 if r := tab.replace(b, last); r != nil { 363 tab.log.Debug("Replaced dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks, "r", r.ID(), "rip", r.IP()) 364 } else { 365 tab.log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks) 366 } 367 } 368 369 // nodeToRevalidate returns the last node in a random, non-empty bucket. 370 func (tab *Table) nodeToRevalidate() (n *node, bi int) { 371 tab.mutex.Lock() 372 defer tab.mutex.Unlock() 373 374 for _, bi = range tab.rand.Perm(len(tab.buckets)) { 375 b := tab.buckets[bi] 376 if len(b.entries) > 0 { 377 last := b.entries[len(b.entries)-1] 378 return last, bi 379 } 380 } 381 return nil, 0 382 } 383 384 func (tab *Table) nextRevalidateTime() time.Duration { 385 tab.mutex.Lock() 386 defer tab.mutex.Unlock() 387 388 return time.Duration(tab.rand.Int63n(int64(revalidateInterval))) 389 } 390 391 // copyLiveNodes adds nodes from the table to the database if they have been in the table 392 // longer than seedMinTableTime. 393 func (tab *Table) copyLiveNodes() { 394 tab.mutex.Lock() 395 defer tab.mutex.Unlock() 396 397 now := time.Now() 398 for _, b := range &tab.buckets { 399 for _, n := range b.entries { 400 if n.livenessChecks > 0 && now.Sub(n.addedAt) >= seedMinTableTime { 401 tab.db.UpdateNode(unwrapNode(n)) 402 } 403 } 404 } 405 } 406 407 // findnodeByID returns the n nodes in the table that are closest to the given id. 408 // This is used by the FINDNODE/v4 handler. 409 // 410 // The preferLive parameter says whether the caller wants liveness-checked results. If 411 // preferLive is true and the table contains any verified nodes, the result will not 412 // contain unverified nodes. However, if there are no verified nodes at all, the result 413 // will contain unverified nodes. 414 func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *nodesByDistance { 415 tab.mutex.Lock() 416 defer tab.mutex.Unlock() 417 418 // Scan all buckets. There might be a better way to do this, but there aren't that many 419 // buckets, so this solution should be fine. The worst-case complexity of this loop 420 // is O(tab.len() * nresults). 421 nodes := &nodesByDistance{target: target} 422 liveNodes := &nodesByDistance{target: target} 423 for _, b := range &tab.buckets { 424 for _, n := range b.entries { 425 nodes.push(n, nresults) 426 if preferLive && n.livenessChecks > 0 { 427 liveNodes.push(n, nresults) 428 } 429 } 430 } 431 432 if preferLive && len(liveNodes.entries) > 0 { 433 return liveNodes 434 } 435 return nodes 436 } 437 438 // len returns the number of nodes in the table. 439 func (tab *Table) len() (n int) { 440 tab.mutex.Lock() 441 defer tab.mutex.Unlock() 442 443 for _, b := range &tab.buckets { 444 n += len(b.entries) 445 } 446 return n 447 } 448 449 // bucketLen returns the number of nodes in the bucket for the given ID. 450 func (tab *Table) bucketLen(id enode.ID) int { 451 tab.mutex.Lock() 452 defer tab.mutex.Unlock() 453 454 return len(tab.bucket(id).entries) 455 } 456 457 // bucket returns the bucket for the given node ID hash. 458 func (tab *Table) bucket(id enode.ID) *bucket { 459 d := enode.LogDist(tab.self().ID(), id) 460 return tab.bucketAtDistance(d) 461 } 462 463 func (tab *Table) bucketAtDistance(d int) *bucket { 464 if d <= bucketMinDistance { 465 return tab.buckets[0] 466 } 467 return tab.buckets[d-bucketMinDistance-1] 468 } 469 470 // addSeenNode adds a node which may or may not be live to the end of a bucket. If the 471 // bucket has space available, adding the node succeeds immediately. Otherwise, the node is 472 // added to the replacements list. 473 // 474 // The caller must not hold tab.mutex. 475 func (tab *Table) addSeenNode(n *node) { 476 if n.ID() == tab.self().ID() { 477 return 478 } 479 480 tab.mutex.Lock() 481 defer tab.mutex.Unlock() 482 b := tab.bucket(n.ID()) 483 if contains(b.entries, n.ID()) { 484 // Already in bucket, don't add. 485 return 486 } 487 if len(b.entries) >= bucketSize { 488 // Bucket full, maybe add as replacement. 489 tab.addReplacement(b, n) 490 return 491 } 492 if !tab.addIP(b, n.IP()) { 493 // Can't add: IP limit reached. 494 return 495 } 496 // Add to end of bucket: 497 b.entries = append(b.entries, n) 498 b.replacements = deleteNode(b.replacements, n) 499 n.addedAt = time.Now() 500 if tab.nodeAddedHook != nil { 501 tab.nodeAddedHook(n) 502 } 503 } 504 505 // addVerifiedNode adds a node whose existence has been verified recently to the front of a 506 // bucket. If the node is already in the bucket, it is moved to the front. If the bucket 507 // has no space, the node is added to the replacements list. 508 // 509 // There is an additional safety measure: if the table is still initializing the node 510 // is not added. This prevents an attack where the table could be filled by just sending 511 // ping repeatedly. 512 // 513 // The caller must not hold tab.mutex. 514 func (tab *Table) addVerifiedNode(n *node) { 515 if !tab.isInitDone() { 516 return 517 } 518 if n.ID() == tab.self().ID() { 519 return 520 } 521 522 tab.mutex.Lock() 523 defer tab.mutex.Unlock() 524 b := tab.bucket(n.ID()) 525 if tab.bumpInBucket(b, n) { 526 // Already in bucket, moved to front. 527 return 528 } 529 if len(b.entries) >= bucketSize { 530 // Bucket full, maybe add as replacement. 531 tab.addReplacement(b, n) 532 return 533 } 534 if !tab.addIP(b, n.IP()) { 535 // Can't add: IP limit reached. 536 return 537 } 538 // Add to front of bucket. 539 b.entries, _ = pushNode(b.entries, n, bucketSize) 540 b.replacements = deleteNode(b.replacements, n) 541 n.addedAt = time.Now() 542 if tab.nodeAddedHook != nil { 543 tab.nodeAddedHook(n) 544 } 545 } 546 547 // delete removes an entry from the node table. It is used to evacuate dead nodes. 548 func (tab *Table) delete(node *node) { 549 tab.mutex.Lock() 550 defer tab.mutex.Unlock() 551 552 tab.deleteInBucket(tab.bucket(node.ID()), node) 553 } 554 555 func (tab *Table) addIP(b *bucket, ip net.IP) bool { 556 if len(ip) == 0 { 557 return false // Nodes without IP cannot be added. 558 } 559 if netutil.IsLAN(ip) { 560 return true 561 } 562 if !tab.ips.Add(ip) { 563 tab.log.Debug("IP exceeds table limit", "ip", ip) 564 return false 565 } 566 if !b.ips.Add(ip) { 567 tab.log.Debug("IP exceeds bucket limit", "ip", ip) 568 tab.ips.Remove(ip) 569 return false 570 } 571 return true 572 } 573 574 func (tab *Table) removeIP(b *bucket, ip net.IP) { 575 if netutil.IsLAN(ip) { 576 return 577 } 578 tab.ips.Remove(ip) 579 b.ips.Remove(ip) 580 } 581 582 func (tab *Table) addReplacement(b *bucket, n *node) { 583 for _, e := range b.replacements { 584 if e.ID() == n.ID() { 585 return // already in list 586 } 587 } 588 if !tab.addIP(b, n.IP()) { 589 return 590 } 591 var removed *node 592 b.replacements, removed = pushNode(b.replacements, n, maxReplacements) 593 if removed != nil { 594 tab.removeIP(b, removed.IP()) 595 } 596 } 597 598 // replace removes n from the replacement list and replaces 'last' with it if it is the 599 // last entry in the bucket. If 'last' isn't the last entry, it has either been replaced 600 // with someone else or became active. 601 func (tab *Table) replace(b *bucket, last *node) *node { 602 if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID() != last.ID() { 603 // Entry has moved, don't replace it. 604 return nil 605 } 606 // Still the last entry. 607 if len(b.replacements) == 0 { 608 tab.deleteInBucket(b, last) 609 return nil 610 } 611 r := b.replacements[tab.rand.Intn(len(b.replacements))] 612 b.replacements = deleteNode(b.replacements, r) 613 b.entries[len(b.entries)-1] = r 614 tab.removeIP(b, last.IP()) 615 return r 616 } 617 618 // bumpInBucket moves the given node to the front of the bucket entry list 619 // if it is contained in that list. 620 func (tab *Table) bumpInBucket(b *bucket, n *node) bool { 621 for i := range b.entries { 622 if b.entries[i].ID() == n.ID() { 623 if !n.IP().Equal(b.entries[i].IP()) { 624 // Endpoint has changed, ensure that the new IP fits into table limits. 625 tab.removeIP(b, b.entries[i].IP()) 626 if !tab.addIP(b, n.IP()) { 627 // It doesn't, put the previous one back. 628 tab.addIP(b, b.entries[i].IP()) 629 return false 630 } 631 } 632 // Move it to the front. 633 copy(b.entries[1:], b.entries[:i]) 634 b.entries[0] = n 635 return true 636 } 637 } 638 return false 639 } 640 641 func (tab *Table) deleteInBucket(b *bucket, n *node) { 642 b.entries = deleteNode(b.entries, n) 643 tab.removeIP(b, n.IP()) 644 } 645 646 func contains(ns []*node, id enode.ID) bool { 647 for _, n := range ns { 648 if n.ID() == id { 649 return true 650 } 651 } 652 return false 653 } 654 655 // pushNode adds n to the front of list, keeping at most max items. 656 func pushNode(list []*node, n *node, max int) ([]*node, *node) { 657 if len(list) < max { 658 list = append(list, nil) 659 } 660 removed := list[len(list)-1] 661 copy(list[1:], list) 662 list[0] = n 663 return list, removed 664 } 665 666 // deleteNode removes n from list. 667 func deleteNode(list []*node, n *node) []*node { 668 for i := range list { 669 if list[i].ID() == n.ID() { 670 return append(list[:i], list[i+1:]...) 671 } 672 } 673 return list 674 } 675 676 // nodesByDistance is a list of nodes, ordered by distance to target. 677 type nodesByDistance struct { 678 entries []*node 679 target enode.ID 680 } 681 682 // push adds the given node to the list, keeping the total size below maxElems. 683 func (h *nodesByDistance) push(n *node, maxElems int) { 684 ix := sort.Search(len(h.entries), func(i int) bool { 685 return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 686 }) 687 if len(h.entries) < maxElems { 688 h.entries = append(h.entries, n) 689 } 690 if ix == len(h.entries) { 691 // farther away than all nodes we already have. 692 // if there was room for it, the node is now the last element. 693 } else { 694 // slide existing entries down to make room 695 // this will overwrite the entry we just appended. 696 copy(h.entries[ix+1:], h.entries[ix:]) 697 h.entries[ix] = n 698 } 699 }