create.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2018 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU 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. // go-ethereum 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 General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
  16. package main
  17. import (
  18. "context"
  19. "encoding/json"
  20. "errors"
  21. "fmt"
  22. "io/ioutil"
  23. "os"
  24. "path"
  25. "path/filepath"
  26. "strings"
  27. "sync"
  28. "time"
  29. "github.com/ethereum/go-ethereum/log"
  30. "github.com/ethereum/go-ethereum/node"
  31. "github.com/ethereum/go-ethereum/p2p/simulations"
  32. "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
  33. "github.com/ethereum/go-ethereum/swarm/network"
  34. "github.com/ethereum/go-ethereum/swarm/network/simulation"
  35. cli "gopkg.in/urfave/cli.v1"
  36. )
  37. // create is used as the entry function for "create" app command.
  38. func create(ctx *cli.Context) error {
  39. log.PrintOrigins(true)
  40. log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
  41. if len(ctx.Args()) < 1 {
  42. return errors.New("argument should be the filename to verify or write-to")
  43. }
  44. filename, err := touchPath(ctx.Args()[0])
  45. if err != nil {
  46. return err
  47. }
  48. return createSnapshot(filename, ctx.Int("nodes"), strings.Split(ctx.String("services"), ","))
  49. }
  50. // createSnapshot creates a new snapshot on filesystem with provided filename,
  51. // number of nodes and service names.
  52. func createSnapshot(filename string, nodes int, services []string) (err error) {
  53. log.Debug("create snapshot", "filename", filename, "nodes", nodes, "services", services)
  54. sim := simulation.New(map[string]simulation.ServiceFunc{
  55. "bzz": func(ctx *adapters.ServiceContext, bucket *sync.Map) (node.Service, func(), error) {
  56. addr := network.NewAddr(ctx.Config.Node())
  57. kad := network.NewKademlia(addr.Over(), network.NewKadParams())
  58. hp := network.NewHiveParams()
  59. hp.KeepAliveInterval = time.Duration(200) * time.Millisecond
  60. hp.Discovery = true // discovery must be enabled when creating a snapshot
  61. // store the kademlia in the bucket, needed later in the WaitTillHealthy function
  62. bucket.Store(simulation.BucketKeyKademlia, kad)
  63. config := &network.BzzConfig{
  64. OverlayAddr: addr.Over(),
  65. UnderlayAddr: addr.Under(),
  66. HiveParams: hp,
  67. }
  68. return network.NewBzz(config, kad, nil, nil, nil), nil, nil
  69. },
  70. })
  71. defer sim.Close()
  72. ids, err := sim.AddNodes(nodes)
  73. if err != nil {
  74. return fmt.Errorf("add nodes: %v", err)
  75. }
  76. err = sim.Net.ConnectNodesRing(ids)
  77. if err != nil {
  78. return fmt.Errorf("connect nodes: %v", err)
  79. }
  80. ctx, cancelSimRun := context.WithTimeout(context.Background(), 3*time.Minute)
  81. defer cancelSimRun()
  82. if _, err := sim.WaitTillHealthy(ctx); err != nil {
  83. return fmt.Errorf("wait for healthy kademlia: %v", err)
  84. }
  85. var snap *simulations.Snapshot
  86. if len(services) > 0 {
  87. // If service names are provided, include them in the snapshot.
  88. // But, check if "bzz" service is not among them to remove it
  89. // form the snapshot as it exists on snapshot creation.
  90. var removeServices []string
  91. var wantBzz bool
  92. for _, s := range services {
  93. if s == "bzz" {
  94. wantBzz = true
  95. break
  96. }
  97. }
  98. if !wantBzz {
  99. removeServices = []string{"bzz"}
  100. }
  101. snap, err = sim.Net.SnapshotWithServices(services, removeServices)
  102. } else {
  103. snap, err = sim.Net.Snapshot()
  104. }
  105. if err != nil {
  106. return fmt.Errorf("create snapshot: %v", err)
  107. }
  108. jsonsnapshot, err := json.Marshal(snap)
  109. if err != nil {
  110. return fmt.Errorf("json encode snapshot: %v", err)
  111. }
  112. return ioutil.WriteFile(filename, jsonsnapshot, 0666)
  113. }
  114. // touchPath creates an empty file and all subdirectories
  115. // that are missing.
  116. func touchPath(filename string) (string, error) {
  117. if path.IsAbs(filename) {
  118. if _, err := os.Stat(filename); err == nil {
  119. // path exists, overwrite
  120. return filename, nil
  121. }
  122. }
  123. d, f := path.Split(filename)
  124. dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
  125. if err != nil {
  126. return "", err
  127. }
  128. _, err = os.Stat(path.Join(dir, filename))
  129. if err == nil {
  130. // path exists, overwrite
  131. return filename, nil
  132. }
  133. dirPath := path.Join(dir, d)
  134. filePath := path.Join(dirPath, f)
  135. if d != "" {
  136. err = os.MkdirAll(dirPath, os.ModeDir)
  137. if err != nil {
  138. return "", err
  139. }
  140. }
  141. return filePath, nil
  142. }