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