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