github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/discv5/sim_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package discv5 19 20 import ( 21 "crypto/ecdsa" 22 "encoding/binary" 23 "fmt" 24 "math/rand" 25 "net" 26 "strconv" 27 "sync" 28 "sync/atomic" 29 "testing" 30 "time" 31 32 "github.com/AigarNetwork/aigar/common" 33 ) 34 35 // In this test, nodes try to randomly resolve each other. 36 func TestSimRandomResolve(t *testing.T) { 37 t.Skip("boring") 38 if runWithPlaygroundTime(t) { 39 return 40 } 41 42 sim := newSimulation() 43 bootnode := sim.launchNode(false) 44 45 // A new node joins every 10s. 46 launcher := time.NewTicker(10 * time.Second) 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 launcher.Stop() 60 sim.shutdown() 61 sim.printStats() 62 } 63 64 func TestSimTopics(t *testing.T) { 65 t.Skip("NaCl test") 66 if runWithPlaygroundTime(t) { 67 return 68 } 69 sim := newSimulation() 70 bootnode := sim.launchNode(false) 71 72 go func() { 73 nets := make([]*Network, 1024) 74 for i := range nets { 75 net := sim.launchNode(false) 76 nets[i] = net 77 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 78 panic(err) 79 } 80 time.Sleep(time.Second * 5) 81 } 82 83 for i, net := range nets { 84 if i < 256 { 85 stop := make(chan struct{}) 86 go net.RegisterTopic(testTopic, stop) 87 go func() { 88 //time.Sleep(time.Second * 36000) 89 time.Sleep(time.Second * 40000) 90 close(stop) 91 }() 92 time.Sleep(time.Millisecond * 100) 93 } 94 // time.Sleep(time.Second * 10) 95 //time.Sleep(time.Second) 96 /*if i%500 == 499 { 97 time.Sleep(time.Second * 9501) 98 } else { 99 time.Sleep(time.Second) 100 }*/ 101 } 102 }() 103 104 // A new node joins every 10s. 105 /* launcher := time.NewTicker(5 * time.Second) 106 cnt := 0 107 var printNet *Network 108 go func() { 109 for range launcher.C { 110 cnt++ 111 if cnt <= 1000 { 112 log := false //(cnt == 500) 113 net := sim.launchNode(log) 114 if log { 115 printNet = net 116 } 117 if cnt > 500 { 118 go net.RegisterTopic(testTopic, nil) 119 } 120 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 121 panic(err) 122 } 123 } 124 //fmt.Printf("launched @ %v: %x\n", time.Now(), net.Self().ID[:16]) 125 } 126 }() 127 */ 128 time.Sleep(55000 * time.Second) 129 //launcher.Stop() 130 sim.shutdown() 131 //sim.printStats() 132 //printNet.log.printLogs() 133 } 134 135 /*func testHierarchicalTopics(i int) []Topic { 136 digits := strconv.FormatInt(int64(256+i/4), 4) 137 res := make([]Topic, 5) 138 for i, _ := range res { 139 res[i] = Topic("foo" + digits[1:i+1]) 140 } 141 return res 142 }*/ 143 144 func testHierarchicalTopics(i int) []Topic { 145 digits := strconv.FormatInt(int64(128+i/8), 2) 146 res := make([]Topic, 8) 147 for i := range res { 148 res[i] = Topic("foo" + digits[1:i+1]) 149 } 150 return res 151 } 152 153 func TestSimTopicHierarchy(t *testing.T) { 154 t.Skip("NaCl test") 155 if runWithPlaygroundTime(t) { 156 return 157 } 158 sim := newSimulation() 159 bootnode := sim.launchNode(false) 160 161 go func() { 162 nets := make([]*Network, 1024) 163 for i := range nets { 164 net := sim.launchNode(false) 165 nets[i] = net 166 if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { 167 panic(err) 168 } 169 time.Sleep(time.Second * 5) 170 } 171 172 stop := make(chan struct{}) 173 for i, net := range nets { 174 //if i < 256 { 175 for _, topic := range testHierarchicalTopics(i)[:5] { 176 //fmt.Println("reg", topic) 177 go net.RegisterTopic(topic, stop) 178 } 179 time.Sleep(time.Millisecond * 100) 180 //} 181 } 182 time.Sleep(time.Second * 90000) 183 close(stop) 184 }() 185 186 time.Sleep(100000 * time.Second) 187 sim.shutdown() 188 } 189 190 func randomResolves(t *testing.T, s *simulation, net *Network) { 191 randtime := func() time.Duration { 192 return time.Duration(rand.Intn(50)+20) * time.Second 193 } 194 lookup := func(target NodeID) bool { 195 result := net.Resolve(target) 196 return result != nil && result.ID == target 197 } 198 199 timer := time.NewTimer(randtime()) 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: 30303} 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 func (s *simulation) dropNode(id NodeID) { 299 s.mu.Lock() 300 n := s.nodes[id] 301 delete(s.nodes, id) 302 s.mu.Unlock() 303 304 n.Close() 305 } 306 307 type simTransport struct { 308 joinTime time.Time 309 sender NodeID 310 senderAddr *net.UDPAddr 311 sim *simulation 312 hashctr uint64 313 priv *ecdsa.PrivateKey 314 } 315 316 func (st *simTransport) localAddr() *net.UDPAddr { 317 return st.senderAddr 318 } 319 320 func (st *simTransport) Close() {} 321 322 func (st *simTransport) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 323 hash = st.nextHash() 324 var raw []byte 325 if ptype == pongPacket { 326 var err error 327 raw, _, err = encodePacket(st.priv, byte(ptype), data) 328 if err != nil { 329 panic(err) 330 } 331 } 332 333 st.sendPacket(remote.ID, ingressPacket{ 334 remoteID: st.sender, 335 remoteAddr: st.senderAddr, 336 hash: hash, 337 ev: ptype, 338 data: data, 339 rawData: raw, 340 }) 341 return hash 342 } 343 344 func (st *simTransport) sendPing(remote *Node, remoteAddr *net.UDPAddr, topics []Topic) []byte { 345 hash := st.nextHash() 346 st.sendPacket(remote.ID, ingressPacket{ 347 remoteID: st.sender, 348 remoteAddr: st.senderAddr, 349 hash: hash, 350 ev: pingPacket, 351 data: &ping{ 352 Version: 4, 353 From: rpcEndpoint{IP: st.senderAddr.IP, UDP: uint16(st.senderAddr.Port), TCP: 30303}, 354 To: rpcEndpoint{IP: remoteAddr.IP, UDP: uint16(remoteAddr.Port), TCP: 30303}, 355 Expiration: uint64(time.Now().Unix() + int64(expiration)), 356 Topics: topics, 357 }, 358 }) 359 return hash 360 } 361 362 func (st *simTransport) sendPong(remote *Node, pingHash []byte) { 363 raddr := remote.addr() 364 365 st.sendPacket(remote.ID, ingressPacket{ 366 remoteID: st.sender, 367 remoteAddr: st.senderAddr, 368 hash: st.nextHash(), 369 ev: pongPacket, 370 data: &pong{ 371 To: rpcEndpoint{IP: raddr.IP, UDP: uint16(raddr.Port), TCP: 30303}, 372 ReplyTok: pingHash, 373 Expiration: uint64(time.Now().Unix() + int64(expiration)), 374 }, 375 }) 376 } 377 378 func (st *simTransport) sendFindnodeHash(remote *Node, target common.Hash) { 379 st.sendPacket(remote.ID, ingressPacket{ 380 remoteID: st.sender, 381 remoteAddr: st.senderAddr, 382 hash: st.nextHash(), 383 ev: findnodeHashPacket, 384 data: &findnodeHash{ 385 Target: target, 386 Expiration: uint64(time.Now().Unix() + int64(expiration)), 387 }, 388 }) 389 } 390 391 func (st *simTransport) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 392 //fmt.Println("send", topics, pong) 393 st.sendPacket(remote.ID, ingressPacket{ 394 remoteID: st.sender, 395 remoteAddr: st.senderAddr, 396 hash: st.nextHash(), 397 ev: topicRegisterPacket, 398 data: &topicRegister{ 399 Topics: topics, 400 Idx: uint(idx), 401 Pong: pong, 402 }, 403 }) 404 } 405 406 func (st *simTransport) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 407 rnodes := make([]rpcNode, len(nodes)) 408 for i := range nodes { 409 rnodes[i] = nodeToRPC(nodes[i]) 410 } 411 st.sendPacket(remote.ID, ingressPacket{ 412 remoteID: st.sender, 413 remoteAddr: st.senderAddr, 414 hash: st.nextHash(), 415 ev: topicNodesPacket, 416 data: &topicNodes{Echo: queryHash, Nodes: rnodes}, 417 }) 418 } 419 420 func (st *simTransport) sendNeighbours(remote *Node, nodes []*Node) { 421 // TODO: send multiple packets 422 rnodes := make([]rpcNode, len(nodes)) 423 for i := range nodes { 424 rnodes[i] = nodeToRPC(nodes[i]) 425 } 426 st.sendPacket(remote.ID, ingressPacket{ 427 remoteID: st.sender, 428 remoteAddr: st.senderAddr, 429 hash: st.nextHash(), 430 ev: neighborsPacket, 431 data: &neighbors{ 432 Nodes: rnodes, 433 Expiration: uint64(time.Now().Unix() + int64(expiration)), 434 }, 435 }) 436 } 437 438 func (st *simTransport) nextHash() []byte { 439 v := atomic.AddUint64(&st.hashctr, 1) 440 var hash common.Hash 441 binary.BigEndian.PutUint64(hash[:], v) 442 return hash[:] 443 } 444 445 const packetLoss = 0 // 1/1000 446 447 func (st *simTransport) sendPacket(remote NodeID, p ingressPacket) { 448 if rand.Int31n(1000) >= packetLoss { 449 st.sim.mu.RLock() 450 recipient := st.sim.nodes[remote] 451 st.sim.mu.RUnlock() 452 453 time.AfterFunc(200*time.Millisecond, func() { 454 recipient.reqReadPacket(p) 455 }) 456 } 457 }