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