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