github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/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/rpc" 43 "github.com/ethereum/go-ethereum/swarm" 44 bzzapi "github.com/ethereum/go-ethereum/swarm/api" 45 swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics" 46 "github.com/ethereum/go-ethereum/swarm/storage/mock" 47 mockrpc "github.com/ethereum/go-ethereum/swarm/storage/mock/rpc" 48 "github.com/ethereum/go-ethereum/swarm/tracing" 49 sv "github.com/ethereum/go-ethereum/swarm/version" 50 51 cli "gopkg.in/urfave/cli.v1" 52 ) 53 54 const clientIdentifier = "swarm" 55 const helpTemplate = `NAME: 56 {{.HelpName}} - {{.Usage}} 57 58 USAGE: 59 {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} 60 61 CATEGORY: 62 {{.Category}}{{end}}{{if .Description}} 63 64 DESCRIPTION: 65 {{.Description}}{{end}}{{if .VisibleFlags}} 66 67 OPTIONS: 68 {{range .VisibleFlags}}{{.}} 69 {{end}}{{end}} 70 ` 71 72 // Git SHA1 commit hash of the release (set via linker flags) 73 // this variable will be assigned if corresponding parameter is passed with install, but not with test 74 // e.g.: go install -ldflags "-X main.gitCommit=ed1312d01b19e04ef578946226e5d8069d5dfd5a" ./cmd/swarm 75 var gitCommit string 76 77 //declare a few constant error messages, useful for later error check comparisons in test 78 var ( 79 SwarmErrNoBZZAccount = "bzzaccount option is required but not set; check your config file, command line or environment variables" 80 SwarmErrSwapSetNoAPI = "SWAP is enabled but --swap-api is not set" 81 ) 82 83 // this help command gets added to any subcommand that does not define it explicitly 84 var defaultSubcommandHelp = cli.Command{ 85 Action: func(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "", 1) }, 86 CustomHelpTemplate: helpTemplate, 87 Name: "help", 88 Usage: "shows this help", 89 Hidden: true, 90 } 91 92 var defaultNodeConfig = node.DefaultConfig 93 94 // This init function sets defaults so cmd/swarm can run alongside geth. 95 func init() { 96 sv.GitCommit = gitCommit 97 defaultNodeConfig.Name = clientIdentifier 98 defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit) 99 defaultNodeConfig.P2P.ListenAddr = ":30399" 100 defaultNodeConfig.IPCPath = "bzzd.ipc" 101 // Set flag defaults for --help display. 102 utils.ListenPortFlag.Value = 30399 103 } 104 105 var app = utils.NewApp("", "Ethereum Swarm") 106 107 // This init function creates the cli.App. 108 func init() { 109 app.Action = bzzd 110 app.Version = sv.ArchiveVersion(gitCommit) 111 app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" 112 app.Commands = []cli.Command{ 113 { 114 Action: version, 115 CustomHelpTemplate: helpTemplate, 116 Name: "version", 117 Usage: "Print version numbers", 118 Description: "The output of this command is supposed to be machine-readable", 119 }, 120 { 121 Action: keys, 122 CustomHelpTemplate: helpTemplate, 123 Name: "print-keys", 124 Flags: []cli.Flag{SwarmCompressedFlag}, 125 Usage: "Print public key information", 126 Description: "The output of this command is supposed to be machine-readable", 127 }, 128 // See upload.go 129 upCommand, 130 // See access.go 131 accessCommand, 132 // See feeds.go 133 feedCommand, 134 // See list.go 135 listCommand, 136 // See hash.go 137 hashCommand, 138 // See download.go 139 downloadCommand, 140 // See manifest.go 141 manifestCommand, 142 // See fs.go 143 fsCommand, 144 // See db.go 145 dbCommand, 146 // See config.go 147 DumpConfigCommand, 148 // hashesCommand 149 hashesCommand, 150 } 151 152 // append a hidden help subcommand to all commands that have subcommands 153 // if a help command was already defined above, that one will take precedence. 154 addDefaultHelpSubcommands(app.Commands) 155 156 sort.Sort(cli.CommandsByName(app.Commands)) 157 158 app.Flags = []cli.Flag{ 159 utils.IdentityFlag, 160 utils.DataDirFlag, 161 utils.BootnodesFlag, 162 utils.KeyStoreDirFlag, 163 utils.ListenPortFlag, 164 utils.DiscoveryV5Flag, 165 utils.NetrestrictFlag, 166 utils.NodeKeyFileFlag, 167 utils.NodeKeyHexFlag, 168 utils.MaxPeersFlag, 169 utils.NATFlag, 170 utils.IPCDisabledFlag, 171 utils.IPCPathFlag, 172 utils.PasswordFileFlag, 173 // bzzd-specific flags 174 CorsStringFlag, 175 EnsAPIFlag, 176 SwarmTomlConfigPathFlag, 177 SwarmSwapEnabledFlag, 178 SwarmSwapAPIFlag, 179 SwarmSyncDisabledFlag, 180 SwarmSyncUpdateDelay, 181 SwarmMaxStreamPeerServersFlag, 182 SwarmLightNodeEnabled, 183 SwarmDeliverySkipCheckFlag, 184 SwarmListenAddrFlag, 185 SwarmPortFlag, 186 SwarmAccountFlag, 187 SwarmNetworkIdFlag, 188 ChequebookAddrFlag, 189 // upload flags 190 SwarmApiFlag, 191 SwarmRecursiveFlag, 192 SwarmWantManifestFlag, 193 SwarmUploadDefaultPath, 194 SwarmUpFromStdinFlag, 195 SwarmUploadMimeType, 196 // bootnode mode 197 SwarmBootnodeModeFlag, 198 // storage flags 199 SwarmStorePath, 200 SwarmStoreCapacity, 201 SwarmStoreCacheCapacity, 202 SwarmGlobalStoreAPIFlag, 203 } 204 rpcFlags := []cli.Flag{ 205 utils.WSEnabledFlag, 206 utils.WSListenAddrFlag, 207 utils.WSPortFlag, 208 utils.WSApiFlag, 209 utils.WSAllowedOriginsFlag, 210 } 211 app.Flags = append(app.Flags, rpcFlags...) 212 app.Flags = append(app.Flags, debug.Flags...) 213 app.Flags = append(app.Flags, swarmmetrics.Flags...) 214 app.Flags = append(app.Flags, tracing.Flags...) 215 app.Before = func(ctx *cli.Context) error { 216 runtime.GOMAXPROCS(runtime.NumCPU()) 217 if err := debug.Setup(ctx, ""); err != nil { 218 return err 219 } 220 swarmmetrics.Setup(ctx) 221 tracing.Setup(ctx) 222 return nil 223 } 224 app.After = func(ctx *cli.Context) error { 225 debug.Exit() 226 return nil 227 } 228 } 229 230 func main() { 231 if err := app.Run(os.Args); err != nil { 232 fmt.Fprintln(os.Stderr, err) 233 os.Exit(1) 234 } 235 } 236 237 func keys(ctx *cli.Context) error { 238 privateKey := getPrivKey(ctx) 239 pubkey := crypto.FromECDSAPub(&privateKey.PublicKey) 240 pubkeyhex := hex.EncodeToString(pubkey) 241 pubCompressed := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)) 242 bzzkey := crypto.Keccak256Hash(pubkey).Hex() 243 244 if !ctx.Bool(SwarmCompressedFlag.Name) { 245 fmt.Println(fmt.Sprintf("bzzkey=%s", bzzkey[2:])) 246 fmt.Println(fmt.Sprintf("publicKey=%s", pubkeyhex)) 247 } 248 fmt.Println(fmt.Sprintf("publicKeyCompressed=%s", pubCompressed)) 249 250 return nil 251 } 252 253 func version(ctx *cli.Context) error { 254 fmt.Println(strings.Title(clientIdentifier)) 255 fmt.Println("Version:", sv.VersionWithMeta) 256 if gitCommit != "" { 257 fmt.Println("Git Commit:", gitCommit) 258 } 259 fmt.Println("Go Version:", runtime.Version()) 260 fmt.Println("OS:", runtime.GOOS) 261 return nil 262 } 263 264 func bzzd(ctx *cli.Context) error { 265 //build a valid bzzapi.Config from all available sources: 266 //default config, file config, command line and env vars 267 268 bzzconfig, err := buildConfig(ctx) 269 if err != nil { 270 utils.Fatalf("unable to configure swarm: %v", err) 271 } 272 273 cfg := defaultNodeConfig 274 275 //pss operates on ws 276 cfg.WSModules = append(cfg.WSModules, "pss") 277 278 //geth only supports --datadir via command line 279 //in order to be consistent within swarm, if we pass --datadir via environment variable 280 //or via config file, we get the same directory for geth and swarm 281 if _, err := os.Stat(bzzconfig.Path); err == nil { 282 cfg.DataDir = bzzconfig.Path 283 } 284 285 //optionally set the bootnodes before configuring the node 286 setSwarmBootstrapNodes(ctx, &cfg) 287 //setup the ethereum node 288 utils.SetNodeConfig(ctx, &cfg) 289 290 //disable dynamic dialing from p2p/discovery 291 cfg.P2P.NoDial = true 292 293 stack, err := node.New(&cfg) 294 if err != nil { 295 utils.Fatalf("can't create node: %v", err) 296 } 297 defer stack.Close() 298 299 //a few steps need to be done after the config phase is completed, 300 //due to overriding behavior 301 err = initSwarmNode(bzzconfig, stack, ctx, &cfg) 302 if err != nil { 303 return err 304 } 305 //register BZZ as node.Service in the ethereum node 306 registerBzzService(bzzconfig, stack) 307 //start the node 308 utils.StartNode(stack) 309 310 go func() { 311 sigc := make(chan os.Signal, 1) 312 signal.Notify(sigc, syscall.SIGTERM) 313 defer signal.Stop(sigc) 314 <-sigc 315 log.Info("Got sigterm, shutting swarm down...") 316 stack.Stop() 317 }() 318 319 // add swarm bootnodes, because swarm doesn't use p2p package's discovery discv5 320 go func() { 321 s := stack.Server() 322 323 for _, n := range cfg.P2P.BootstrapNodes { 324 s.AddPeer(n) 325 } 326 }() 327 328 stack.Wait() 329 return nil 330 } 331 332 func registerBzzService(bzzconfig *bzzapi.Config, stack *node.Node) { 333 //define the swarm service boot function 334 boot := func(_ *node.ServiceContext) (node.Service, error) { 335 var nodeStore *mock.NodeStore 336 if bzzconfig.GlobalStoreAPI != "" { 337 // connect to global store 338 client, err := rpc.Dial(bzzconfig.GlobalStoreAPI) 339 if err != nil { 340 return nil, fmt.Errorf("global store: %v", err) 341 } 342 globalStore := mockrpc.NewGlobalStore(client) 343 // create a node store for this swarm key on global store 344 nodeStore = globalStore.NewNodeStore(common.HexToAddress(bzzconfig.BzzKey)) 345 } 346 return swarm.NewSwarm(bzzconfig, nodeStore) 347 } 348 //register within the ethereum node 349 if err := stack.Register(boot); err != nil { 350 utils.Fatalf("Failed to register the Swarm service: %v", err) 351 } 352 } 353 354 func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { 355 //an account is mandatory 356 if bzzaccount == "" { 357 utils.Fatalf(SwarmErrNoBZZAccount) 358 } 359 // Try to load the arg as a hex key file. 360 if key, err := crypto.LoadECDSA(bzzaccount); err == nil { 361 log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey)) 362 return key 363 } 364 // Otherwise try getting it from the keystore. 365 am := stack.AccountManager() 366 ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 367 368 return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx)) 369 } 370 371 // getPrivKey returns the private key of the specified bzzaccount 372 // Used only by client commands, such as `feed` 373 func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey { 374 // booting up the swarm node just as we do in bzzd action 375 bzzconfig, err := buildConfig(ctx) 376 if err != nil { 377 utils.Fatalf("unable to configure swarm: %v", err) 378 } 379 cfg := defaultNodeConfig 380 if _, err := os.Stat(bzzconfig.Path); err == nil { 381 cfg.DataDir = bzzconfig.Path 382 } 383 utils.SetNodeConfig(ctx, &cfg) 384 stack, err := node.New(&cfg) 385 if err != nil { 386 utils.Fatalf("can't create node: %v", err) 387 } 388 defer stack.Close() 389 390 return getAccount(bzzconfig.BzzAccount, ctx, stack) 391 } 392 393 func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey { 394 var a accounts.Account 395 var err error 396 if common.IsHexAddress(account) { 397 a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)}) 398 } else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 { 399 if accounts := ks.Accounts(); len(accounts) > ix { 400 a = accounts[ix] 401 } else { 402 err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts)) 403 } 404 } else { 405 utils.Fatalf("Can't find swarm account key %s", account) 406 } 407 if err != nil { 408 utils.Fatalf("Can't find swarm account key: %v - Is the provided bzzaccount(%s) from the right datadir/Path?", err, account) 409 } 410 keyjson, err := ioutil.ReadFile(a.URL.Path) 411 if err != nil { 412 utils.Fatalf("Can't load swarm account key: %v", err) 413 } 414 for i := 0; i < 3; i++ { 415 password := getPassPhrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i+1), i, passwords) 416 key, err := keystore.DecryptKey(keyjson, password) 417 if err == nil { 418 return key.PrivateKey 419 } 420 } 421 utils.Fatalf("Can't decrypt swarm account key") 422 return nil 423 } 424 425 // getPassPhrase retrieves the password associated with bzz account, either by fetching 426 // from a list of pre-loaded passwords, or by requesting it interactively from user. 427 func getPassPhrase(prompt string, i int, passwords []string) string { 428 // non-interactive 429 if len(passwords) > 0 { 430 if i < len(passwords) { 431 return passwords[i] 432 } 433 return passwords[len(passwords)-1] 434 } 435 436 // fallback to interactive mode 437 if prompt != "" { 438 fmt.Println(prompt) 439 } 440 password, err := console.Stdin.PromptPassword("Passphrase: ") 441 if err != nil { 442 utils.Fatalf("Failed to read passphrase: %v", err) 443 } 444 return password 445 } 446 447 // addDefaultHelpSubcommand scans through defined CLI commands and adds 448 // a basic help subcommand to each 449 // if a help command is already defined, it will take precedence over the default. 450 func addDefaultHelpSubcommands(commands []cli.Command) { 451 for i := range commands { 452 cmd := &commands[i] 453 if cmd.Subcommands != nil { 454 cmd.Subcommands = append(cmd.Subcommands, defaultSubcommandHelp) 455 addDefaultHelpSubcommands(cmd.Subcommands) 456 } 457 } 458 } 459 460 func setSwarmBootstrapNodes(ctx *cli.Context, cfg *node.Config) { 461 if ctx.GlobalIsSet(utils.BootnodesFlag.Name) || ctx.GlobalIsSet(utils.BootnodesV4Flag.Name) { 462 return 463 } 464 465 cfg.P2P.BootstrapNodes = []*enode.Node{} 466 467 for _, url := range SwarmBootnodes { 468 node, err := enode.ParseV4(url) 469 if err != nil { 470 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 471 } 472 cfg.P2P.BootstrapNodes = append(cfg.P2P.BootstrapNodes, node) 473 } 474 475 }