github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/simulations/mocker.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:44</date>
    10  //</624342661502865408>
    11  
    12  
    13  //包模拟模拟P2P网络。
    14  //模拟程序模拟网络中真实节点的启动和停止。
    15  package simulations
    16  
    17  import (
    18  	"fmt"
    19  	"math/rand"
    20  	"sync"
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/log"
    24  	"github.com/ethereum/go-ethereum/p2p/discover"
    25  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    26  )
    27  
    28  //mocker名称到其函数的映射
    29  var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){
    30  	"startStop":     startStop,
    31  	"probabilistic": probabilistic,
    32  	"boot":          boot,
    33  }
    34  
    35  //按名称查找mocker,返回mokerfn
    36  func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) {
    37  	return mockerList[mockerType]
    38  }
    39  
    40  //获取模拟程序列表(地图的键)
    41  //用于前端构建可用的mocker选择
    42  func GetMockerList() []string {
    43  	list := make([]string, 0, len(mockerList))
    44  	for k := range mockerList {
    45  		list = append(list, k)
    46  	}
    47  	return list
    48  }
    49  
    50  //引导mokerfn只连接环中的节点,不执行任何其他操作
    51  func boot(net *Network, quit chan struct{}, nodeCount int) {
    52  	_, err := connectNodesInRing(net, nodeCount)
    53  	if err != nil {
    54  		panic("Could not startup node network for mocker")
    55  	}
    56  }
    57  
    58  //startstop mokerfn在定义的时间段内停止和启动节点(ticker)
    59  func startStop(net *Network, quit chan struct{}, nodeCount int) {
    60  	nodes, err := connectNodesInRing(net, nodeCount)
    61  	if err != nil {
    62  		panic("Could not startup node network for mocker")
    63  	}
    64  	tick := time.NewTicker(10 * time.Second)
    65  	defer tick.Stop()
    66  	for {
    67  		select {
    68  		case <-quit:
    69  			log.Info("Terminating simulation loop")
    70  			return
    71  		case <-tick.C:
    72  			id := nodes[rand.Intn(len(nodes))]
    73  			log.Info("stopping node", "id", id)
    74  			if err := net.Stop(id); err != nil {
    75  				log.Error("error stopping node", "id", id, "err", err)
    76  				return
    77  			}
    78  
    79  			select {
    80  			case <-quit:
    81  				log.Info("Terminating simulation loop")
    82  				return
    83  			case <-time.After(3 * time.Second):
    84  			}
    85  
    86  			log.Debug("starting node", "id", id)
    87  			if err := net.Start(id); err != nil {
    88  				log.Error("error starting node", "id", id, "err", err)
    89  				return
    90  			}
    91  		}
    92  	}
    93  }
    94  
    95  //概率嘲弄者func有一个更为概率的模式。
    96  //(实施可能会得到改进):
    97  //节点以环形连接,然后选择不同数量的随机节点,
    98  //然后mocker以随机间隔停止并启动它们,并继续循环
    99  func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
   100  	nodes, err := connectNodesInRing(net, nodeCount)
   101  	if err != nil {
   102  		select {
   103  		case <-quit:
   104  //错误可能是由于模拟中止;因此退出通道关闭
   105  			return
   106  		default:
   107  			panic("Could not startup node network for mocker")
   108  		}
   109  	}
   110  	for {
   111  		select {
   112  		case <-quit:
   113  			log.Info("Terminating simulation loop")
   114  			return
   115  		default:
   116  		}
   117  		var lowid, highid int
   118  		var wg sync.WaitGroup
   119  		randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond
   120  		rand1 := rand.Intn(nodeCount - 1)
   121  		rand2 := rand.Intn(nodeCount - 1)
   122  		if rand1 < rand2 {
   123  			lowid = rand1
   124  			highid = rand2
   125  		} else if rand1 > rand2 {
   126  			highid = rand1
   127  			lowid = rand2
   128  		} else {
   129  			if rand1 == 0 {
   130  				rand2 = 9
   131  			} else if rand1 == 9 {
   132  				rand1 = 0
   133  			}
   134  			lowid = rand1
   135  			highid = rand2
   136  		}
   137  		var steps = highid - lowid
   138  		wg.Add(steps)
   139  		for i := lowid; i < highid; i++ {
   140  			select {
   141  			case <-quit:
   142  				log.Info("Terminating simulation loop")
   143  				return
   144  			case <-time.After(randWait):
   145  			}
   146  			log.Debug(fmt.Sprintf("node %v shutting down", nodes[i]))
   147  			err := net.Stop(nodes[i])
   148  			if err != nil {
   149  				log.Error("Error stopping node", "node", nodes[i])
   150  				wg.Done()
   151  				continue
   152  			}
   153  			go func(id discover.NodeID) {
   154  				time.Sleep(randWait)
   155  				err := net.Start(id)
   156  				if err != nil {
   157  					log.Error("Error starting node", "node", id)
   158  				}
   159  				wg.Done()
   160  			}(nodes[i])
   161  		}
   162  		wg.Wait()
   163  	}
   164  
   165  }
   166  
   167  //连接节点计数环中的节点数
   168  func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) {
   169  	ids := make([]discover.NodeID, nodeCount)
   170  	for i := 0; i < nodeCount; i++ {
   171  		conf := adapters.RandomNodeConfig()
   172  		node, err := net.NewNodeWithConfig(conf)
   173  		if err != nil {
   174  			log.Error("Error creating a node!", "err", err)
   175  			return nil, err
   176  		}
   177  		ids[i] = node.ID()
   178  	}
   179  
   180  	for _, id := range ids {
   181  		if err := net.Start(id); err != nil {
   182  			log.Error("Error starting a node!", "err", err)
   183  			return nil, err
   184  		}
   185  		log.Debug(fmt.Sprintf("node %v starting up", id))
   186  	}
   187  	for i, id := range ids {
   188  		peerID := ids[(i+1)%len(ids)]
   189  		if err := net.Connect(id, peerID); err != nil {
   190  			log.Error("Error connecting a node to a peer!", "err", err)
   191  			return nil, err
   192  		}
   193  	}
   194  
   195  	return ids, nil
   196  }
   197