main.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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. package main
  17. import (
  18. "context"
  19. "crypto/ecdsa"
  20. "fmt"
  21. "io/ioutil"
  22. "math/big"
  23. "os"
  24. "os/signal"
  25. "runtime"
  26. "sort"
  27. "strconv"
  28. "strings"
  29. "syscall"
  30. "time"
  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/contracts/ens"
  37. "github.com/ethereum/go-ethereum/crypto"
  38. "github.com/ethereum/go-ethereum/ethclient"
  39. "github.com/ethereum/go-ethereum/internal/debug"
  40. "github.com/ethereum/go-ethereum/log"
  41. "github.com/ethereum/go-ethereum/node"
  42. "github.com/ethereum/go-ethereum/p2p"
  43. "github.com/ethereum/go-ethereum/p2p/discover"
  44. "github.com/ethereum/go-ethereum/params"
  45. "github.com/ethereum/go-ethereum/rpc"
  46. "github.com/ethereum/go-ethereum/swarm"
  47. bzzapi "github.com/ethereum/go-ethereum/swarm/api"
  48. "gopkg.in/urfave/cli.v1"
  49. )
  50. const clientIdentifier = "swarm"
  51. var (
  52. gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
  53. testbetBootNodes = []string{
  54. "enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429",
  55. "enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430",
  56. "enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431",
  57. "enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432",
  58. "enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433",
  59. }
  60. )
  61. var (
  62. ChequebookAddrFlag = cli.StringFlag{
  63. Name: "chequebook",
  64. Usage: "chequebook contract address",
  65. EnvVar: SWARM_ENV_CHEQUEBOOK_ADDR,
  66. }
  67. SwarmAccountFlag = cli.StringFlag{
  68. Name: "bzzaccount",
  69. Usage: "Swarm account key file",
  70. EnvVar: SWARM_ENV_ACCOUNT,
  71. }
  72. SwarmListenAddrFlag = cli.StringFlag{
  73. Name: "httpaddr",
  74. Usage: "Swarm HTTP API listening interface",
  75. EnvVar: SWARM_ENV_LISTEN_ADDR,
  76. }
  77. SwarmPortFlag = cli.StringFlag{
  78. Name: "bzzport",
  79. Usage: "Swarm local http api port",
  80. EnvVar: SWARM_ENV_PORT,
  81. }
  82. SwarmNetworkIdFlag = cli.IntFlag{
  83. Name: "bzznetworkid",
  84. Usage: "Network identifier (integer, default 3=swarm testnet)",
  85. EnvVar: SWARM_ENV_NETWORK_ID,
  86. }
  87. SwarmConfigPathFlag = cli.StringFlag{
  88. Name: "bzzconfig",
  89. Usage: "DEPRECATED: please use --config path/to/TOML-file",
  90. }
  91. SwarmSwapEnabledFlag = cli.BoolFlag{
  92. Name: "swap",
  93. Usage: "Swarm SWAP enabled (default false)",
  94. EnvVar: SWARM_ENV_SWAP_ENABLE,
  95. }
  96. SwarmSwapAPIFlag = cli.StringFlag{
  97. Name: "swap-api",
  98. Usage: "URL of the Ethereum API provider to use to settle SWAP payments",
  99. EnvVar: SWARM_ENV_SWAP_API,
  100. }
  101. SwarmSyncEnabledFlag = cli.BoolTFlag{
  102. Name: "sync",
  103. Usage: "Swarm Syncing enabled (default true)",
  104. EnvVar: SWARM_ENV_SYNC_ENABLE,
  105. }
  106. EnsAPIFlag = cli.StringFlag{
  107. Name: "ens-api",
  108. Usage: "URL of the Ethereum API provider to use for ENS record lookups",
  109. EnvVar: SWARM_ENV_ENS_API,
  110. }
  111. EnsAddrFlag = cli.StringFlag{
  112. Name: "ens-addr",
  113. Usage: "ENS contract address (default is detected as testnet or mainnet using --ens-api)",
  114. EnvVar: SWARM_ENV_ENS_ADDR,
  115. }
  116. SwarmApiFlag = cli.StringFlag{
  117. Name: "bzzapi",
  118. Usage: "Swarm HTTP endpoint",
  119. Value: "http://127.0.0.1:8500",
  120. }
  121. SwarmRecursiveUploadFlag = cli.BoolFlag{
  122. Name: "recursive",
  123. Usage: "Upload directories recursively",
  124. }
  125. SwarmWantManifestFlag = cli.BoolTFlag{
  126. Name: "manifest",
  127. Usage: "Automatic manifest upload",
  128. }
  129. SwarmUploadDefaultPath = cli.StringFlag{
  130. Name: "defaultpath",
  131. Usage: "path to file served for empty url path (none)",
  132. }
  133. SwarmUpFromStdinFlag = cli.BoolFlag{
  134. Name: "stdin",
  135. Usage: "reads data to be uploaded from stdin",
  136. }
  137. SwarmUploadMimeType = cli.StringFlag{
  138. Name: "mime",
  139. Usage: "force mime type",
  140. }
  141. CorsStringFlag = cli.StringFlag{
  142. Name: "corsdomain",
  143. Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')",
  144. EnvVar: SWARM_ENV_CORS,
  145. }
  146. // the following flags are deprecated and should be removed in the future
  147. DeprecatedEthAPIFlag = cli.StringFlag{
  148. Name: "ethapi",
  149. Usage: "DEPRECATED: please use --ens-api and --swap-api",
  150. }
  151. )
  152. //declare a few constant error messages, useful for later error check comparisons in test
  153. var (
  154. SWARM_ERR_NO_BZZACCOUNT = "bzzaccount option is required but not set; check your config file, command line or environment variables"
  155. SWARM_ERR_SWAP_SET_NO_API = "SWAP is enabled but --swap-api is not set"
  156. )
  157. var defaultNodeConfig = node.DefaultConfig
  158. // This init function sets defaults so cmd/swarm can run alongside geth.
  159. func init() {
  160. defaultNodeConfig.Name = clientIdentifier
  161. defaultNodeConfig.Version = params.VersionWithCommit(gitCommit)
  162. defaultNodeConfig.P2P.ListenAddr = ":30399"
  163. defaultNodeConfig.IPCPath = "bzzd.ipc"
  164. // Set flag defaults for --help display.
  165. utils.ListenPortFlag.Value = 30399
  166. }
  167. var app = utils.NewApp(gitCommit, "Ethereum Swarm")
  168. // This init function creates the cli.App.
  169. func init() {
  170. app.Action = bzzd
  171. app.HideVersion = true // we have a command to print the version
  172. app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
  173. app.Commands = []cli.Command{
  174. {
  175. Action: version,
  176. Name: "version",
  177. Usage: "Print version numbers",
  178. ArgsUsage: " ",
  179. Description: `
  180. The output of this command is supposed to be machine-readable.
  181. `,
  182. },
  183. {
  184. Action: upload,
  185. Name: "up",
  186. Usage: "upload a file or directory to swarm using the HTTP API",
  187. ArgsUsage: " <file>",
  188. Description: `
  189. "upload a file or directory to swarm using the HTTP API and prints the root hash",
  190. `,
  191. },
  192. {
  193. Action: list,
  194. Name: "ls",
  195. Usage: "list files and directories contained in a manifest",
  196. ArgsUsage: " <manifest> [<prefix>]",
  197. Description: `
  198. Lists files and directories contained in a manifest.
  199. `,
  200. },
  201. {
  202. Action: hash,
  203. Name: "hash",
  204. Usage: "print the swarm hash of a file or directory",
  205. ArgsUsage: " <file>",
  206. Description: `
  207. Prints the swarm hash of file or directory.
  208. `,
  209. },
  210. {
  211. Name: "manifest",
  212. Usage: "update a MANIFEST",
  213. ArgsUsage: "manifest COMMAND",
  214. Description: `
  215. Updates a MANIFEST by adding/removing/updating the hash of a path.
  216. `,
  217. Subcommands: []cli.Command{
  218. {
  219. Action: add,
  220. Name: "add",
  221. Usage: "add a new path to the manifest",
  222. ArgsUsage: "<MANIFEST> <path> <hash> [<content-type>]",
  223. Description: `
  224. Adds a new path to the manifest
  225. `,
  226. },
  227. {
  228. Action: update,
  229. Name: "update",
  230. Usage: "update the hash for an already existing path in the manifest",
  231. ArgsUsage: "<MANIFEST> <path> <newhash> [<newcontent-type>]",
  232. Description: `
  233. Update the hash for an already existing path in the manifest
  234. `,
  235. },
  236. {
  237. Action: remove,
  238. Name: "remove",
  239. Usage: "removes a path from the manifest",
  240. ArgsUsage: "<MANIFEST> <path>",
  241. Description: `
  242. Removes a path from the manifest
  243. `,
  244. },
  245. },
  246. },
  247. {
  248. Name: "db",
  249. Usage: "manage the local chunk database",
  250. ArgsUsage: "db COMMAND",
  251. Description: `
  252. Manage the local chunk database.
  253. `,
  254. Subcommands: []cli.Command{
  255. {
  256. Action: dbExport,
  257. Name: "export",
  258. Usage: "export a local chunk database as a tar archive (use - to send to stdout)",
  259. ArgsUsage: "<chunkdb> <file>",
  260. Description: `
  261. Export a local chunk database as a tar archive (use - to send to stdout).
  262. swarm db export ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar
  263. The export may be quite large, consider piping the output through the Unix
  264. pv(1) tool to get a progress bar:
  265. swarm db export ~/.ethereum/swarm/bzz-KEY/chunks - | pv > chunks.tar
  266. `,
  267. },
  268. {
  269. Action: dbImport,
  270. Name: "import",
  271. Usage: "import chunks from a tar archive into a local chunk database (use - to read from stdin)",
  272. ArgsUsage: "<chunkdb> <file>",
  273. Description: `
  274. Import chunks from a tar archive into a local chunk database (use - to read from stdin).
  275. swarm db import ~/.ethereum/swarm/bzz-KEY/chunks chunks.tar
  276. The import may be quite large, consider piping the input through the Unix
  277. pv(1) tool to get a progress bar:
  278. pv chunks.tar | swarm db import ~/.ethereum/swarm/bzz-KEY/chunks -
  279. `,
  280. },
  281. {
  282. Action: dbClean,
  283. Name: "clean",
  284. Usage: "remove corrupt entries from a local chunk database",
  285. ArgsUsage: "<chunkdb>",
  286. Description: `
  287. Remove corrupt entries from a local chunk database.
  288. `,
  289. },
  290. },
  291. },
  292. {
  293. Action: func(ctx *cli.Context) {
  294. utils.Fatalf("ERROR: 'swarm cleandb' has been removed, please use 'swarm db clean'.")
  295. },
  296. Name: "cleandb",
  297. Usage: "DEPRECATED: use 'swarm db clean'",
  298. ArgsUsage: " ",
  299. Description: `
  300. DEPRECATED: use 'swarm db clean'.
  301. `,
  302. },
  303. // See config.go
  304. DumpConfigCommand,
  305. }
  306. sort.Sort(cli.CommandsByName(app.Commands))
  307. app.Flags = []cli.Flag{
  308. utils.IdentityFlag,
  309. utils.DataDirFlag,
  310. utils.BootnodesFlag,
  311. utils.KeyStoreDirFlag,
  312. utils.ListenPortFlag,
  313. utils.NoDiscoverFlag,
  314. utils.DiscoveryV5Flag,
  315. utils.NetrestrictFlag,
  316. utils.NodeKeyFileFlag,
  317. utils.NodeKeyHexFlag,
  318. utils.MaxPeersFlag,
  319. utils.NATFlag,
  320. utils.IPCDisabledFlag,
  321. utils.IPCPathFlag,
  322. utils.PasswordFileFlag,
  323. // bzzd-specific flags
  324. CorsStringFlag,
  325. EnsAPIFlag,
  326. EnsAddrFlag,
  327. SwarmTomlConfigPathFlag,
  328. SwarmConfigPathFlag,
  329. SwarmSwapEnabledFlag,
  330. SwarmSwapAPIFlag,
  331. SwarmSyncEnabledFlag,
  332. SwarmListenAddrFlag,
  333. SwarmPortFlag,
  334. SwarmAccountFlag,
  335. SwarmNetworkIdFlag,
  336. ChequebookAddrFlag,
  337. // upload flags
  338. SwarmApiFlag,
  339. SwarmRecursiveUploadFlag,
  340. SwarmWantManifestFlag,
  341. SwarmUploadDefaultPath,
  342. SwarmUpFromStdinFlag,
  343. SwarmUploadMimeType,
  344. //deprecated flags
  345. DeprecatedEthAPIFlag,
  346. }
  347. app.Flags = append(app.Flags, debug.Flags...)
  348. app.Before = func(ctx *cli.Context) error {
  349. runtime.GOMAXPROCS(runtime.NumCPU())
  350. return debug.Setup(ctx)
  351. }
  352. app.After = func(ctx *cli.Context) error {
  353. debug.Exit()
  354. return nil
  355. }
  356. }
  357. func main() {
  358. if err := app.Run(os.Args); err != nil {
  359. fmt.Fprintln(os.Stderr, err)
  360. os.Exit(1)
  361. }
  362. }
  363. func version(ctx *cli.Context) error {
  364. fmt.Println(strings.Title(clientIdentifier))
  365. fmt.Println("Version:", params.Version)
  366. if gitCommit != "" {
  367. fmt.Println("Git Commit:", gitCommit)
  368. }
  369. fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name))
  370. fmt.Println("Go Version:", runtime.Version())
  371. fmt.Println("OS:", runtime.GOOS)
  372. fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
  373. fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
  374. return nil
  375. }
  376. func bzzd(ctx *cli.Context) error {
  377. //build a valid bzzapi.Config from all available sources:
  378. //default config, file config, command line and env vars
  379. bzzconfig, err := buildConfig(ctx)
  380. if err != nil {
  381. utils.Fatalf("unable to configure swarm: %v", err)
  382. }
  383. cfg := defaultNodeConfig
  384. //geth only supports --datadir via command line
  385. //in order to be consistent within swarm, if we pass --datadir via environment variable
  386. //or via config file, we get the same directory for geth and swarm
  387. if _, err := os.Stat(bzzconfig.Path); err == nil {
  388. cfg.DataDir = bzzconfig.Path
  389. }
  390. //setup the ethereum node
  391. utils.SetNodeConfig(ctx, &cfg)
  392. stack, err := node.New(&cfg)
  393. if err != nil {
  394. utils.Fatalf("can't create node: %v", err)
  395. }
  396. //a few steps need to be done after the config phase is completed,
  397. //due to overriding behavior
  398. initSwarmNode(bzzconfig, stack, ctx)
  399. //register BZZ as node.Service in the ethereum node
  400. registerBzzService(bzzconfig, ctx, stack)
  401. //start the node
  402. utils.StartNode(stack)
  403. go func() {
  404. sigc := make(chan os.Signal, 1)
  405. signal.Notify(sigc, syscall.SIGTERM)
  406. defer signal.Stop(sigc)
  407. <-sigc
  408. log.Info("Got sigterm, shutting swarm down...")
  409. stack.Stop()
  410. }()
  411. // Add bootnodes as initial peers.
  412. if bzzconfig.BootNodes != "" {
  413. bootnodes := strings.Split(bzzconfig.BootNodes, ",")
  414. injectBootnodes(stack.Server(), bootnodes)
  415. } else {
  416. if bzzconfig.NetworkId == 3 {
  417. injectBootnodes(stack.Server(), testbetBootNodes)
  418. }
  419. }
  420. stack.Wait()
  421. return nil
  422. }
  423. // detectEnsAddr determines the ENS contract address by getting both the
  424. // version and genesis hash using the client and matching them to either
  425. // mainnet or testnet addresses
  426. func detectEnsAddr(client *rpc.Client) (common.Address, error) {
  427. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  428. defer cancel()
  429. var version string
  430. if err := client.CallContext(ctx, &version, "net_version"); err != nil {
  431. return common.Address{}, err
  432. }
  433. block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0))
  434. if err != nil {
  435. return common.Address{}, err
  436. }
  437. switch {
  438. case version == "1" && block.Hash() == params.MainnetGenesisHash:
  439. log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress)
  440. return ens.MainNetAddress, nil
  441. case version == "3" && block.Hash() == params.TestnetGenesisHash:
  442. log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress)
  443. return ens.TestNetAddress, nil
  444. default:
  445. return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash())
  446. }
  447. }
  448. func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.Node) {
  449. //define the swarm service boot function
  450. boot := func(ctx *node.ServiceContext) (node.Service, error) {
  451. var swapClient *ethclient.Client
  452. var err error
  453. if bzzconfig.SwapApi != "" {
  454. log.Info("connecting to SWAP API", "url", bzzconfig.SwapApi)
  455. swapClient, err = ethclient.Dial(bzzconfig.SwapApi)
  456. if err != nil {
  457. return nil, fmt.Errorf("error connecting to SWAP API %s: %s", bzzconfig.SwapApi, err)
  458. }
  459. }
  460. var ensClient *ethclient.Client
  461. if bzzconfig.EnsApi != "" {
  462. log.Info("connecting to ENS API", "url", bzzconfig.EnsApi)
  463. client, err := rpc.Dial(bzzconfig.EnsApi)
  464. if err != nil {
  465. return nil, fmt.Errorf("error connecting to ENS API %s: %s", bzzconfig.EnsApi, err)
  466. }
  467. ensClient = ethclient.NewClient(client)
  468. //no ENS root address set yet
  469. if bzzconfig.EnsRoot == (common.Address{}) {
  470. ensAddr, err := detectEnsAddr(client)
  471. if err == nil {
  472. bzzconfig.EnsRoot = ensAddr
  473. } else {
  474. log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", bzzconfig.EnsRoot), "err", err)
  475. }
  476. }
  477. }
  478. return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors)
  479. }
  480. //register within the ethereum node
  481. if err := stack.Register(boot); err != nil {
  482. utils.Fatalf("Failed to register the Swarm service: %v", err)
  483. }
  484. }
  485. func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey {
  486. //an account is mandatory
  487. if bzzaccount == "" {
  488. utils.Fatalf(SWARM_ERR_NO_BZZACCOUNT)
  489. }
  490. // Try to load the arg as a hex key file.
  491. if key, err := crypto.LoadECDSA(bzzaccount); err == nil {
  492. log.Info("Swarm account key loaded", "address", crypto.PubkeyToAddress(key.PublicKey))
  493. return key
  494. }
  495. // Otherwise try getting it from the keystore.
  496. am := stack.AccountManager()
  497. ks := am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
  498. return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx))
  499. }
  500. func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey {
  501. var a accounts.Account
  502. var err error
  503. if common.IsHexAddress(account) {
  504. a, err = ks.Find(accounts.Account{Address: common.HexToAddress(account)})
  505. } else if ix, ixerr := strconv.Atoi(account); ixerr == nil && ix > 0 {
  506. if accounts := ks.Accounts(); len(accounts) > ix {
  507. a = accounts[ix]
  508. } else {
  509. err = fmt.Errorf("index %d higher than number of accounts %d", ix, len(accounts))
  510. }
  511. } else {
  512. utils.Fatalf("Can't find swarm account key %s", account)
  513. }
  514. if err != nil {
  515. utils.Fatalf("Can't find swarm account key: %v - Is the provided bzzaccount(%s) from the right datadir/Path?", err, account)
  516. }
  517. keyjson, err := ioutil.ReadFile(a.URL.Path)
  518. if err != nil {
  519. utils.Fatalf("Can't load swarm account key: %v", err)
  520. }
  521. for i := 0; i < 3; i++ {
  522. password := getPassPhrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i+1), i, passwords)
  523. key, err := keystore.DecryptKey(keyjson, password)
  524. if err == nil {
  525. return key.PrivateKey
  526. }
  527. }
  528. utils.Fatalf("Can't decrypt swarm account key")
  529. return nil
  530. }
  531. // getPassPhrase retrieves the password associated with bzz account, either by fetching
  532. // from a list of pre-loaded passwords, or by requesting it interactively from user.
  533. func getPassPhrase(prompt string, i int, passwords []string) string {
  534. // non-interactive
  535. if len(passwords) > 0 {
  536. if i < len(passwords) {
  537. return passwords[i]
  538. }
  539. return passwords[len(passwords)-1]
  540. }
  541. // fallback to interactive mode
  542. if prompt != "" {
  543. fmt.Println(prompt)
  544. }
  545. password, err := console.Stdin.PromptPassword("Passphrase: ")
  546. if err != nil {
  547. utils.Fatalf("Failed to read passphrase: %v", err)
  548. }
  549. return password
  550. }
  551. func injectBootnodes(srv *p2p.Server, nodes []string) {
  552. for _, url := range nodes {
  553. n, err := discover.ParseNode(url)
  554. if err != nil {
  555. log.Error("Invalid swarm bootnode", "err", err)
  556. continue
  557. }
  558. srv.AddPeer(n)
  559. }
  560. }