github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/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 "sort" 27 "strconv" 28 "strings" 29 "syscall" 30 31 "github.com/ethereum/go-ethereum/accounts" 32 "github.com/ethereum/go-ethereum/accounts/keystore" 33 "github.com/ethereum/go-ethereum/cmd/utils" 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/console" 36 "github.com/ethereum/go-ethereum/crypto" 37 "github.com/ethereum/go-ethereum/internal/debug" 38 "github.com/ethereum/go-ethereum/log" 39 "github.com/ethereum/go-ethereum/node" 40 "github.com/ethereum/go-ethereum/p2p" 41 "github.com/ethereum/go-ethereum/p2p/discover" 42 "github.com/ethereum/go-ethereum/swarm" 43 bzzapi "github.com/ethereum/go-ethereum/swarm/api" 44 swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics" 45 "github.com/ethereum/go-ethereum/swarm/tracing" 46 sv "github.com/ethereum/go-ethereum/swarm/version" 47 48 "gopkg.in/urfave/cli.v1" 49 ) 50 51 const clientIdentifier = "swarm" 52 const helpTemplate = `NAME: 53 {{.HelpName}} - {{.Usage}} 54 55 USAGE: 56 {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} 57 58 CATEGORY: 59 {{.Category}}{{end}}{{if .Description}} 60 61 DESCRIPTION: 62 {{.Description}}{{end}}{{if .VisibleFlags}} 63 64 OPTIONS: 65 {{range .VisibleFlags}}{{.}} 66 {{end}}{{end}} 67 ` 68 69 var ( 70 gitCommit string // Git SHA1 commit hash of the release (set via linker flags) 71 testbetBootNodes = []string{ 72 "enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429", 73 "enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430", 74 "enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431", 75 "enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432", 76 "enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433", 77 } 78 ) 79 80 var ( 81 ChequebookAddrFlag = cli.StringFlag{ 82 Name: "chequebook", 83 Usage: "chequebook contract address", 84 EnvVar: SWARM_ENV_CHEQUEBOOK_ADDR, 85 } 86 SwarmAccountFlag = cli.StringFlag{ 87 Name: "bzzaccount", 88 Usage: "Swarm account key file", 89 EnvVar: SWARM_ENV_ACCOUNT, 90 } 91 SwarmListenAddrFlag = cli.StringFlag{ 92 Name: "httpaddr", 93 Usage: "Swarm HTTP API listening interface", 94 EnvVar: SWARM_ENV_LISTEN_ADDR, 95 } 96 SwarmPortFlag = cli.StringFlag{ 97 Name: "bzzport", 98 Usage: "Swarm local http api port", 99 EnvVar: SWARM_ENV_PORT, 100 } 101 SwarmNetworkIdFlag = cli.IntFlag{ 102 Name: "bzznetworkid", 103 Usage: "Network identifier (integer, default 3=swarm testnet)", 104 EnvVar: SWARM_ENV_NETWORK_ID, 105 } 106 SwarmSwapEnabledFlag = cli.BoolFlag{ 107 Name: "swap", 108 Usage: "Swarm SWAP enabled (default false)", 109 EnvVar: SWARM_ENV_SWAP_ENABLE, 110 } 111 SwarmSwapAPIFlag = cli.StringFlag{ 112 Name: "swap-api", 113 Usage: "URL of the Ethereum API provider to use to settle SWAP payments", 114 EnvVar: SWARM_ENV_SWAP_API, 115 } 116 SwarmSyncDisabledFlag = cli.BoolTFlag{ 117 Name: "nosync", 118 Usage: "Disable swarm syncing", 119 EnvVar: SWARM_ENV_SYNC_DISABLE, 120 } 121 SwarmSyncUpdateDelay = cli.DurationFlag{ 122 Name: "sync-update-delay", 123 Usage: "Duration for sync subscriptions update after no new peers are added (default 15s)", 124 EnvVar: SWARM_ENV_SYNC_UPDATE_DELAY, 125 } 126 SwarmLightNodeEnabled = cli.BoolFlag{ 127 Name: "lightnode", 128 Usage: "Enable Swarm LightNode (default false)", 129 EnvVar: SWARM_ENV_LIGHT_NODE_ENABLE, 130 } 131 SwarmDeliverySkipCheckFlag = cli.BoolFlag{ 132 Name: "delivery-skip-check", 133 Usage: "Skip chunk delivery check (default false)", 134 EnvVar: SWARM_ENV_DELIVERY_SKIP_CHECK, 135 } 136 EnsAPIFlag = cli.StringSliceFlag{ 137 Name: "ens-api", 138 Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url", 139 EnvVar: SWARM_ENV_ENS_API, 140 } 141 SwarmApiFlag = cli.StringFlag{ 142 Name: "bzzapi", 143 Usage: "Swarm HTTP endpoint", 144 Value: "http://127.0.0.1:8500", 145 } 146 SwarmRecursiveFlag = cli.BoolFlag{ 147 Name: "recursive", 148 Usage: "Upload directories recursively", 149 } 150 SwarmWantManifestFlag = cli.BoolTFlag{ 151 Name: "manifest", 152 Usage: "Automatic manifest upload (default true)", 153 } 154 SwarmUploadDefaultPath = cli.StringFlag{ 155 Name: "defaultpath", 156 Usage: "path to file served for empty url path (none)", 157 } 158 SwarmUpFromStdinFlag = cli.BoolFlag{ 159 Name: "stdin", 160 Usage: "reads data to be uploaded from stdin", 161 } 162 SwarmUploadMimeType = cli.StringFlag{ 163 Name: "mime", 164 Usage: "Manually specify MIME type", 165 } 166 SwarmEncryptedFlag = cli.BoolFlag{ 167 Name: "encrypt", 168 Usage: "use encrypted upload", 169 } 170 CorsStringFlag = cli.StringFlag{ 171 Name: "corsdomain", 172 Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')", 173 EnvVar: SWARM_ENV_CORS, 174 } 175 SwarmStorePath = cli.StringFlag{ 176 Name: "store.path", 177 Usage: "Path to leveldb chunk DB (default <$GETH_ENV_DIR>/swarm/bzz-<$BZZ_KEY>/chunks)", 178 EnvVar: SWARM_ENV_STORE_PATH, 179 } 180 SwarmStoreCapacity = cli.Uint64Flag{ 181 Name: "store.size", 182 Usage: "Number of chunks (5M is roughly 20-25GB) (default 5000000)", 183 EnvVar: SWARM_ENV_STORE_CAPACITY, 184 } 185 SwarmStoreCacheCapacity = cli.UintFlag{ 186 Name: "store.cache.size", 187 Usage: "Number of recent chunks cached in memory (default 5000)", 188 EnvVar: SWARM_ENV_STORE_CACHE_CAPACITY, 189 } 190 SwarmResourceMultihashFlag = cli.BoolFlag{ 191 Name: "multihash", 192 Usage: "Determines how to interpret data for a resource update. If not present, data will be interpreted as raw, literal data that will be included in the resource", 193 } 194 SwarmResourceNameFlag = cli.StringFlag{ 195 Name: "name", 196 Usage: "User-defined name for the new resource", 197 } 198 SwarmResourceDataOnCreateFlag = cli.StringFlag{ 199 Name: "data", 200 Usage: "Initializes the resource with the given hex-encoded data. Data must be prefixed by 0x", 201 } 202 ) 203 204 //declare a few constant error messages, useful for later error check comparisons in test 205 var ( 206 SWARM_ERR_NO_BZZACCOUNT = "bzzaccount option is required but not set; check your config file, command line or environment variables" 207 SWARM_ERR_SWAP_SET_NO_API = "SWAP is enabled but --swap-api is not set" 208 ) 209 210 // this help command gets added to any subcommand that does not define it explicitly 211 var defaultSubcommandHelp = cli.Command{ 212 Action: func(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "", 1) }, 213 CustomHelpTemplate: helpTemplate, 214 Name: "help", 215 Usage: "shows this help", 216 Hidden: true, 217 } 218 219 var defaultNodeConfig = node.DefaultConfig 220 221 // This init function sets defaults so cmd/swarm can run alongside geth. 222 func init() { 223 defaultNodeConfig.Name = clientIdentifier 224 defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit) 225 defaultNodeConfig.P2P.ListenAddr = ":30399" 226 defaultNodeConfig.IPCPath = "bzzd.ipc" 227 // Set flag defaults for --help display. 228 utils.ListenPortFlag.Value = 30399 229 } 230 231 var app = utils.NewApp(gitCommit, "Ethereum Swarm") 232 233 // This init function creates the cli.App. 234 func init() { 235 app.Action = bzzd 236 app.HideVersion = true // we have a command to print the version 237 app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" 238 app.Commands = []cli.Command{ 239 { 240 Action: version, 241 CustomHelpTemplate: helpTemplate, 242 Name: "version", 243 Usage: "Print version numbers", 244 Description: "The output of this command is supposed to be machine-readable", 245 }, 246 { 247 Action: upload, 248 CustomHelpTemplate: helpTemplate, 249 Name: "up", 250 Usage: "uploads a file or directory to swarm using the HTTP API", 251 ArgsUsage: "<file>", 252 Flags: []cli.Flag{SwarmEncryptedFlag}, 253 Description: "uploads a file or directory to swarm using the HTTP API and prints the root hash", 254 }, 255 { 256 CustomHelpTemplate: helpTemplate, 257 Name: "resource", 258 Usage: "(Advanced) Create and update Mutable Resources", 259 ArgsUsage: "<create|update|info>", 260 Description: "Works with Mutable Resource Updates", 261 Subcommands: []cli.Command{ 262 { 263 Action: resourceCreate, 264 CustomHelpTemplate: helpTemplate, 265 Name: "create", 266 Usage: "creates a new Mutable Resource", 267 ArgsUsage: "<frequency>", 268 Description: "creates a new Mutable Resource", 269 Flags: []cli.Flag{SwarmResourceNameFlag, SwarmResourceDataOnCreateFlag, SwarmResourceMultihashFlag}, 270 }, 271 { 272 Action: resourceUpdate, 273 CustomHelpTemplate: helpTemplate, 274 Name: "update", 275 Usage: "updates the content of an existing Mutable Resource", 276 ArgsUsage: "<Manifest Address or ENS domain> <0x Hex data>", 277 Description: "updates the content of an existing Mutable Resource", 278 Flags: []cli.Flag{SwarmResourceMultihashFlag}, 279 }, 280 { 281 Action: resourceInfo, 282 CustomHelpTemplate: helpTemplate, 283 Name: "info", 284 Usage: "obtains information about an existing Mutable Resource", 285 ArgsUsage: "<Manifest Address or ENS domain>", 286 Description: "obtains information about an existing Mutable Resource", 287 }, 288 }, 289 }, 290 { 291 Action: list, 292 CustomHelpTemplate: helpTemplate, 293 Name: "ls", 294 Usage: "list files and directories contained in a manifest", 295 ArgsUsage: "<manifest> [<prefix>]", 296 Description: "Lists files and directories contained in a manifest", 297 }, 298 { 299 Action: hash, 300 CustomHelpTemplate: helpTemplate, 301 Name: "hash", 302 Usage: "print the swarm hash of a file or directory", 303 ArgsUsage: "<file>", 304 Description: "Prints the swarm hash of file or directory", 305 }, 306 { 307 Action: download, 308 Name: "down", 309 Flags: []cli.Flag{SwarmRecursiveFlag}, 310 Usage: "downloads a swarm manifest or a file inside a manifest", 311 ArgsUsage: " <uri> [<dir>]", 312 Description: ` 313 Downloads a swarm bzz uri to the given dir. When no dir is provided, working directory is assumed. --recursive flag is expected when downloading a manifest with multiple entries. 314 `, 315 }, 316 317 { 318 Name: "manifest", 319 CustomHelpTemplate: helpTemplate, 320 Usage: "perform operations on swarm manifests", 321 ArgsUsage: "COMMAND", 322 Description: "Updates a MANIFEST by adding/removing/updating the hash of a path.\nCOMMAND could be: add, update, remove", 323 Subcommands: []cli.Command{ 324 { 325 Action: add, 326 CustomHelpTemplate: helpTemplate, 327 Name: "add", 328 Usage: "add a new path to the manifest", 329 ArgsUsage: "<MANIFEST> <path> <hash> [<content-type>]", 330 Description: "Adds a new path to the manifest", 331 }, 332 { 333 Action: update, 334 CustomHelpTemplate: helpTemplate, 335 Name: "update", 336 Usage: "update the hash for an already existing path in the manifest", 337 ArgsUsage: "<MANIFEST> <path> <newhash> [<newcontent-type>]", 338 Description: "Update the hash for an already existing path in the manifest", 339 }, 340 { 341 Action: remove, 342 CustomHelpTemplate: helpTemplate, 343 Name: "remove", 344 Usage: "removes a path from the manifest", 345 ArgsUsage: "<MANIFEST> <path>", 346 Description: "Removes a path from the manifest", 347 }, 348 }, 349 }, 350 { 351 Name: "fs", 352 CustomHelpTemplate: helpTemplate, 353 Usage: "perform FUSE operations", 354 ArgsUsage: "fs COMMAND", 355 Description: "Performs FUSE operations by mounting/unmounting/listing mount points. This assumes you already have a Swarm node running locally. For all operation you must reference the correct path to bzzd.ipc in order to communicate with the node", 356 Subcommands: []cli.Command{ 357 { 358 Action: mount, 359 CustomHelpTemplate: helpTemplate, 360 Name: "mount", 361 Flags: []cli.Flag{utils.IPCPathFlag}, 362 Usage: "mount a swarm hash to a mount point", 363 ArgsUsage: "swarm fs mount --ipcpath <path to bzzd.ipc> <manifest hash> <mount point>", 364 Description: "Mounts a Swarm manifest hash to a given mount point. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", 365 }, 366 { 367 Action: unmount, 368 CustomHelpTemplate: helpTemplate, 369 Name: "unmount", 370 Flags: []cli.Flag{utils.IPCPathFlag}, 371 Usage: "unmount a swarmfs mount", 372 ArgsUsage: "swarm fs unmount --ipcpath <path to bzzd.ipc> <mount point>", 373 Description: "Unmounts a swarmfs mount residing at <mount point>. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", 374 }, 375 { 376 Action: listMounts, 377 CustomHelpTemplate: helpTemplate, 378 Name: "list", 379 Flags: []cli.Flag{utils.IPCPathFlag}, 380 Usage: "list swarmfs mounts", 381 ArgsUsage: "swarm fs list --ipcpath <path to bzzd.ipc>", 382 Description: "Lists all mounted swarmfs volumes. This assumes you already have a Swarm node running locally. You must reference the correct path to your bzzd.ipc file", 383 }, 384 }, 385 }, 386 { 387 Name: "db", 388 CustomHelpTemplate: helpTemplate, 389 Usage: "manage the local chunk database", 390 ArgsUsage: "db COMMAND", 391 Description: "Manage the local chunk database", 392 Subcommands: []cli.Command{ 393 { 394 Action: dbExport, 395 CustomHelpTemplate: helpTemplate, 396 Name: "export", 397 Usage: "export a local chunk database as a tar archive (use - to send to stdout)", 398 ArgsUsage: "<chunkdb> <file>", 399 Description: ` 400 Export a local chunk database as a tar archive (use - to send to stdout). 401 402 swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar 403 404 The export may be quite large, consider piping the output through the Unix 405 pv(1) tool to get a progress bar: 406 407 swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar 408 `, 409 }, 410 { 411 Action: dbImport, 412 CustomHelpTemplate: helpTemplate, 413 Name: "import", 414 Usage: "import chunks from a tar archive into a local chunk database (use - to read from stdin)", 415 ArgsUsage: "<chunkdb> <file>", 416 Description: ` 417 Import chunks from a tar archive into a local chunk database (use - to read from stdin). 418 419 swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar 420 421 The import may be quite large, consider piping the input through the Unix 422 pv(1) tool to get a progress bar: 423 424 pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks - 425 `, 426 }, 427 { 428 Action: dbClean, 429 CustomHelpTemplate: helpTemplate, 430 Name: "clean", 431 Usage: "remove corrupt entries from a local chunk database", 432 ArgsUsage: "<chunkdb>", 433 Description: "Remove corrupt entries from a local chunk database", 434 }, 435 }, 436 }, 437 438 // See config.go 439 DumpConfigCommand, 440 } 441 442 // append a hidden help subcommand to all commands that have subcommands 443 // if a help command was already defined above, that one will take precedence. 444 addDefaultHelpSubcommands(app.Commands) 445 446 sort.Sort(cli.CommandsByName(app.Commands)) 447 448 app.Flags = []cli.Flag{ 449 utils.IdentityFlag, 450 utils.DataDirFlag, 451 utils.BootnodesFlag, 452 utils.KeyStoreDirFlag, 453 utils.ListenPortFlag, 454 utils.NoDiscoverFlag, 455 utils.DiscoveryV5Flag, 456 utils.NetrestrictFlag, 457 utils.NodeKeyFileFlag, 458 utils.NodeKeyHexFlag, 459 utils.MaxPeersFlag, 460 utils.NATFlag, 461 utils.IPCDisabledFlag, 462 utils.IPCPathFlag, 463 utils.PasswordFileFlag, 464 // bzzd-specific flags 465 CorsStringFlag, 466 EnsAPIFlag, 467 SwarmTomlConfigPathFlag, 468 SwarmSwapEnabledFlag, 469 SwarmSwapAPIFlag, 470 SwarmSyncDisabledFlag, 471 SwarmSyncUpdateDelay, 472 SwarmLightNodeEnabled, 473 SwarmDeliverySkipCheckFlag, 474 SwarmListenAddrFlag, 475 SwarmPortFlag, 476 SwarmAccountFlag, 477 SwarmNetworkIdFlag, 478 ChequebookAddrFlag, 479 // upload flags 480 SwarmApiFlag, 481 SwarmRecursiveFlag, 482 SwarmWantManifestFlag, 483 SwarmUploadDefaultPath, 484 SwarmUpFromStdinFlag, 485 SwarmUploadMimeType, 486 // storage flags 487 SwarmStorePath, 488 SwarmStoreCapacity, 489 SwarmStoreCacheCapacity, 490 } 491 rpcFlags := []cli.Flag{ 492 utils.WSEnabledFlag, 493 utils.WSListenAddrFlag, 494 utils.WSPortFlag, 495 utils.WSApiFlag, 496 utils.WSAllowedOriginsFlag, 497 } 498 app.Flags = append(app.Flags, rpcFlags...) 499 app.Flags = append(app.Flags, debug.Flags...) 500 app.Flags = append(app.Flags, swarmmetrics.Flags...) 501 app.Flags = append(app.Flags, tracing.Flags...) 502 app.Before = func(ctx *cli.Context) error { 503 runtime.GOMAXPROCS(runtime.NumCPU()) 504 if err := debug.Setup(ctx, ""); err != nil { 505 return err 506 } 507 swarmmetrics.Setup(ctx) 508 tracing.Setup(ctx) 509 return nil 510 } 511 app.After = func(ctx *cli.Context) error { 512 debug.Exit() 513 return nil 514 } 515 } 516 517 func main() { 518 if err := app.Run(os.Args); err != nil { 519 fmt.Fprintln(os.Stderr, err) 520 os.Exit(1) 521 } 522 } 523 524 func version(ctx *cli.Context) error { 525 fmt.Println(strings.Title(clientIdentifier)) 526 fmt.Println("Version:", sv.VersionWithMeta) 527 if gitCommit != "" { 528 fmt.Println("Git Commit:", gitCommit) 529 } 530 fmt.Println("Go Version:", runtime.Version()) 531 fmt.Println("OS:", runtime.GOOS) 532 return nil 533 } 534 535 func bzzd(ctx *cli.Context) error { 536 //build a valid bzzapi.Config from all available sources: 537 //default config, file config, command line and env vars 538 bzzconfig, err := buildConfig(ctx) 539 if err != nil { 540 utils.Fatalf("unable to configure swarm: %v", err) 541 } 542 543 cfg := defaultNodeConfig 544 545 //pss operates on ws 546 cfg.WSModules = append(cfg.WSModules, "pss") 547 548 //geth only supports --datadir via command line 549 //in order to be consistent within swarm, if we pass --datadir via environment variable 550 //or via config file, we get the same directory for geth and swarm 551 if _, err := os.Stat(bzzconfig.Path); err == nil { 552 cfg.DataDir = bzzconfig.Path 553 } 554 //setup the ethereum node 555 utils.SetNodeConfig(ctx, &cfg) 556 stack, err := node.New(&cfg) 557 if err != nil { 558 utils.Fatalf("can't create node: %v", err) 559 } 560 //a few steps need to be done after the config phase is completed, 561 //due to overriding behavior 562 initSwarmNode(bzzconfig, stack, ctx) 563 //register BZZ as node.Service in the ethereum node 564 registerBzzService(bzzconfig, stack) 565 //start the node 566 utils.StartNode(stack) 567 568 go func() { 569 sigc := make(chan os.Signal, 1) 570 signal.Notify(sigc, syscall.SIGTERM) 571 defer signal.Stop(sigc) 572 <-sigc 573 log.Info("Got sigterm, shutting swarm down...") 574 stack.Stop() 575 }() 576 577 // Add bootnodes as initial peers. 578 if bzzconfig.BootNodes != "" { 579 bootnodes := strings.Split(bzzconfig.BootNodes, ",") 580 injectBootnodes(stack.Server(), bootnodes) 581 } else { 582 if bzzconfig.NetworkID == 3 { 583 injectBootnodes(stack.Server(), testbetBootNodes) 584 } 585 } 586 587 stack.Wait() 588 return nil 589 } 590 591 func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) { 592 //define the swarm service boot function 593 boot := func(_ *node.ServiceContext) (node.Service, error) { 594 // In production, mockStore must be always nil. 595 return swarm.NewSwarm(bzzconfig, nil) 596 } 597 //register within the ethereum node 598 if err := stack.Register(boot); err != nil { 599 utils.Fatalf("Failed to register the Swarm service: %v", err) 600 } 601 } 602 603 func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { 604 //an account is mandatory 605 if bzzaccount == "" { 606 utils.Fatalf(SWARM_ERR_NO_BZZACCOUNT) 607 } 608 // Try to load the arg as a hex key file. 609 if key, err := crypto.LoadECDSA(bzzaccount); err == nil { 610 log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey)) 611 return key 612 } 613 // Otherwise try getting it from the keystore. 614 am := stack.AccountManager() 615 ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 616 617 return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx)) 618 } 619 620 // getPrivKey returns the private key of the specified bzzaccount 621 // Used only by client commands, such as `resource` 622 func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey { 623 // booting up the swarm node just as we do in bzzd action 624 bzzconfig, err := buildConfig(ctx) 625 if err != nil { 626 utils.Fatalf("unable to configure swarm: %v", err) 627 } 628 cfg := defaultNodeConfig 629 if _, err := os.Stat(bzzconfig.Path); err == nil { 630 cfg.DataDir = bzzconfig.Path 631 } 632 utils.SetNodeConfig(ctx, &cfg) 633 stack, err := node.New(&cfg) 634 if err != nil { 635 utils.Fatalf("can't create node: %v", err) 636 } 637 return getAccount(bzzconfig.BzzAccount, ctx, stack) 638 } 639 640 func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey { 641 var a accounts.Account 642 var err error 643 if common.IsHexAddress(account) { 644 a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)}) 645 } else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 { 646 if accounts := ks.Accounts(); len(accounts) > ix { 647 a = accounts[ix] 648 } else { 649 err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts)) 650 } 651 } else { 652 utils.Fatalf("Can't find swarm account key %s", account) 653 } 654 if err != nil { 655 utils.Fatalf("Can't find swarm account key: %v - Is the provided bzzaccount(%s) from the right datadir/Path?", err, account) 656 } 657 keyjson, err := ioutil.ReadFile(a.URL.Path) 658 if err != nil { 659 utils.Fatalf("Can't load swarm account key: %v", err) 660 } 661 for i := 0; i < 3; i++ { 662 password := getPassPhrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i+1), i, passwords) 663 key, err := keystore.DecryptKey(keyjson, password) 664 if err == nil { 665 return key.PrivateKey 666 } 667 } 668 utils.Fatalf("Can't decrypt swarm account key") 669 return nil 670 } 671 672 // getPassPhrase retrieves the password associated with bzz account, either by fetching 673 // from a list of pre-loaded passwords, or by requesting it interactively from user. 674 func getPassPhrase(prompt string, i int, passwords []string) string { 675 // non-interactive 676 if len(passwords) > 0 { 677 if i < len(passwords) { 678 return passwords[i] 679 } 680 return passwords[len(passwords)-1] 681 } 682 683 // fallback to interactive mode 684 if prompt != "" { 685 fmt.Println(prompt) 686 } 687 password, err := console.Stdin.PromptPassword("Passphrase: ") 688 if err != nil { 689 utils.Fatalf("Failed to read passphrase: %v", err) 690 } 691 return password 692 } 693 694 func injectBootnodes(srv *p2p.Server, nodes []string) { 695 for _, url := range nodes { 696 n, err := discover.ParseNode(url) 697 if err != nil { 698 log.Error("Invalid swarm bootnode", "err", err) 699 continue 700 } 701 srv.AddPeer(n) 702 } 703 } 704 705 // addDefaultHelpSubcommand scans through defined CLI commands and adds 706 // a basic help subcommand to each 707 // if a help command is already defined, it will take precedence over the default. 708 func addDefaultHelpSubcommands(commands []cli.Command) { 709 for i := range commands { 710 cmd := &commands[i] 711 if cmd.Subcommands != nil { 712 cmd.Subcommands = append(cmd.Subcommands, defaultSubcommandHelp) 713 addDefaultHelpSubcommands(cmd.Subcommands) 714 } 715 } 716 }