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