mocker.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2017 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. // Package simulations simulates p2p networks.
  17. // A mocker simulates starting and stopping real nodes in a network.
  18. package simulations
  19. import (
  20. "fmt"
  21. "math/rand"
  22. "sync"
  23. "time"
  24. "github.com/ethereum/go-ethereum/log"
  25. "github.com/ethereum/go-ethereum/p2p/enode"
  26. "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
  27. )
  28. //a map of mocker names to its function
  29. var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){
  30. "startStop": startStop,
  31. "probabilistic": probabilistic,
  32. "boot": boot,
  33. }
  34. //Lookup a mocker by its name, returns the mockerFn
  35. func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) {
  36. return mockerList[mockerType]
  37. }
  38. //Get a list of mockers (keys of the map)
  39. //Useful for frontend to build available mocker selection
  40. func GetMockerList() []string {
  41. list := make([]string, 0, len(mockerList))
  42. for k := range mockerList {
  43. list = append(list, k)
  44. }
  45. return list
  46. }
  47. //The boot mockerFn only connects the node in a ring and doesn't do anything else
  48. func boot(net *Network, quit chan struct{}, nodeCount int) {
  49. _, err := connectNodesInRing(net, nodeCount)
  50. if err != nil {
  51. panic("Could not startup node network for mocker")
  52. }
  53. }
  54. //The startStop mockerFn stops and starts nodes in a defined period (ticker)
  55. func startStop(net *Network, quit chan struct{}, nodeCount int) {
  56. nodes, err := connectNodesInRing(net, nodeCount)
  57. if err != nil {
  58. panic("Could not startup node network for mocker")
  59. }
  60. tick := time.NewTicker(10 * time.Second)
  61. defer tick.Stop()
  62. for {
  63. select {
  64. case <-quit:
  65. log.Info("Terminating simulation loop")
  66. return
  67. case <-tick.C:
  68. id := nodes[rand.Intn(len(nodes))]
  69. log.Info("stopping node", "id", id)
  70. if err := net.Stop(id); err != nil {
  71. log.Error("error stopping node", "id", id, "err", err)
  72. return
  73. }
  74. select {
  75. case <-quit:
  76. log.Info("Terminating simulation loop")
  77. return
  78. case <-time.After(3 * time.Second):
  79. }
  80. log.Debug("starting node", "id", id)
  81. if err := net.Start(id); err != nil {
  82. log.Error("error starting node", "id", id, "err", err)
  83. return
  84. }
  85. }
  86. }
  87. }
  88. //The probabilistic mocker func has a more probabilistic pattern
  89. //(the implementation could probably be improved):
  90. //nodes are connected in a ring, then a varying number of random nodes is selected,
  91. //mocker then stops and starts them in random intervals, and continues the loop
  92. func probabilistic(net *Network, quit chan struct{}, nodeCount int) {
  93. nodes, err := connectNodesInRing(net, nodeCount)
  94. if err != nil {
  95. select {
  96. case <-quit:
  97. //error may be due to abortion of mocking; so the quit channel is closed
  98. return
  99. default:
  100. panic("Could not startup node network for mocker")
  101. }
  102. }
  103. for {
  104. select {
  105. case <-quit:
  106. log.Info("Terminating simulation loop")
  107. return
  108. default:
  109. }
  110. var lowid, highid int
  111. var wg sync.WaitGroup
  112. randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond
  113. rand1 := rand.Intn(nodeCount - 1)
  114. rand2 := rand.Intn(nodeCount - 1)
  115. if rand1 < rand2 {
  116. lowid = rand1
  117. highid = rand2
  118. } else if rand1 > rand2 {
  119. highid = rand1
  120. lowid = rand2
  121. } else {
  122. if rand1 == 0 {
  123. rand2 = 9
  124. } else if rand1 == 9 {
  125. rand1 = 0
  126. }
  127. lowid = rand1
  128. highid = rand2
  129. }
  130. var steps = highid - lowid
  131. wg.Add(steps)
  132. for i := lowid; i < highid; i++ {
  133. select {
  134. case <-quit:
  135. log.Info("Terminating simulation loop")
  136. return
  137. case <-time.After(randWait):
  138. }
  139. log.Debug(fmt.Sprintf("node %v shutting down", nodes[i]))
  140. err := net.Stop(nodes[i])
  141. if err != nil {
  142. log.Error("Error stopping node", "node", nodes[i])
  143. wg.Done()
  144. continue
  145. }
  146. go func(id enode.ID) {
  147. time.Sleep(randWait)
  148. err := net.Start(id)
  149. if err != nil {
  150. log.Error("Error starting node", "node", id)
  151. }
  152. wg.Done()
  153. }(nodes[i])
  154. }
  155. wg.Wait()
  156. }
  157. }
  158. //connect nodeCount number of nodes in a ring
  159. func connectNodesInRing(net *Network, nodeCount int) ([]enode.ID, error) {
  160. ids := make([]enode.ID, nodeCount)
  161. for i := 0; i < nodeCount; i++ {
  162. conf := adapters.RandomNodeConfig()
  163. node, err := net.NewNodeWithConfig(conf)
  164. if err != nil {
  165. log.Error("Error creating a node!", "err", err)
  166. return nil, err
  167. }
  168. ids[i] = node.ID()
  169. }
  170. for _, id := range ids {
  171. if err := net.Start(id); err != nil {
  172. log.Error("Error starting a node!", "err", err)
  173. return nil, err
  174. }
  175. log.Debug(fmt.Sprintf("node %v starting up", id))
  176. }
  177. for i, id := range ids {
  178. peerID := ids[(i+1)%len(ids)]
  179. if err := net.Connect(id, peerID); err != nil {
  180. log.Error("Error connecting a node to a peer!", "err", err)
  181. return nil, err
  182. }
  183. }
  184. return ids, nil
  185. }