node.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2018 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 simulation
  17. import (
  18. "encoding/json"
  19. "errors"
  20. "io/ioutil"
  21. "math/rand"
  22. "os"
  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"
  27. "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
  28. )
  29. // NodeIDs returns NodeIDs for all nodes in the network.
  30. func (s *Simulation) NodeIDs() (ids []enode.ID) {
  31. nodes := s.Net.GetNodes()
  32. ids = make([]enode.ID, len(nodes))
  33. for i, node := range nodes {
  34. ids[i] = node.ID()
  35. }
  36. return ids
  37. }
  38. // UpNodeIDs returns NodeIDs for nodes that are up in the network.
  39. func (s *Simulation) UpNodeIDs() (ids []enode.ID) {
  40. nodes := s.Net.GetNodes()
  41. for _, node := range nodes {
  42. if node.Up() {
  43. ids = append(ids, node.ID())
  44. }
  45. }
  46. return ids
  47. }
  48. // DownNodeIDs returns NodeIDs for nodes that are stopped in the network.
  49. func (s *Simulation) DownNodeIDs() (ids []enode.ID) {
  50. nodes := s.Net.GetNodes()
  51. for _, node := range nodes {
  52. if !node.Up() {
  53. ids = append(ids, node.ID())
  54. }
  55. }
  56. return ids
  57. }
  58. // AddNodeOption defines the option that can be passed
  59. // to Simulation.AddNode method.
  60. type AddNodeOption func(*adapters.NodeConfig)
  61. // AddNodeWithMsgEvents sets the EnableMsgEvents option
  62. // to NodeConfig.
  63. func AddNodeWithMsgEvents(enable bool) AddNodeOption {
  64. return func(o *adapters.NodeConfig) {
  65. o.EnableMsgEvents = enable
  66. }
  67. }
  68. // AddNodeWithService specifies a service that should be
  69. // started on a node. This option can be repeated as variadic
  70. // argument toe AddNode and other add node related methods.
  71. // If AddNodeWithService is not specified, all services will be started.
  72. func AddNodeWithService(serviceName string) AddNodeOption {
  73. return func(o *adapters.NodeConfig) {
  74. o.Services = append(o.Services, serviceName)
  75. }
  76. }
  77. // AddNode creates a new node with random configuration,
  78. // applies provided options to the config and adds the node to network.
  79. // By default all services will be started on a node. If one or more
  80. // AddNodeWithService option are provided, only specified services will be started.
  81. func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) {
  82. conf := adapters.RandomNodeConfig()
  83. for _, o := range opts {
  84. o(conf)
  85. }
  86. if len(conf.Services) == 0 {
  87. conf.Services = s.serviceNames
  88. }
  89. node, err := s.Net.NewNodeWithConfig(conf)
  90. if err != nil {
  91. return id, err
  92. }
  93. return node.ID(), s.Net.Start(node.ID())
  94. }
  95. // AddNodes creates new nodes with random configurations,
  96. // applies provided options to the config and adds nodes to network.
  97. func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
  98. ids = make([]enode.ID, 0, count)
  99. for i := 0; i < count; i++ {
  100. id, err := s.AddNode(opts...)
  101. if err != nil {
  102. return nil, err
  103. }
  104. ids = append(ids, id)
  105. }
  106. return ids, nil
  107. }
  108. // AddNodesAndConnectFull is a helpper method that combines
  109. // AddNodes and ConnectNodesFull. Only new nodes will be connected.
  110. func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
  111. if count < 2 {
  112. return nil, errors.New("count of nodes must be at least 2")
  113. }
  114. ids, err = s.AddNodes(count, opts...)
  115. if err != nil {
  116. return nil, err
  117. }
  118. err = s.Net.ConnectNodesFull(ids)
  119. if err != nil {
  120. return nil, err
  121. }
  122. return ids, nil
  123. }
  124. // AddNodesAndConnectChain is a helpper method that combines
  125. // AddNodes and ConnectNodesChain. The chain will be continued from the last
  126. // added node, if there is one in simulation using ConnectToLastNode method.
  127. func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
  128. if count < 2 {
  129. return nil, errors.New("count of nodes must be at least 2")
  130. }
  131. id, err := s.AddNode(opts...)
  132. if err != nil {
  133. return nil, err
  134. }
  135. err = s.Net.ConnectToLastNode(id)
  136. if err != nil {
  137. return nil, err
  138. }
  139. ids, err = s.AddNodes(count-1, opts...)
  140. if err != nil {
  141. return nil, err
  142. }
  143. ids = append([]enode.ID{id}, ids...)
  144. err = s.Net.ConnectNodesChain(ids)
  145. if err != nil {
  146. return nil, err
  147. }
  148. return ids, nil
  149. }
  150. // AddNodesAndConnectRing is a helpper method that combines
  151. // AddNodes and ConnectNodesRing.
  152. func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
  153. if count < 2 {
  154. return nil, errors.New("count of nodes must be at least 2")
  155. }
  156. ids, err = s.AddNodes(count, opts...)
  157. if err != nil {
  158. return nil, err
  159. }
  160. err = s.Net.ConnectNodesRing(ids)
  161. if err != nil {
  162. return nil, err
  163. }
  164. return ids, nil
  165. }
  166. // AddNodesAndConnectStar is a helpper method that combines
  167. // AddNodes and ConnectNodesStar.
  168. func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error) {
  169. if count < 2 {
  170. return nil, errors.New("count of nodes must be at least 2")
  171. }
  172. ids, err = s.AddNodes(count, opts...)
  173. if err != nil {
  174. return nil, err
  175. }
  176. err = s.Net.ConnectNodesStar(ids[1:], ids[0])
  177. if err != nil {
  178. return nil, err
  179. }
  180. return ids, nil
  181. }
  182. // UploadSnapshot uploads a snapshot to the simulation
  183. // This method tries to open the json file provided, applies the config to all nodes
  184. // and then loads the snapshot into the Simulation network
  185. func (s *Simulation) UploadSnapshot(snapshotFile string, opts ...AddNodeOption) error {
  186. f, err := os.Open(snapshotFile)
  187. if err != nil {
  188. return err
  189. }
  190. defer func() {
  191. err := f.Close()
  192. if err != nil {
  193. log.Error("Error closing snapshot file", "err", err)
  194. }
  195. }()
  196. jsonbyte, err := ioutil.ReadAll(f)
  197. if err != nil {
  198. return err
  199. }
  200. var snap simulations.Snapshot
  201. err = json.Unmarshal(jsonbyte, &snap)
  202. if err != nil {
  203. return err
  204. }
  205. //the snapshot probably has the property EnableMsgEvents not set
  206. //just in case, set it to true!
  207. //(we need this to wait for messages before uploading)
  208. for _, n := range snap.Nodes {
  209. n.Node.Config.EnableMsgEvents = true
  210. n.Node.Config.Services = s.serviceNames
  211. for _, o := range opts {
  212. o(n.Node.Config)
  213. }
  214. }
  215. log.Info("Waiting for p2p connections to be established...")
  216. //now we can load the snapshot
  217. err = s.Net.Load(&snap)
  218. if err != nil {
  219. return err
  220. }
  221. log.Info("Snapshot loaded")
  222. return nil
  223. }
  224. // StartNode starts a node by NodeID.
  225. func (s *Simulation) StartNode(id enode.ID) (err error) {
  226. return s.Net.Start(id)
  227. }
  228. // StartRandomNode starts a random node.
  229. func (s *Simulation) StartRandomNode() (id enode.ID, err error) {
  230. n := s.Net.GetRandomDownNode()
  231. if n == nil {
  232. return id, ErrNodeNotFound
  233. }
  234. return n.ID(), s.Net.Start(n.ID())
  235. }
  236. // StartRandomNodes starts random nodes.
  237. func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error) {
  238. ids = make([]enode.ID, 0, count)
  239. for i := 0; i < count; i++ {
  240. n := s.Net.GetRandomDownNode()
  241. if n == nil {
  242. return nil, ErrNodeNotFound
  243. }
  244. err = s.Net.Start(n.ID())
  245. if err != nil {
  246. return nil, err
  247. }
  248. ids = append(ids, n.ID())
  249. }
  250. return ids, nil
  251. }
  252. // StopNode stops a node by NodeID.
  253. func (s *Simulation) StopNode(id enode.ID) (err error) {
  254. return s.Net.Stop(id)
  255. }
  256. // StopRandomNode stops a random node.
  257. func (s *Simulation) StopRandomNode() (id enode.ID, err error) {
  258. n := s.Net.GetRandomUpNode()
  259. if n == nil {
  260. return id, ErrNodeNotFound
  261. }
  262. return n.ID(), s.Net.Stop(n.ID())
  263. }
  264. // StopRandomNodes stops random nodes.
  265. func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) {
  266. ids = make([]enode.ID, 0, count)
  267. for i := 0; i < count; i++ {
  268. n := s.Net.GetRandomUpNode()
  269. if n == nil {
  270. return nil, ErrNodeNotFound
  271. }
  272. err = s.Net.Stop(n.ID())
  273. if err != nil {
  274. return nil, err
  275. }
  276. ids = append(ids, n.ID())
  277. }
  278. return ids, nil
  279. }
  280. // seed the random generator for Simulation.randomNode.
  281. func init() {
  282. rand.Seed(time.Now().UnixNano())
  283. }