mocker.go 5.1 KB

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