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