github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/p2p/discv5/sim_test.go (about)

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