github.com/core-coin/go-core/v2@v2.1.9/p2p/discv5/sim_test.go (about) 1 // Copyright 2016 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 discv5 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 "math/rand" 23 "net" 24 "strconv" 25 "sync" 26 "sync/atomic" 27 "testing" 28 "time" 29 30 "github.com/core-coin/go-core/v2/common" 31 "github.com/core-coin/go-core/v2/crypto" 32 ) 33 34 // In this test, nodes try to randomly resolve each other. 35 func TestSimRandomResolve(t *testing.T) { 36 t.Skip("boring") 37 if runWithPlaygroundTime(t) { 38 return 39 } 40 41 sim := newSimulation() 42 bootnode := sim.launchNode(false) 43 44 // A new node joins every 10s. 45 launcher := time.NewTicker(10 * time.Second) 46 defer launcher.Stop() 47 go func() { 48 for range launcher.C { 49 net := sim.launchNode(false) 50 go randomResolves(t, sim, net) 51 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 52 panic(err) 53 } 54 t.Logf("launched @ %v: %x\n", time.Now(), net.Self().ID[:16]) 55 } 56 }() 57 58 time.Sleep(3 * time.Hour) 59 sim.shutdown() 60 sim.printStats() 61 } 62 63 func TestSimTopics(t *testing.T) { 64 t.Skip("NaCl test") 65 if runWithPlaygroundTime(t) { 66 return 67 } 68 sim := newSimulation() 69 bootnode := sim.launchNode(false) 70 71 go func() { 72 nets := make([]*Network, 1024) 73 for i := range nets { 74 net := sim.launchNode(false) 75 nets[i] = net 76 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 77 panic(err) 78 } 79 time.Sleep(time.Second * 5) 80 } 81 82 for i, net := range nets { 83 if i < 256 { 84 stop := make(chan struct{}) 85 go net.RegisterTopic(testTopic, stop) 86 go func() { 87 //time.Sleep(time.Second * 36000) 88 time.Sleep(time.Second * 40000) 89 close(stop) 90 }() 91 time.Sleep(time.Millisecond * 100) 92 } 93 // time.Sleep(time.Second * 10) 94 //time.Sleep(time.Second) 95 /*if i%500 == 499 { 96 time.Sleep(time.Second * 9501) 97 } else { 98 time.Sleep(time.Second) 99 }*/ 100 } 101 }() 102 103 // A new node joins every 10s. 104 /* launcher := time.NewTicker(5 * time.Second) 105 cnt := 0 106 var printNet *Network 107 go func() { 108 for range launcher.C { 109 cnt++ 110 if cnt <= 1000 { 111 log := false //(cnt == 500) 112 net := sim.launchNode(log) 113 if log { 114 printNet = net 115 } 116 if cnt > 500 { 117 go net.RegisterTopic(testTopic, nil) 118 } 119 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 120 panic(err) 121 } 122 } 123 //fmt.Printf("launched @ %v: %x\n", time.Now(), net.Self().ID[:16]) 124 } 125 }() 126 */ 127 time.Sleep(55000 * time.Second) 128 //launcher.Stop() 129 sim.shutdown() 130 //sim.printStats() 131 //printNet.log.printLogs() 132 } 133 134 /*func testHierarchicalTopics(i int) []Topic { 135 digits := strconv.FormatInt(int64(256+i/4), 4) 136 res := make([]Topic, 5) 137 for i, _ := range res { 138 res[i] = Topic("foo" + digits[1:i+1]) 139 } 140 return res 141 }*/ 142 143 func testHierarchicalTopics(i int) []Topic { 144 digits := strconv.FormatInt(int64(128+i/8), 2) 145 res := make([]Topic, 8) 146 for i := range res { 147 res[i] = Topic("foo" + digits[1:i+1]) 148 } 149 return res 150 } 151 152 func TestSimTopicHierarchy(t *testing.T) { 153 t.Skip("NaCl test") 154 if runWithPlaygroundTime(t) { 155 return 156 } 157 sim := newSimulation() 158 bootnode := sim.launchNode(false) 159 160 go func() { 161 nets := make([]*Network, 1024) 162 for i := range nets { 163 net := sim.launchNode(false) 164 nets[i] = net 165 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 166 panic(err) 167 } 168 time.Sleep(time.Second * 5) 169 } 170 171 stop := make(chan struct{}) 172 for i, net := range nets { 173 //if i < 256 { 174 for _, topic := range testHierarchicalTopics(i)[:5] { 175 //fmt.Println("reg", topic) 176 go net.RegisterTopic(topic, stop) 177 } 178 time.Sleep(time.Millisecond * 100) 179 //} 180 } 181 time.Sleep(time.Second * 90000) 182 close(stop) 183 }() 184 185 time.Sleep(100000 * time.Second) 186 sim.shutdown() 187 } 188 189 func randomResolves(t *testing.T, s *simulation, net *Network) { 190 randtime := func() time.Duration { 191 return time.Duration(rand.Intn(50)+20) * time.Second 192 } 193 lookup := func(target NodeID) bool { 194 result := net.Resolve(target) 195 return result != nil && result.ID == target 196 } 197 198 timer := time.NewTimer(randtime()) 199 defer timer.Stop() 200 for { 201 select { 202 case <-timer.C: 203 target := s.randomNode().Self().ID 204 if !lookup(target) { 205 t.Errorf("node %x: target %x not found", net.Self().ID[:8], target[:8]) 206 } 207 timer.Reset(randtime()) 208 case <-net.closed: 209 return 210 } 211 } 212 } 213 214 type simulation struct { 215 mu sync.RWMutex 216 nodes map[NodeID]*Network 217 nodectr uint32 218 } 219 220 func newSimulation() *simulation { 221 return &simulation{nodes: make(map[NodeID]*Network)} 222 } 223 224 func (s *simulation) shutdown() { 225 s.mu.RLock() 226 alive := make([]*Network, 0, len(s.nodes)) 227 for _, n := range s.nodes { 228 alive = append(alive, n) 229 } 230 defer s.mu.RUnlock() 231 232 for _, n := range alive { 233 n.Close() 234 } 235 } 236 237 func (s *simulation) printStats() { 238 s.mu.Lock() 239 defer s.mu.Unlock() 240 fmt.Println("node counter:", s.nodectr) 241 fmt.Println("alive nodes:", len(s.nodes)) 242 243 // for _, n := range s.nodes { 244 // fmt.Printf("%x\n", n.tab.self.ID[:8]) 245 // transport := n.conn.(*simTransport) 246 // fmt.Println(" joined:", transport.joinTime) 247 // fmt.Println(" sends:", transport.hashctr) 248 // fmt.Println(" table size:", n.tab.count) 249 // } 250 251 /*for _, n := range s.nodes { 252 fmt.Println() 253 fmt.Printf("*** Node %x\n", n.tab.self.ID[:8]) 254 n.log.printLogs() 255 }*/ 256 257 } 258 259 func (s *simulation) randomNode() *Network { 260 s.mu.Lock() 261 defer s.mu.Unlock() 262 263 n := rand.Intn(len(s.nodes)) 264 for _, net := range s.nodes { 265 if n == 0 { 266 return net 267 } 268 n-- 269 } 270 return nil 271 } 272 273 func (s *simulation) launchNode(log bool) *Network { 274 var ( 275 num = s.nodectr 276 key = newkey() 277 id = PubkeyID(key.PublicKey()) 278 ip = make(net.IP, 4) 279 ) 280 s.nodectr++ 281 binary.BigEndian.PutUint32(ip, num) 282 ip[0] = 10 283 addr := &net.UDPAddr{IP: ip, Port: 30300} 284 285 transport := &simTransport{joinTime: time.Now(), sender: id, senderAddr: addr, sim: s, priv: key} 286 net, err := newNetwork(transport, *key.PublicKey(), "<no database>", nil) 287 if err != nil { 288 panic("cannot launch new node: " + err.Error()) 289 } 290 291 s.mu.Lock() 292 s.nodes[id] = net 293 s.mu.Unlock() 294 295 return net 296 } 297 298 type simTransport struct { 299 joinTime time.Time 300 sender NodeID 301 senderAddr *net.UDPAddr 302 sim *simulation 303 hashctr uint64 304 priv *crypto.PrivateKey 305 } 306 307 func (st *simTransport) localAddr() *net.UDPAddr { 308 return st.senderAddr 309 } 310 311 func (st *simTransport) Close() {} 312 313 func (st *simTransport) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 314 hash = st.nextHash() 315 var raw []byte 316 if ptype == pongPacket { 317 var err error 318 raw, _, err = encodePacket(st.priv, byte(ptype), data) 319 if err != nil { 320 panic(err) 321 } 322 } 323 324 st.sendPacket(remote.ID, ingressPacket{ 325 remoteID: st.sender, 326 remoteAddr: st.senderAddr, 327 hash: hash, 328 ev: ptype, 329 data: data, 330 rawData: raw, 331 }) 332 return hash 333 } 334 335 func (st *simTransport) sendPing(remote *Node, remoteAddr *net.UDPAddr, topics []Topic) []byte { 336 hash := st.nextHash() 337 st.sendPacket(remote.ID, ingressPacket{ 338 remoteID: st.sender, 339 remoteAddr: st.senderAddr, 340 hash: hash, 341 ev: pingPacket, 342 data: &ping{ 343 Version: 4, 344 From: rpcEndpoint{IP: st.senderAddr.IP, UDP: uint16(st.senderAddr.Port), TCP: 30300}, 345 To: rpcEndpoint{IP: remoteAddr.IP, UDP: uint16(remoteAddr.Port), TCP: 30300}, 346 Expiration: uint64(time.Now().Unix() + int64(expiration)), 347 Topics: topics, 348 }, 349 }) 350 return hash 351 } 352 353 func (st *simTransport) sendFindnodeHash(remote *Node, target common.Hash) { 354 st.sendPacket(remote.ID, ingressPacket{ 355 remoteID: st.sender, 356 remoteAddr: st.senderAddr, 357 hash: st.nextHash(), 358 ev: findnodeHashPacket, 359 data: &findnodeHash{ 360 Target: target, 361 Expiration: uint64(time.Now().Unix() + int64(expiration)), 362 }, 363 }) 364 } 365 366 func (st *simTransport) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 367 //fmt.Println("send", topics, pong) 368 st.sendPacket(remote.ID, ingressPacket{ 369 remoteID: st.sender, 370 remoteAddr: st.senderAddr, 371 hash: st.nextHash(), 372 ev: topicRegisterPacket, 373 data: &topicRegister{ 374 Topics: topics, 375 Idx: uint(idx), 376 Pong: pong, 377 }, 378 }) 379 } 380 381 func (st *simTransport) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 382 rnodes := make([]rpcNode, len(nodes)) 383 for i := range nodes { 384 rnodes[i] = nodeToRPC(nodes[i]) 385 } 386 st.sendPacket(remote.ID, ingressPacket{ 387 remoteID: st.sender, 388 remoteAddr: st.senderAddr, 389 hash: st.nextHash(), 390 ev: topicNodesPacket, 391 data: &topicNodes{Echo: queryHash, Nodes: rnodes}, 392 }) 393 } 394 395 func (st *simTransport) sendNeighbours(remote *Node, nodes []*Node) { 396 // TODO: send multiple packets 397 rnodes := make([]rpcNode, len(nodes)) 398 for i := range nodes { 399 rnodes[i] = nodeToRPC(nodes[i]) 400 } 401 st.sendPacket(remote.ID, ingressPacket{ 402 remoteID: st.sender, 403 remoteAddr: st.senderAddr, 404 hash: st.nextHash(), 405 ev: neighborsPacket, 406 data: &neighbors{ 407 Nodes: rnodes, 408 Expiration: uint64(time.Now().Unix() + int64(expiration)), 409 }, 410 }) 411 } 412 413 func (st *simTransport) nextHash() []byte { 414 v := atomic.AddUint64(&st.hashctr, 1) 415 var hash common.Hash 416 binary.BigEndian.PutUint64(hash[:], v) 417 return hash[:] 418 } 419 420 const packetLoss = 0 // 1/1000 421 422 func (st *simTransport) sendPacket(remote NodeID, p ingressPacket) { 423 if rand.Int31n(1000) >= packetLoss { 424 st.sim.mu.RLock() 425 recipient := st.sim.nodes[remote] 426 st.sim.mu.RUnlock() 427 428 time.AfterFunc(200*time.Millisecond, func() { 429 recipient.reqReadPacket(p) 430 }) 431 } 432 }