github.com/simplechain-org/go-simplechain@v1.0.6/p2p/discv5/sim_test.go (about) 1 // Copyright 2016 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain 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/simplechain-org/go-simplechain/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 type simTransport struct { 298 joinTime time.Time 299 sender NodeID 300 senderAddr *net.UDPAddr 301 sim *simulation 302 hashctr uint64 303 priv *ecdsa.PrivateKey 304 } 305 306 func (st *simTransport) localAddr() *net.UDPAddr { 307 return st.senderAddr 308 } 309 310 func (st *simTransport) Close() {} 311 312 func (st *simTransport) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 313 hash = st.nextHash() 314 var raw []byte 315 if ptype == pongPacket { 316 var err error 317 raw, _, err = encodePacket(st.priv, byte(ptype), data) 318 if err != nil { 319 panic(err) 320 } 321 } 322 323 st.sendPacket(remote.ID, ingressPacket{ 324 remoteID: st.sender, 325 remoteAddr: st.senderAddr, 326 hash: hash, 327 ev: ptype, 328 data: data, 329 rawData: raw, 330 }) 331 return hash 332 } 333 334 func (st *simTransport) sendPing(remote *Node, remoteAddr *net.UDPAddr, topics []Topic) []byte { 335 hash := st.nextHash() 336 st.sendPacket(remote.ID, ingressPacket{ 337 remoteID: st.sender, 338 remoteAddr: st.senderAddr, 339 hash: hash, 340 ev: pingPacket, 341 data: &ping{ 342 Version: 4, 343 From: rpcEndpoint{IP: st.senderAddr.IP, UDP: uint16(st.senderAddr.Port), TCP: 30303}, 344 To: rpcEndpoint{IP: remoteAddr.IP, UDP: uint16(remoteAddr.Port), TCP: 30303}, 345 Expiration: uint64(time.Now().Unix() + int64(expiration)), 346 Topics: topics, 347 }, 348 }) 349 return hash 350 } 351 352 func (st *simTransport) sendFindnodeHash(remote *Node, target common.Hash) { 353 st.sendPacket(remote.ID, ingressPacket{ 354 remoteID: st.sender, 355 remoteAddr: st.senderAddr, 356 hash: st.nextHash(), 357 ev: findnodeHashPacket, 358 data: &findnodeHash{ 359 Target: target, 360 Expiration: uint64(time.Now().Unix() + int64(expiration)), 361 }, 362 }) 363 } 364 365 func (st *simTransport) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 366 //fmt.Println("send", topics, pong) 367 st.sendPacket(remote.ID, ingressPacket{ 368 remoteID: st.sender, 369 remoteAddr: st.senderAddr, 370 hash: st.nextHash(), 371 ev: topicRegisterPacket, 372 data: &topicRegister{ 373 Topics: topics, 374 Idx: uint(idx), 375 Pong: pong, 376 }, 377 }) 378 } 379 380 func (st *simTransport) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 381 rnodes := make([]rpcNode, len(nodes)) 382 for i := range nodes { 383 rnodes[i] = nodeToRPC(nodes[i]) 384 } 385 st.sendPacket(remote.ID, ingressPacket{ 386 remoteID: st.sender, 387 remoteAddr: st.senderAddr, 388 hash: st.nextHash(), 389 ev: topicNodesPacket, 390 data: &topicNodes{Echo: queryHash, Nodes: rnodes}, 391 }) 392 } 393 394 func (st *simTransport) sendNeighbours(remote *Node, nodes []*Node) { 395 // TODO: send multiple packets 396 rnodes := make([]rpcNode, len(nodes)) 397 for i := range nodes { 398 rnodes[i] = nodeToRPC(nodes[i]) 399 } 400 st.sendPacket(remote.ID, ingressPacket{ 401 remoteID: st.sender, 402 remoteAddr: st.senderAddr, 403 hash: st.nextHash(), 404 ev: neighborsPacket, 405 data: &neighbors{ 406 Nodes: rnodes, 407 Expiration: uint64(time.Now().Unix() + int64(expiration)), 408 }, 409 }) 410 } 411 412 func (st *simTransport) nextHash() []byte { 413 v := atomic.AddUint64(&st.hashctr, 1) 414 var hash common.Hash 415 binary.BigEndian.PutUint64(hash[:], v) 416 return hash[:] 417 } 418 419 const packetLoss = 0 // 1/1000 420 421 func (st *simTransport) sendPacket(remote NodeID, p ingressPacket) { 422 if rand.Int31n(1000) >= packetLoss { 423 st.sim.mu.RLock() 424 recipient := st.sim.nodes[remote] 425 st.sim.mu.RUnlock() 426 427 time.AfterFunc(200*time.Millisecond, func() { 428 recipient.reqReadPacket(p) 429 }) 430 } 431 }