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