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