github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/discv5/sim_test.go (about)

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