github.com/AlohaMobile/go-ethereum@v1.9.7/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 t.Logf("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 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 for { 200 select { 201 case <-timer.C: 202 target := s.randomNode().Self().ID 203 if !lookup(target) { 204 t.Errorf("node %x: target %x not found", net.Self().ID[:8], target[:8]) 205 } 206 timer.Reset(randtime()) 207 case <-net.closed: 208 return 209 } 210 } 211 } 212 213 type simulation struct { 214 mu sync.RWMutex 215 nodes map[NodeID]*Network 216 nodectr uint32 217 } 218 219 func newSimulation() *simulation { 220 return &simulation{nodes: make(map[NodeID]*Network)} 221 } 222 223 func (s *simulation) shutdown() { 224 s.mu.RLock() 225 alive := make([]*Network, 0, len(s.nodes)) 226 for _, n := range s.nodes { 227 alive = append(alive, n) 228 } 229 defer s.mu.RUnlock() 230 231 for _, n := range alive { 232 n.Close() 233 } 234 } 235 236 func (s *simulation) printStats() { 237 s.mu.Lock() 238 defer s.mu.Unlock() 239 fmt.Println("node counter:", s.nodectr) 240 fmt.Println("alive nodes:", len(s.nodes)) 241 242 // for _, n := range s.nodes { 243 // fmt.Printf("%x\n", n.tab.self.ID[:8]) 244 // transport := n.conn.(*simTransport) 245 // fmt.Println(" joined:", transport.joinTime) 246 // fmt.Println(" sends:", transport.hashctr) 247 // fmt.Println(" table size:", n.tab.count) 248 // } 249 250 /*for _, n := range s.nodes { 251 fmt.Println() 252 fmt.Printf("*** Node %x\n", n.tab.self.ID[:8]) 253 n.log.printLogs() 254 }*/ 255 256 } 257 258 func (s *simulation) randomNode() *Network { 259 s.mu.Lock() 260 defer s.mu.Unlock() 261 262 n := rand.Intn(len(s.nodes)) 263 for _, net := range s.nodes { 264 if n == 0 { 265 return net 266 } 267 n-- 268 } 269 return nil 270 } 271 272 func (s *simulation) launchNode(log bool) *Network { 273 var ( 274 num = s.nodectr 275 key = newkey() 276 id = PubkeyID(&key.PublicKey) 277 ip = make(net.IP, 4) 278 ) 279 s.nodectr++ 280 binary.BigEndian.PutUint32(ip, num) 281 ip[0] = 10 282 addr := &net.UDPAddr{IP: ip, Port: 30303} 283 284 transport := &simTransport{joinTime: time.Now(), sender: id, senderAddr: addr, sim: s, priv: key} 285 net, err := newNetwork(transport, key.PublicKey, "<no database>", nil) 286 if err != nil { 287 panic("cannot launch new node: " + err.Error()) 288 } 289 290 s.mu.Lock() 291 s.nodes[id] = net 292 s.mu.Unlock() 293 294 return net 295 } 296 297 func (s *simulation) dropNode(id NodeID) { 298 s.mu.Lock() 299 n := s.nodes[id] 300 delete(s.nodes, id) 301 s.mu.Unlock() 302 303 n.Close() 304 } 305 306 type simTransport struct { 307 joinTime time.Time 308 sender NodeID 309 senderAddr *net.UDPAddr 310 sim *simulation 311 hashctr uint64 312 priv *ecdsa.PrivateKey 313 } 314 315 func (st *simTransport) localAddr() *net.UDPAddr { 316 return st.senderAddr 317 } 318 319 func (st *simTransport) Close() {} 320 321 func (st *simTransport) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 322 hash = st.nextHash() 323 var raw []byte 324 if ptype == pongPacket { 325 var err error 326 raw, _, err = encodePacket(st.priv, byte(ptype), data) 327 if err != nil { 328 panic(err) 329 } 330 } 331 332 st.sendPacket(remote.ID, ingressPacket{ 333 remoteID: st.sender, 334 remoteAddr: st.senderAddr, 335 hash: hash, 336 ev: ptype, 337 data: data, 338 rawData: raw, 339 }) 340 return hash 341 } 342 343 func (st *simTransport) sendPing(remote *Node, remoteAddr *net.UDPAddr, topics []Topic) []byte { 344 hash := st.nextHash() 345 st.sendPacket(remote.ID, ingressPacket{ 346 remoteID: st.sender, 347 remoteAddr: st.senderAddr, 348 hash: hash, 349 ev: pingPacket, 350 data: &ping{ 351 Version: 4, 352 From: rpcEndpoint{IP: st.senderAddr.IP, UDP: uint16(st.senderAddr.Port), TCP: 30303}, 353 To: rpcEndpoint{IP: remoteAddr.IP, UDP: uint16(remoteAddr.Port), TCP: 30303}, 354 Expiration: uint64(time.Now().Unix() + int64(expiration)), 355 Topics: topics, 356 }, 357 }) 358 return hash 359 } 360 361 func (st *simTransport) sendPong(remote *Node, pingHash []byte) { 362 raddr := remote.addr() 363 364 st.sendPacket(remote.ID, ingressPacket{ 365 remoteID: st.sender, 366 remoteAddr: st.senderAddr, 367 hash: st.nextHash(), 368 ev: pongPacket, 369 data: &pong{ 370 To: rpcEndpoint{IP: raddr.IP, UDP: uint16(raddr.Port), TCP: 30303}, 371 ReplyTok: pingHash, 372 Expiration: uint64(time.Now().Unix() + int64(expiration)), 373 }, 374 }) 375 } 376 377 func (st *simTransport) sendFindnodeHash(remote *Node, target common.Hash) { 378 st.sendPacket(remote.ID, ingressPacket{ 379 remoteID: st.sender, 380 remoteAddr: st.senderAddr, 381 hash: st.nextHash(), 382 ev: findnodeHashPacket, 383 data: &findnodeHash{ 384 Target: target, 385 Expiration: uint64(time.Now().Unix() + int64(expiration)), 386 }, 387 }) 388 } 389 390 func (st *simTransport) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 391 //fmt.Println("send", topics, pong) 392 st.sendPacket(remote.ID, ingressPacket{ 393 remoteID: st.sender, 394 remoteAddr: st.senderAddr, 395 hash: st.nextHash(), 396 ev: topicRegisterPacket, 397 data: &topicRegister{ 398 Topics: topics, 399 Idx: uint(idx), 400 Pong: pong, 401 }, 402 }) 403 } 404 405 func (st *simTransport) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 406 rnodes := make([]rpcNode, len(nodes)) 407 for i := range nodes { 408 rnodes[i] = nodeToRPC(nodes[i]) 409 } 410 st.sendPacket(remote.ID, ingressPacket{ 411 remoteID: st.sender, 412 remoteAddr: st.senderAddr, 413 hash: st.nextHash(), 414 ev: topicNodesPacket, 415 data: &topicNodes{Echo: queryHash, Nodes: rnodes}, 416 }) 417 } 418 419 func (st *simTransport) sendNeighbours(remote *Node, nodes []*Node) { 420 // TODO: send multiple packets 421 rnodes := make([]rpcNode, len(nodes)) 422 for i := range nodes { 423 rnodes[i] = nodeToRPC(nodes[i]) 424 } 425 st.sendPacket(remote.ID, ingressPacket{ 426 remoteID: st.sender, 427 remoteAddr: st.senderAddr, 428 hash: st.nextHash(), 429 ev: neighborsPacket, 430 data: &neighbors{ 431 Nodes: rnodes, 432 Expiration: uint64(time.Now().Unix() + int64(expiration)), 433 }, 434 }) 435 } 436 437 func (st *simTransport) nextHash() []byte { 438 v := atomic.AddUint64(&st.hashctr, 1) 439 var hash common.Hash 440 binary.BigEndian.PutUint64(hash[:], v) 441 return hash[:] 442 } 443 444 const packetLoss = 0 // 1/1000 445 446 func (st *simTransport) sendPacket(remote NodeID, p ingressPacket) { 447 if rand.Int31n(1000) >= packetLoss { 448 st.sim.mu.RLock() 449 recipient := st.sim.nodes[remote] 450 st.sim.mu.RUnlock() 451 452 time.AfterFunc(200*time.Millisecond, func() { 453 recipient.reqReadPacket(p) 454 }) 455 } 456 }