github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/swarm/main.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:33</date>
    10  //</624450071114551296>
    11  
    12  
    13  package main
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"encoding/hex"
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"os/signal"
    22  	"runtime"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"syscall"
    27  
    28  	"github.com/ethereum/go-ethereum/accounts"
    29  	"github.com/ethereum/go-ethereum/accounts/keystore"
    30  	"github.com/ethereum/go-ethereum/cmd/utils"
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/console"
    33  	"github.com/ethereum/go-ethereum/crypto"
    34  	"github.com/ethereum/go-ethereum/internal/debug"
    35  	"github.com/ethereum/go-ethereum/log"
    36  	"github.com/ethereum/go-ethereum/node"
    37  	"github.com/ethereum/go-ethereum/p2p/enode"
    38  	"github.com/ethereum/go-ethereum/swarm"
    39  	bzzapi "github.com/ethereum/go-ethereum/swarm/api"
    40  	swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
    41  	"github.com/ethereum/go-ethereum/swarm/tracing"
    42  	sv "github.com/ethereum/go-ethereum/swarm/version"
    43  
    44  	"gopkg.in/urfave/cli.v1"
    45  )
    46  
    47  const clientIdentifier = "swarm"
    48  const helpTemplate = `NAME:
    49  {{.HelpName}} - {{.Usage}}
    50  
    51  USAGE:
    52  {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
    53  
    54  CATEGORY:
    55  {{.Category}}{{end}}{{if .Description}}
    56  
    57  DESCRIPTION:
    58  {{.Description}}{{end}}{{if .VisibleFlags}}
    59  
    60  OPTIONS:
    61  {{range .VisibleFlags}}{{.}}
    62  {{end}}{{end}}
    63  `
    64  
    65  var (
    66  gitCommit string //git sha1提交发布的哈希(通过链接器标志设置)
    67  )
    68  
    69  //声明几个常量错误消息,对以后测试中的错误检查比较很有用
    70  var (
    71  	SWARM_ERR_NO_BZZACCOUNT   = "bzzaccount option is required but not set; check your config file, command line or environment variables"
    72  	SWARM_ERR_SWAP_SET_NO_API = "SWAP is enabled but --swap-api is not set"
    73  )
    74  
    75  //此帮助命令将添加到未显式定义它的任何子命令中
    76  var defaultSubcommandHelp = cli.Command{
    77  	Action:             func(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "", 1) },
    78  	CustomHelpTemplate: helpTemplate,
    79  	Name:               "help",
    80  	Usage:              "shows this help",
    81  	Hidden:             true,
    82  }
    83  
    84  var defaultNodeConfig = node.DefaultConfig
    85  
    86  //这个init函数设置默认值,以便cmd/swarm可以与geth一起运行。
    87  func init() {
    88  	defaultNodeConfig.Name = clientIdentifier
    89  	defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit)
    90  	defaultNodeConfig.P2P.ListenAddr = ":30399"
    91  	defaultNodeConfig.IPCPath = "bzzd.ipc"
    92  //设置--help显示的标志默认值。
    93  	utils.ListenPortFlag.Value = 30399
    94  }
    95  
    96  var app = utils.NewApp("", "Ethereum Swarm")
    97  
    98  //这个init函数创建cli.app。
    99  func init() {
   100  	app.Action = bzzd
   101  	app.Version = sv.ArchiveVersion(gitCommit)
   102  	app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
   103  	app.Commands = []cli.Command{
   104  		{
   105  			Action:             version,
   106  			CustomHelpTemplate: helpTemplate,
   107  			Name:               "version",
   108  			Usage:              "Print version numbers",
   109  			Description:        "The output of this command is supposed to be machine-readable",
   110  		},
   111  		{
   112  			Action:             keys,
   113  			CustomHelpTemplate: helpTemplate,
   114  			Name:               "print-keys",
   115  			Flags:              []cli.Flag{SwarmCompressedFlag},
   116  			Usage:              "Print public key information",
   117  			Description:        "The output of this command is supposed to be machine-readable",
   118  		},
   119  //看上传
   120  		upCommand,
   121  //参见Access
   122  		accessCommand,
   123  //见饲料
   124  		feedCommand,
   125  //参见List.Go
   126  		listCommand,
   127  //看HAH.GO
   128  		hashCommand,
   129  //参见下载
   130  		downloadCommand,
   131  //见宣言
   132  		manifestCommand,
   133  //见鬼去吧
   134  		fsCommand,
   135  //参见D.Go
   136  		dbCommand,
   137  //参见CONG.GO
   138  		DumpConfigCommand,
   139  	}
   140  
   141  //将隐藏的帮助子命令附加到具有子命令的所有命令
   142  //如果上面已经定义了帮助命令,则该命令将优先。
   143  	addDefaultHelpSubcommands(app.Commands)
   144  
   145  	sort.Sort(cli.CommandsByName(app.Commands))
   146  
   147  	app.Flags = []cli.Flag{
   148  		utils.IdentityFlag,
   149  		utils.DataDirFlag,
   150  		utils.BootnodesFlag,
   151  		utils.KeyStoreDirFlag,
   152  		utils.ListenPortFlag,
   153  		utils.NoDiscoverFlag,
   154  		utils.DiscoveryV5Flag,
   155  		utils.NetrestrictFlag,
   156  		utils.NodeKeyFileFlag,
   157  		utils.NodeKeyHexFlag,
   158  		utils.MaxPeersFlag,
   159  		utils.NATFlag,
   160  		utils.IPCDisabledFlag,
   161  		utils.IPCPathFlag,
   162  		utils.PasswordFileFlag,
   163  //BZZD特定标志
   164  		CorsStringFlag,
   165  		EnsAPIFlag,
   166  		SwarmTomlConfigPathFlag,
   167  		SwarmSwapEnabledFlag,
   168  		SwarmSwapAPIFlag,
   169  		SwarmSyncDisabledFlag,
   170  		SwarmSyncUpdateDelay,
   171  		SwarmMaxStreamPeerServersFlag,
   172  		SwarmLightNodeEnabled,
   173  		SwarmDeliverySkipCheckFlag,
   174  		SwarmListenAddrFlag,
   175  		SwarmPortFlag,
   176  		SwarmAccountFlag,
   177  		SwarmNetworkIdFlag,
   178  		ChequebookAddrFlag,
   179  //上传标志
   180  		SwarmApiFlag,
   181  		SwarmRecursiveFlag,
   182  		SwarmWantManifestFlag,
   183  		SwarmUploadDefaultPath,
   184  		SwarmUpFromStdinFlag,
   185  		SwarmUploadMimeType,
   186  //存储标志
   187  		SwarmStorePath,
   188  		SwarmStoreCapacity,
   189  		SwarmStoreCacheCapacity,
   190  	}
   191  	rpcFlags := []cli.Flag{
   192  		utils.WSEnabledFlag,
   193  		utils.WSListenAddrFlag,
   194  		utils.WSPortFlag,
   195  		utils.WSApiFlag,
   196  		utils.WSAllowedOriginsFlag,
   197  	}
   198  	app.Flags = append(app.Flags, rpcFlags...)
   199  	app.Flags = append(app.Flags, debug.Flags...)
   200  	app.Flags = append(app.Flags, swarmmetrics.Flags...)
   201  	app.Flags = append(app.Flags, tracing.Flags...)
   202  	app.Before = func(ctx *cli.Context) error {
   203  		runtime.GOMAXPROCS(runtime.NumCPU())
   204  		if err := debug.Setup(ctx, ""); err != nil {
   205  			return err
   206  		}
   207  		swarmmetrics.Setup(ctx)
   208  		tracing.Setup(ctx)
   209  		return nil
   210  	}
   211  	app.After = func(ctx *cli.Context) error {
   212  		debug.Exit()
   213  		return nil
   214  	}
   215  }
   216  
   217  func main() {
   218  	if err := app.Run(os.Args); err != nil {
   219  		fmt.Fprintln(os.Stderr, err)
   220  		os.Exit(1)
   221  	}
   222  }
   223  
   224  func keys(ctx *cli.Context) error {
   225  	privateKey := getPrivKey(ctx)
   226  	pub := hex.EncodeToString(crypto.FromECDSAPub(&privateKey.PublicKey))
   227  	pubCompressed := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey))
   228  	if !ctx.Bool(SwarmCompressedFlag.Name) {
   229  		fmt.Println(fmt.Sprintf("publicKey=%s", pub))
   230  	}
   231  	fmt.Println(fmt.Sprintf("publicKeyCompressed=%s", pubCompressed))
   232  	return nil
   233  }
   234  
   235  func version(ctx *cli.Context) error {
   236  	fmt.Println(strings.Title(clientIdentifier))
   237  	fmt.Println("Version:", sv.VersionWithMeta)
   238  	if gitCommit != "" {
   239  		fmt.Println("Git Commit:", gitCommit)
   240  	}
   241  	fmt.Println("Go Version:", runtime.Version())
   242  	fmt.Println("OS:", runtime.GOOS)
   243  	return nil
   244  }
   245  
   246  func bzzd(ctx *cli.Context) error {
   247  //从所有可用源生成有效的bzzapi.config:
   248  //默认配置、文件配置、命令行和env vars
   249  
   250  	bzzconfig, err := buildConfig(ctx)
   251  	if err != nil {
   252  		utils.Fatalf("unable to configure swarm: %v", err)
   253  	}
   254  
   255  	cfg := defaultNodeConfig
   256  
   257  //PSS在WS上运行
   258  	cfg.WSModules = append(cfg.WSModules, "pss")
   259  
   260  //geth只支持--datadir通过命令行
   261  //为了在Swarm中保持一致,如果我们通过环境变量传递--datadir
   262  //
   263  	if _, err := os.Stat(bzzconfig.Path); err == nil {
   264  		cfg.DataDir = bzzconfig.Path
   265  	}
   266  
   267  //可以选择在配置节点之前设置引导节点
   268  	setSwarmBootstrapNodes(ctx, &cfg)
   269  //设置以太坊节点
   270  	utils.SetNodeConfig(ctx, &cfg)
   271  	stack, err := node.New(&cfg)
   272  	if err != nil {
   273  		utils.Fatalf("can't create node: %v", err)
   274  	}
   275  
   276  //配置阶段完成后,需要执行一些步骤,
   277  //由于覆盖行为
   278  	initSwarmNode(bzzconfig, stack, ctx)
   279  //在以太坊节点中将bzz注册为node.service
   280  	registerBzzService(bzzconfig, stack)
   281  //启动节点
   282  	utils.StartNode(stack)
   283  
   284  	go func() {
   285  		sigc := make(chan os.Signal, 1)
   286  		signal.Notify(sigc, syscall.SIGTERM)
   287  		defer signal.Stop(sigc)
   288  		<-sigc
   289  		log.Info("Got sigterm, shutting swarm down...")
   290  		stack.Stop()
   291  	}()
   292  
   293  	stack.Wait()
   294  	return nil
   295  }
   296  
   297  func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) {
   298  //定义Swarm服务引导功能
   299  	boot := func(_ *node.ServiceContext) (node.Service, error) {
   300  //在生产中,mockstore必须始终为零。
   301  		return swarm.NewSwarm(bzzconfig, nil)
   302  	}
   303  //在以太坊节点中注册
   304  	if err := stack.Register(boot); err != nil {
   305  		utils.Fatalf("Failed to register the Swarm service: %v", err)
   306  	}
   307  }
   308  
   309  func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey {
   310  //帐户是必需的
   311  	if bzzaccount == "" {
   312  		utils.Fatalf(SWARM_ERR_NO_BZZACCOUNT)
   313  	}
   314  //尝试将arg作为十六进制密钥文件加载。
   315  	if key, err := crypto.LoadECDSA(bzzaccount); err == nil {
   316  		log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey))
   317  		return key
   318  	}
   319  //
   320  	am := stack.AccountManager()
   321  	ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   322  
   323  	return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx))
   324  }
   325  
   326  //getprivkey返回指定bzzaccount的私钥
   327  //
   328  func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey {
   329  //像在bzzd操作中一样启动群节点
   330  	bzzconfig, err := buildConfig(ctx)
   331  	if err != nil {
   332  		utils.Fatalf("unable to configure swarm: %v", err)
   333  	}
   334  	cfg := defaultNodeConfig
   335  	if _, err := os.Stat(bzzconfig.Path); err == nil {
   336  		cfg.DataDir = bzzconfig.Path
   337  	}
   338  	utils.SetNodeConfig(ctx, &cfg)
   339  	stack, err := node.New(&cfg)
   340  	if err != nil {
   341  		utils.Fatalf("can't create node: %v", err)
   342  	}
   343  	return getAccount(bzzconfig.BzzAccount, ctx, stack)
   344  }
   345  
   346  func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey {
   347  	var a accounts.Account
   348  	var err error
   349  	if common.IsHexAddress(account) {
   350  		a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)})
   351  	} else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 {
   352  		if accounts := ks.Accounts(); len(accounts) > ix {
   353  			a = accounts[ix]
   354  		} else {
   355  			err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts))
   356  		}
   357  	} else {
   358  		utils.Fatalf("Can't find swarm account key %s", account)
   359  	}
   360  	if err != nil {
   361  		utils.Fatalf("Can't find swarm account key: %v - Is the provided bzzaccount(%s) from the right datadir/Path?", err, account)
   362  	}
   363  	keyjson, err := ioutil.ReadFile(a.URL.Path)
   364  	if err != nil {
   365  		utils.Fatalf("Can't load swarm account key: %v", err)
   366  	}
   367  	for i := 0; i < 3; i++ {
   368  		password := getPassPhrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i+1), i, passwords)
   369  		key, err := keystore.DecryptKey(keyjson, password)
   370  		if err == nil {
   371  			return key.PrivateKey
   372  		}
   373  	}
   374  	utils.Fatalf("Can't decrypt swarm account key")
   375  	return nil
   376  }
   377  
   378  //getpassphrase通过获取与bzz帐户关联的密码
   379  //从预先加载的密码列表中,或通过交互方式向用户请求密码。
   380  func getPassPhrase(prompt string, i int, passwords []string) string {
   381  //非交互式
   382  	if len(passwords) > 0 {
   383  		if i < len(passwords) {
   384  			return passwords[i]
   385  		}
   386  		return passwords[len(passwords)-1]
   387  	}
   388  
   389  //回退到交互模式
   390  	if prompt != "" {
   391  		fmt.Println(prompt)
   392  	}
   393  	password, err := console.Stdin.PromptPassword("Passphrase: ")
   394  	if err != nil {
   395  		utils.Fatalf("Failed to read passphrase: %v", err)
   396  	}
   397  	return password
   398  }
   399  
   400  //adddefaulthelpsubcommand通过定义的cli命令扫描并添加
   401  //每个的基本帮助子命令
   402  //
   403  func addDefaultHelpSubcommands(commands []cli.Command) {
   404  	for i := range commands {
   405  		cmd := &commands[i]
   406  		if cmd.Subcommands != nil {
   407  			cmd.Subcommands = append(cmd.Subcommands, defaultSubcommandHelp)
   408  			addDefaultHelpSubcommands(cmd.Subcommands)
   409  		}
   410  	}
   411  }
   412  
   413  func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) {
   414  	if ctx.GlobalIsSet(utils.BootnodesFlag.Name) || ctx.GlobalIsSet(utils.BootnodesV4Flag.Name) {
   415  		return
   416  	}
   417  
   418  	cfg.P2P.BootstrapNodes = []*enode.Node{}
   419  
   420  	for _, url := range SwarmBootnodes {
   421  		node, err := enode.ParseV4(url)
   422  		if err != nil {
   423  			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
   424  		}
   425  		cfg.P2P.BootstrapNodes = append(cfg.P2P.BootstrapNodes, node)
   426  	}
   427  	log.Debug("added default swarm bootnodes", "length", len(cfg.P2P.BootstrapNodes))
   428  }
   429