node.go 9.5 KB

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