github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/simulations/mocker.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //包模拟模拟P2P网络。
    26  //模拟程序模拟网络中真实节点的启动和停止。
    27  package simulations
    28  
    29  import (
    30  	"fmt"
    31  	"math/rand"
    32  	"sync"
    33  	"time"
    34  
    35  	"github.com/ethereum/go-ethereum/log"
    36  	"github.com/ethereum/go-ethereum/p2p/discover"
    37  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    38  )
    39  
    40  //mocker名称到其函数的映射
    41  var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){
    42  	"startStop":     startStop,
    43  	"probabilistic": probabilistic,
    44  	"boot":          boot,
    45  }
    46  
    47  //按名称查找mocker,返回mokerfn
    48  func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) {
    49  	return mockerList[mockerType]
    50  }
    51  
    52  //获取模拟程序列表(地图的键)
    53  //用于前端构建可用的mocker选择
    54  func GetMockerList() []string {
    55  	list := make([]string, 0, len(mockerList))
    56  	for k := range mockerList {
    57  		list = append(list, k)
    58  	}
    59  	return list
    60  }
    61  
    62  //引导mokerfn只连接环中的节点,不执行任何其他操作
    63  func boot(net *Network, quit chan struct{}, nodeCount int) {
    64  	_, err := connectNodesInRing(net, nodeCount)
    65  	if err != nil {
    66  		panic("Could not startup node network for mocker")
    67  	}
    68  }
    69  
    70  //startstop mokerfn在定义的时间段内停止和启动节点(ticker)
    71  func startStop(net *Network, quit chan struct{}, nodeCount int) {
    72  	nodes, err := connectNodesInRing(net, nodeCount)
    73  	if err != nil {
    74  		panic("Could not startup node network for mocker")
    75  	}
    76  	tick := time.NewTicker(10 * time.Second)
    77  	defer tick.Stop()
    78  	for {
    79  		select {
    80  		case <-quit:
    81  			log.Info("Terminating simulation loop")
    82  			return
    83  		case <-tick.C:
    84  			id := nodes[rand.Intn(len(nodes))]
    85  			log.Info("stopping node", "id", id)
    86  			if err := net.Stop(id); err != nil {
    87  				log.Error("error stopping node", "id", id, "err", err)
    88  				return
    89  			}
    90  
    91  			select {
    92  			case <-quit:
    93  				log.Info("Terminating simulation loop")
    94  				return
    95  			case <-time.After(3 * time.Second):
    96  			}
    97  
    98  			log.Debug("starting node", "id", id)
    99  			if err := net.Start(id); err != nil {
   100  				log.Error("error starting node", "id", id, "err", err)
   101  				return
   102  			}
   103  		}
   104  	}
   105  }
   106  
   107  //概率嘲弄者func有一个更为概率的模式。
   108  //(实施可能会得到改进):
   109  //节点以环形连接,然后选择不同数量的随机节点,
   110  //然后mocker以随机间隔停止并启动它们,并继续循环
   111  func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
   112  	nodes, err := connectNodesInRing(net, nodeCount)
   113  	if err != nil {
   114  		select {
   115  		case <-quit:
   116  //错误可能是由于模拟中止;因此退出通道关闭
   117  			return
   118  		default:
   119  			panic("Could not startup node network for mocker")
   120  		}
   121  	}
   122  	for {
   123  		select {
   124  		case <-quit:
   125  			log.Info("Terminating simulation loop")
   126  			return
   127  		default:
   128  		}
   129  		var lowid, highid int
   130  		var wg sync.WaitGroup
   131  		randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond
   132  		rand1 := rand.Intn(nodeCount - 1)
   133  		rand2 := rand.Intn(nodeCount - 1)
   134  		if rand1 < rand2 {
   135  			lowid = rand1
   136  			highid = rand2
   137  		} else if rand1 > rand2 {
   138  			highid = rand1
   139  			lowid = rand2
   140  		} else {
   141  			if rand1 == 0 {
   142  				rand2 = 9
   143  			} else if rand1 == 9 {
   144  				rand1 = 0
   145  			}
   146  			lowid = rand1
   147  			highid = rand2
   148  		}
   149  		var steps = highid - lowid
   150  		wg.Add(steps)
   151  		for i := lowid; i < highid; i++ {
   152  			select {
   153  			case <-quit:
   154  				log.Info("Terminating simulation loop")
   155  				return
   156  			case <-time.After(randWait):
   157  			}
   158  			log.Debug(fmt.Sprintf("node %v shutting down", nodes[i]))
   159  			err := net.Stop(nodes[i])
   160  			if err != nil {
   161  				log.Error("Error stopping node", "node", nodes[i])
   162  				wg.Done()
   163  				continue
   164  			}
   165  			go func(id discover.NodeID) {
   166  				time.Sleep(randWait)
   167  				err := net.Start(id)
   168  				if err != nil {
   169  					log.Error("Error starting node", "node", id)
   170  				}
   171  				wg.Done()
   172  			}(nodes[i])
   173  		}
   174  		wg.Wait()
   175  	}
   176  
   177  }
   178  
   179  //连接节点计数环中的节点数
   180  func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) {
   181  	ids := make([]discover.NodeID, nodeCount)
   182  	for i := 0; i < nodeCount; i++ {
   183  		conf := adapters.RandomNodeConfig()
   184  		node, err := net.NewNodeWithConfig(conf)
   185  		if err != nil {
   186  			log.Error("Error creating a node!", "err", err)
   187  			return nil, err
   188  		}
   189  		ids[i] = node.ID()
   190  	}
   191  
   192  	for _, id := range ids {
   193  		if err := net.Start(id); err != nil {
   194  			log.Error("Error starting a node!", "err", err)
   195  			return nil, err
   196  		}
   197  		log.Debug(fmt.Sprintf("node %v starting up", id))
   198  	}
   199  	for i, id := range ids {
   200  		peerID := ids[(i+1)%len(ids)]
   201  		if err := net.Connect(id, peerID); err != nil {
   202  			log.Error("Error connecting a node to a peer!", "err", err)
   203  			return nil, err
   204  		}
   205  	}
   206  
   207  	return ids, nil
   208  }