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