github.com/core-coin/go-core/v2@v2.1.9/p2p/discover/table_util_test.go (about) 1 // Copyright 2018 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 "bytes" 21 "encoding/hex" 22 "errors" 23 "fmt" 24 "math/rand" 25 "net" 26 "sort" 27 "sync" 28 29 "github.com/core-coin/go-core/v2/crypto" 30 "github.com/core-coin/go-core/v2/log" 31 "github.com/core-coin/go-core/v2/p2p/enode" 32 "github.com/core-coin/go-core/v2/p2p/enr" 33 ) 34 35 var nullNode *enode.Node 36 37 func init() { 38 var r enr.Record 39 r.Set(enr.IP{0, 0, 0, 0}) 40 nullNode = enode.SignNull(&r, enode.ID{}) 41 } 42 43 func newTestTable(t transport) (*Table, *enode.DB) { 44 db, _ := enode.OpenDB("") 45 tab, _ := newTable(t, db, nil, log.Root()) 46 go tab.loop() 47 return tab, db 48 } 49 50 // nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld. 51 func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { 52 var r enr.Record 53 r.Set(enr.IP(ip)) 54 return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) 55 } 56 57 // nodesAtDistance creates n nodes for which enode.LogDist(base, node.ID()) == ld. 58 func nodesAtDistance(base enode.ID, ld int, n int) []*enode.Node { 59 results := make([]*enode.Node, n) 60 for i := range results { 61 results[i] = unwrapNode(nodeAtDistance(base, ld, intIP(i))) 62 } 63 return results 64 } 65 66 func nodesToRecords(nodes []*enode.Node) []*enr.Record { 67 records := make([]*enr.Record, len(nodes)) 68 for i := range nodes { 69 records[i] = nodes[i].Record() 70 } 71 return records 72 } 73 74 // idAtDistance returns a random hash such that enode.LogDist(a, b) == n 75 func idAtDistance(a enode.ID, n int) (b enode.ID) { 76 if n == 0 { 77 return a 78 } 79 // flip bit at position n, fill the rest with random bits 80 b = a 81 pos := len(a) - n/8 - 1 82 bit := byte(0x01) << (byte(n%8) - 1) 83 if bit == 0 { 84 pos++ 85 bit = 0x80 86 } 87 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 88 for i := pos + 1; i < len(a); i++ { 89 b[i] = byte(rand.Intn(255)) 90 } 91 return b 92 } 93 94 func intIP(i int) net.IP { 95 return net.IP{byte(i), 0, 2, byte(i)} 96 } 97 98 // fillBucket inserts nodes into the given bucket until it is full. 99 func fillBucket(tab *Table, n *node) (last *node) { 100 ld := enode.LogDist(tab.self().ID(), n.ID()) 101 b := tab.bucket(n.ID()) 102 for len(b.entries) < bucketSize { 103 b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld))) 104 } 105 return b.entries[bucketSize-1] 106 } 107 108 // fillTable adds nodes the table to the end of their corresponding bucket 109 // if the bucket is not full. The caller must not hold tab.mutex. 110 func fillTable(tab *Table, nodes []*node) { 111 for _, n := range nodes { 112 tab.addSeenNode(n) 113 } 114 } 115 116 type pingRecorder struct { 117 mu sync.Mutex 118 dead, pinged map[enode.ID]bool 119 records map[enode.ID]*enode.Node 120 n *enode.Node 121 } 122 123 func newPingRecorder() *pingRecorder { 124 var r enr.Record 125 r.Set(enr.IP{0, 0, 0, 0}) 126 n := enode.SignNull(&r, enode.ID{}) 127 128 return &pingRecorder{ 129 dead: make(map[enode.ID]bool), 130 pinged: make(map[enode.ID]bool), 131 records: make(map[enode.ID]*enode.Node), 132 n: n, 133 } 134 } 135 136 // setRecord updates a node record. Future calls to ping and 137 // requestENR will return this record. 138 func (t *pingRecorder) updateRecord(n *enode.Node) { 139 t.mu.Lock() 140 defer t.mu.Unlock() 141 t.records[n.ID()] = n 142 } 143 144 // Stubs to satisfy the transport interface. 145 func (t *pingRecorder) Self() *enode.Node { return nullNode } 146 func (t *pingRecorder) lookupSelf() []*enode.Node { return nil } 147 func (t *pingRecorder) lookupRandom() []*enode.Node { return nil } 148 149 // ping simulates a ping request. 150 func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { 151 t.mu.Lock() 152 defer t.mu.Unlock() 153 154 t.pinged[n.ID()] = true 155 if t.dead[n.ID()] { 156 return 0, errTimeout 157 } 158 if t.records[n.ID()] != nil { 159 seq = t.records[n.ID()].Seq() 160 } 161 return seq, nil 162 } 163 164 // requestENR simulates an ENR request. 165 func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { 166 t.mu.Lock() 167 defer t.mu.Unlock() 168 169 if t.dead[n.ID()] || t.records[n.ID()] == nil { 170 return nil, errTimeout 171 } 172 return t.records[n.ID()], nil 173 } 174 175 func hasDuplicates(slice []*node) bool { 176 seen := make(map[enode.ID]bool) 177 for i, e := range slice { 178 if e == nil { 179 panic(fmt.Sprintf("nil *Node at %d", i)) 180 } 181 if seen[e.ID()] { 182 return true 183 } 184 seen[e.ID()] = true 185 } 186 return false 187 } 188 189 // checkNodesEqual checks whether the two given node lists contain the same nodes. 190 func checkNodesEqual(got, want []*enode.Node) error { 191 if len(got) == len(want) { 192 for i := range got { 193 if !nodeEqual(got[i], want[i]) { 194 goto NotEqual 195 } 196 } 197 } 198 return nil 199 200 NotEqual: 201 output := new(bytes.Buffer) 202 fmt.Fprintf(output, "got %d nodes:\n", len(got)) 203 for _, n := range got { 204 fmt.Fprintf(output, " %v %v\n", n.ID(), n) 205 } 206 fmt.Fprintf(output, "want %d:\n", len(want)) 207 for _, n := range want { 208 fmt.Fprintf(output, " %v %v\n", n.ID(), n) 209 } 210 return errors.New(output.String()) 211 } 212 213 func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool { 214 return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP()) 215 } 216 217 func sortByID(nodes []*enode.Node) { 218 sort.Slice(nodes, func(i, j int) bool { 219 return string(nodes[i].ID().Bytes()) < string(nodes[j].ID().Bytes()) 220 }) 221 } 222 223 func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { 224 return sort.SliceIsSorted(slice, func(i, j int) bool { 225 return enode.DistCmp(distbase, slice[i].ID(), slice[j].ID()) < 0 226 }) 227 } 228 229 // hexEncPrivkey decodes h as a private key. 230 func hexEncPrivkey(h string) *crypto.PrivateKey { 231 b, err := hex.DecodeString(h) 232 if err != nil { 233 panic(err) 234 } 235 key, err := crypto.UnmarshalPrivateKey(b) 236 if err != nil { 237 panic(err) 238 } 239 return key 240 } 241 242 // hexEncPubkey decodes h as a public key. 243 func hexEncPubkey(h string) (ret encPubkey) { 244 b, err := hex.DecodeString(h) 245 if err != nil { 246 panic(err) 247 } 248 if len(b) != len(ret) { 249 panic("invalid length") 250 } 251 copy(ret[:], b) 252 return ret 253 }