github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/cmd/swarm/main.go (about) 1 // Copyright 2016 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 "crypto/ecdsa" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "os/signal" 25 "runtime" 26 "strconv" 27 "strings" 28 "syscall" 29 30 "github.com/atheioschain/go-atheios/accounts" 31 "github.com/atheioschain/go-atheios/accounts/keystore" 32 "github.com/atheioschain/go-atheios/cmd/utils" 33 "github.com/atheioschain/go-atheios/common" 34 "github.com/atheioschain/go-atheios/console" 35 "github.com/atheioschain/go-atheios/crypto" 36 "github.com/atheioschain/go-atheios/ethclient" 37 "github.com/atheioschain/go-atheios/internal/debug" 38 "github.com/atheioschain/go-atheios/logger" 39 "github.com/atheioschain/go-atheios/logger/glog" 40 "github.com/atheioschain/go-atheios/node" 41 "github.com/atheioschain/go-atheios/p2p" 42 "github.com/atheioschain/go-atheios/p2p/discover" 43 "github.com/atheioschain/go-atheios/swarm" 44 bzzapi "github.com/atheioschain/go-atheios/swarm/api" 45 "gopkg.in/urfave/cli.v1" 46 ) 47 48 const ( 49 clientIdentifier = "swarm" 50 versionString = "0.2" 51 ) 52 53 var ( 54 gitCommit string // Git SHA1 commit hash of the release (set via linker flags) 55 app = utils.NewApp(gitCommit, "atheios Swarm") 56 testbetBootNodes = []string{} 57 ) 58 59 var ( 60 ChequebookAddrFlag = cli.StringFlag{ 61 Name: "chequebook", 62 Usage: "chequebook contract address", 63 } 64 SwarmAccountFlag = cli.StringFlag{ 65 Name: "bzzaccount", 66 Usage: "Swarm account key file", 67 } 68 SwarmPortFlag = cli.StringFlag{ 69 Name: "bzzport", 70 Usage: "Swarm local http api port", 71 } 72 SwarmNetworkIdFlag = cli.IntFlag{ 73 Name: "bzznetworkid", 74 Usage: "Network identifier (integer, default 3=swarm testnet)", 75 } 76 SwarmConfigPathFlag = cli.StringFlag{ 77 Name: "bzzconfig", 78 Usage: "Swarm config file path (datadir/bzz)", 79 } 80 SwarmSwapEnabledFlag = cli.BoolFlag{ 81 Name: "swap", 82 Usage: "Swarm SWAP enabled (default false)", 83 } 84 SwarmSyncEnabledFlag = cli.BoolTFlag{ 85 Name: "sync", 86 Usage: "Swarm Syncing enabled (default true)", 87 } 88 EthAPIFlag = cli.StringFlag{ 89 Name: "ethapi", 90 Usage: "URL of the Ethereum API provider", 91 Value: node.DefaultIPCEndpoint("gath"), 92 } 93 SwarmApiFlag = cli.StringFlag{ 94 Name: "bzzapi", 95 Usage: "Swarm HTTP endpoint", 96 Value: "http://127.0.0.1:8500", 97 } 98 SwarmRecursiveUploadFlag = cli.BoolFlag{ 99 Name: "recursive", 100 Usage: "Upload directories recursively", 101 } 102 SwarmWantManifestFlag = cli.BoolTFlag{ 103 Name: "manifest", 104 Usage: "Automatic manifest upload", 105 } 106 SwarmUploadDefaultPath = cli.StringFlag{ 107 Name: "defaultpath", 108 Usage: "path to file served for empty url path (none)", 109 } 110 CorsStringFlag = cli.StringFlag{ 111 Name: "corsdomain", 112 Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')", 113 } 114 ) 115 116 func init() { 117 // Override flag defaults so bzzd can run alongside gath. 118 utils.ListenPortFlag.Value = 30399 119 utils.IPCPathFlag.Value = utils.DirectoryString{Value: "bzzd.ipc"} 120 utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3" 121 122 // Set up the cli app. 123 app.Action = bzzd 124 app.HideVersion = true // we have a command to print the version 125 app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" 126 app.Commands = []cli.Command{ 127 { 128 Action: version, 129 Name: "version", 130 Usage: "Print version numbers", 131 ArgsUsage: " ", 132 Description: ` 133 The output of this command is supposed to be machine-readable. 134 `, 135 }, 136 { 137 Action: upload, 138 Name: "up", 139 Usage: "upload a file or directory to swarm using the HTTP API", 140 ArgsUsage: " <file>", 141 Description: ` 142 "upload a file or directory to swarm using the HTTP API and prints the root hash", 143 `, 144 }, 145 { 146 Action: hash, 147 Name: "hash", 148 Usage: "print the swarm hash of a file or directory", 149 ArgsUsage: " <file>", 150 Description: ` 151 Prints the swarm hash of file or directory. 152 `, 153 }, 154 { 155 Name: "manifest", 156 Usage: "update a MANIFEST", 157 ArgsUsage: "manifest COMMAND", 158 Description: ` 159 Updates a MANIFEST by adding/removing/updating the hash of a path. 160 `, 161 Subcommands: []cli.Command{ 162 { 163 Action: add, 164 Name: "add", 165 Usage: "add a new path to the manifest", 166 ArgsUsage: "<MANIFEST> <path> <hash> [<content-type>]", 167 Description: ` 168 Adds a new path to the manifest 169 `, 170 }, 171 { 172 Action: update, 173 Name: "update", 174 Usage: "update the hash for an already existing path in the manifest", 175 ArgsUsage: "<MANIFEST> <path> <newhash> [<newcontent-type>]", 176 Description: ` 177 Update the hash for an already existing path in the manifest 178 `, 179 }, 180 { 181 Action: remove, 182 Name: "remove", 183 Usage: "removes a path from the manifest", 184 ArgsUsage: "<MANIFEST> <path>", 185 Description: ` 186 Removes a path from the manifest 187 `, 188 }, 189 }, 190 }, 191 { 192 Action: cleandb, 193 Name: "cleandb", 194 Usage: "Cleans database of corrupted entries", 195 ArgsUsage: " ", 196 Description: ` 197 Cleans database of corrupted entries. 198 `, 199 }, 200 } 201 202 app.Flags = []cli.Flag{ 203 utils.IdentityFlag, 204 utils.DataDirFlag, 205 utils.BootnodesFlag, 206 utils.KeyStoreDirFlag, 207 utils.ListenPortFlag, 208 utils.NoDiscoverFlag, 209 utils.DiscoveryV5Flag, 210 utils.NetrestrictFlag, 211 utils.NodeKeyFileFlag, 212 utils.NodeKeyHexFlag, 213 utils.MaxPeersFlag, 214 utils.NATFlag, 215 utils.IPCDisabledFlag, 216 utils.IPCApiFlag, 217 utils.IPCPathFlag, 218 // bzzd-specific flags 219 CorsStringFlag, 220 EthAPIFlag, 221 SwarmConfigPathFlag, 222 SwarmSwapEnabledFlag, 223 SwarmSyncEnabledFlag, 224 SwarmPortFlag, 225 SwarmAccountFlag, 226 SwarmNetworkIdFlag, 227 ChequebookAddrFlag, 228 // upload flags 229 SwarmApiFlag, 230 SwarmRecursiveUploadFlag, 231 SwarmWantManifestFlag, 232 SwarmUploadDefaultPath, 233 } 234 app.Flags = append(app.Flags, debug.Flags...) 235 app.Before = func(ctx *cli.Context) error { 236 runtime.GOMAXPROCS(runtime.NumCPU()) 237 return debug.Setup(ctx) 238 } 239 app.After = func(ctx *cli.Context) error { 240 debug.Exit() 241 return nil 242 } 243 } 244 245 func main() { 246 if err := app.Run(os.Args); err != nil { 247 fmt.Fprintln(os.Stderr, err) 248 os.Exit(1) 249 } 250 } 251 252 func version(ctx *cli.Context) error { 253 fmt.Println(strings.Title(clientIdentifier)) 254 fmt.Println("Version:", versionString) 255 if gitCommit != "" { 256 fmt.Println("Git Commit:", gitCommit) 257 } 258 fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name)) 259 fmt.Println("Go Version:", runtime.Version()) 260 fmt.Println("OS:", runtime.GOOS) 261 fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) 262 fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) 263 return nil 264 } 265 266 func bzzd(ctx *cli.Context) error { 267 stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) 268 registerBzzService(ctx, stack) 269 utils.StartNode(stack) 270 go func() { 271 sigc := make(chan os.Signal, 1) 272 signal.Notify(sigc, syscall.SIGTERM) 273 defer signal.Stop(sigc) 274 <-sigc 275 glog.V(logger.Info).Infoln("Got sigterm, shutting down...") 276 stack.Stop() 277 }() 278 networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name) 279 // Add bootnodes as initial peers. 280 if ctx.GlobalIsSet(utils.BootnodesFlag.Name) { 281 bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",") 282 injectBootnodes(stack.Server(), bootnodes) 283 } else { 284 if networkId == 3 { 285 injectBootnodes(stack.Server(), testbetBootNodes) 286 } 287 } 288 289 stack.Wait() 290 return nil 291 } 292 293 func registerBzzService(ctx *cli.Context, stack *node.Node) { 294 295 prvkey := getAccount(ctx, stack) 296 297 chbookaddr := common.HexToAddress(ctx.GlobalString(ChequebookAddrFlag.Name)) 298 bzzdir := ctx.GlobalString(SwarmConfigPathFlag.Name) 299 if bzzdir == "" { 300 bzzdir = stack.InstanceDir() 301 } 302 303 bzzconfig, err := bzzapi.NewConfig(bzzdir, chbookaddr, prvkey, ctx.GlobalUint64(SwarmNetworkIdFlag.Name)) 304 if err != nil { 305 utils.Fatalf("unable to configure swarm: %v", err) 306 } 307 bzzport := ctx.GlobalString(SwarmPortFlag.Name) 308 if len(bzzport) > 0 { 309 bzzconfig.Port = bzzport 310 } 311 swapEnabled := ctx.GlobalBool(SwarmSwapEnabledFlag.Name) 312 syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabledFlag.Name) 313 314 ethapi := ctx.GlobalString(EthAPIFlag.Name) 315 cors := ctx.GlobalString(CorsStringFlag.Name) 316 317 boot := func(ctx *node.ServiceContext) (node.Service, error) { 318 var client *ethclient.Client 319 if len(ethapi) > 0 { 320 client, err = ethclient.Dial(ethapi) 321 if err != nil { 322 utils.Fatalf("Can't connect: %v", err) 323 } 324 } 325 return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors) 326 } 327 if err := stack.Register(boot); err != nil { 328 utils.Fatalf("Failed to register the Swarm service: %v", err) 329 } 330 } 331 332 func getAccount(ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { 333 keyid := ctx.GlobalString(SwarmAccountFlag.Name) 334 335 if keyid == "" { 336 utils.Fatalf("Option %q is required", SwarmAccountFlag.Name) 337 } 338 // Try to load the arg as a hex key file. 339 if key, err := crypto.LoadECDSA(keyid); err == nil { 340 glog.V(logger.Info).Infof("swarm account key loaded: %#x", crypto.PubkeyToAddress(key.PublicKey)) 341 return key 342 } 343 // Otherwise try getting it from the keystore. 344 am := stack.AccountManager() 345 ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 346 347 return decryptStoreAccount(ks, keyid) 348 } 349 350 func decryptStoreAccount(ks *keystore.KeyStore, account string) *ecdsa.PrivateKey { 351 var a accounts.Account 352 var err error 353 if common.IsHexAddress(account) { 354 a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)}) 355 } else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 { 356 if accounts := ks.Accounts(); len(accounts) > ix { 357 a = accounts[ix] 358 } else { 359 err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts)) 360 } 361 } else { 362 utils.Fatalf("Can't find swarm account key %s", account) 363 } 364 if err != nil { 365 utils.Fatalf("Can't find swarm account key: %v", err) 366 } 367 keyjson, err := ioutil.ReadFile(a.URL.Path) 368 if err != nil { 369 utils.Fatalf("Can't load swarm account key: %v", err) 370 } 371 for i := 1; i <= 3; i++ { 372 passphrase := promptPassphrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i)) 373 key, err := keystore.DecryptKey(keyjson, passphrase) 374 if err == nil { 375 return key.PrivateKey 376 } 377 } 378 utils.Fatalf("Can't decrypt swarm account key") 379 return nil 380 } 381 382 func promptPassphrase(prompt string) string { 383 if prompt != "" { 384 fmt.Println(prompt) 385 } 386 password, err := console.Stdin.PromptPassword("Passphrase: ") 387 if err != nil { 388 utils.Fatalf("Failed to read passphrase: %v", err) 389 } 390 return password 391 } 392 393 func injectBootnodes(srv *p2p.Server, nodes []string) { 394 for _, url := range nodes { 395 n, err := discover.ParseNode(url) 396 if err != nil { 397 glog.Errorf("invalid bootnode %q", err) 398 continue 399 } 400 srv.AddPeer(n) 401 } 402 }