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