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