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  }