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  }