github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/p2p/discover/table_util_test.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 18 19 import ( 20 "encoding/hex" 21 "fmt" 22 "math/rand" 23 "net" 24 "sync" 25 26 "github.com/ethereum/go-ethereum/p2p/enode" 27 "github.com/ethereum/go-ethereum/p2p/enr" 28 ) 29 30 var nullNode *enode.Node 31 32 func init() { 33 var r enr.Record 34 r.Set(enr.IP{0, 0, 0, 0}) 35 nullNode = enode.SignNull(&r, enode.ID{}) 36 } 37 38 func newTestTable(t transport) (*Table, *enode.DB) { 39 db, _ := enode.OpenDB("") 40 tab, _ := newTable(t, db, nil) 41 return tab, db 42 } 43 44 // nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld. 45 func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { 46 var r enr.Record 47 r.Set(enr.IP(ip)) 48 return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) 49 } 50 51 // idAtDistance returns a random hash such that enode.LogDist(a, b) == n 52 func idAtDistance(a enode.ID, n int) (b enode.ID) { 53 if n == 0 { 54 return a 55 } 56 // flip bit at position n, fill the rest with random bits 57 b = a 58 pos := len(a) - n/8 - 1 59 bit := byte(0x01) << (byte(n%8) - 1) 60 if bit == 0 { 61 pos++ 62 bit = 0x80 63 } 64 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 65 for i := pos + 1; i < len(a); i++ { 66 b[i] = byte(rand.Intn(255)) 67 } 68 return b 69 } 70 71 func intIP(i int) net.IP { 72 return net.IP{byte(i), 0, 2, byte(i)} 73 } 74 75 // fillBucket inserts nodes into the given bucket until it is full. 76 func fillBucket(tab *Table, n *node) (last *node) { 77 ld := enode.LogDist(tab.self().ID(), n.ID()) 78 b := tab.bucket(n.ID()) 79 for len(b.entries) < bucketSize { 80 b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld))) 81 } 82 return b.entries[bucketSize-1] 83 } 84 85 // fillTable adds nodes the table to the end of their corresponding bucket 86 // if the bucket is not full. The caller must not hold tab.mutex. 87 func fillTable(tab *Table, nodes []*node) { 88 for _, n := range nodes { 89 tab.addSeenNode(n) 90 } 91 } 92 93 type pingRecorder struct { 94 mu sync.Mutex 95 dead, pinged map[enode.ID]bool 96 n *enode.Node 97 } 98 99 func newPingRecorder() *pingRecorder { 100 var r enr.Record 101 r.Set(enr.IP{0, 0, 0, 0}) 102 n := enode.SignNull(&r, enode.ID{}) 103 104 return &pingRecorder{ 105 dead: make(map[enode.ID]bool), 106 pinged: make(map[enode.ID]bool), 107 n: n, 108 } 109 } 110 111 func (t *pingRecorder) self() *enode.Node { 112 return nullNode 113 } 114 115 func (t *pingRecorder) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) { 116 return nil, nil 117 } 118 119 func (t *pingRecorder) ping(toid enode.ID, toaddr *net.UDPAddr) error { 120 t.mu.Lock() 121 defer t.mu.Unlock() 122 123 t.pinged[toid] = true 124 if t.dead[toid] { 125 return errTimeout 126 } else { 127 return nil 128 } 129 } 130 131 func (t *pingRecorder) close() {} 132 133 func hasDuplicates(slice []*node) bool { 134 seen := make(map[enode.ID]bool) 135 for i, e := range slice { 136 if e == nil { 137 panic(fmt.Sprintf("nil *Node at %d", i)) 138 } 139 if seen[e.ID()] { 140 return true 141 } 142 seen[e.ID()] = true 143 } 144 return false 145 } 146 147 func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { 148 var last enode.ID 149 for i, e := range slice { 150 if i > 0 && enode.DistCmp(distbase, e.ID(), last) < 0 { 151 return false 152 } 153 last = e.ID() 154 } 155 return true 156 } 157 158 func hexEncPubkey(h string) (ret encPubkey) { 159 b, err := hex.DecodeString(h) 160 if err != nil { 161 panic(err) 162 } 163 if len(b) != len(ret) { 164 panic("invalid length") 165 } 166 copy(ret[:], b) 167 return ret 168 }