github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/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 "fmt" 22 "io/ioutil" 23 "os" 24 "runtime" 25 "strconv" 26 "strings" 27 28 "github.com/ethereum/go-ethereum/accounts" 29 "github.com/ethereum/go-ethereum/cmd/utils" 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/console" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/ethclient" 34 "github.com/ethereum/go-ethereum/internal/debug" 35 "github.com/ethereum/go-ethereum/logger" 36 "github.com/ethereum/go-ethereum/logger/glog" 37 "github.com/ethereum/go-ethereum/node" 38 "github.com/ethereum/go-ethereum/p2p" 39 "github.com/ethereum/go-ethereum/p2p/discover" 40 "github.com/ethereum/go-ethereum/swarm" 41 bzzapi "github.com/ethereum/go-ethereum/swarm/api" 42 "github.com/ethereum/go-ethereum/swarm/network" 43 "gopkg.in/urfave/cli.v1" 44 ) 45 46 const ( 47 clientIdentifier = "swarm" 48 versionString = "0.2" 49 ) 50 51 var ( 52 gitCommit string // Git SHA1 commit hash of the release (set via linker flags) 53 app = utils.NewApp(gitCommit, "Ethereum Swarm") 54 testbetBootNodes = []string{ 55 "enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429", 56 "enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430", 57 "enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431", 58 "enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432", 59 "enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433", 60 } 61 ) 62 63 var ( 64 ChequebookAddrFlag = cli.StringFlag{ 65 Name: "chequebook", 66 Usage: "chequebook contract address", 67 } 68 SwarmAccountFlag = cli.StringFlag{ 69 Name: "bzzaccount", 70 Usage: "Swarm account key file", 71 } 72 SwarmPortFlag = cli.StringFlag{ 73 Name: "bzzport", 74 Usage: "Swarm local http api port", 75 } 76 SwarmNetworkIdFlag = cli.IntFlag{ 77 Name: "bzznetworkid", 78 Usage: "Network identifier (integer, default 3=swarm testnet)", 79 Value: network.NetworkId, 80 } 81 SwarmConfigPathFlag = cli.StringFlag{ 82 Name: "bzzconfig", 83 Usage: "Swarm config file path (datadir/bzz)", 84 } 85 SwarmSwapEnabledFlag = cli.BoolFlag{ 86 Name: "swap", 87 Usage: "Swarm SWAP enabled (default false)", 88 } 89 SwarmSyncEnabledFlag = cli.BoolTFlag{ 90 Name: "sync", 91 Usage: "Swarm Syncing enabled (default true)", 92 } 93 EthAPIFlag = cli.StringFlag{ 94 Name: "ethapi", 95 Usage: "URL of the Ethereum API provider", 96 Value: node.DefaultIPCEndpoint("geth"), 97 } 98 SwarmApiFlag = cli.StringFlag{ 99 Name: "bzzapi", 100 Usage: "Swarm HTTP endpoint", 101 Value: "http://127.0.0.1:8500", 102 } 103 SwarmRecursiveUploadFlag = cli.BoolFlag{ 104 Name: "recursive", 105 Usage: "Upload directories recursively", 106 } 107 SwarmWantManifestFlag = cli.BoolTFlag{ 108 Name: "manifest", 109 Usage: "Automatic manifest upload", 110 } 111 SwarmUploadDefaultPath = cli.StringFlag{ 112 Name: "defaultpath", 113 Usage: "path to file served for empty url path (none)", 114 } 115 CorsStringFlag = cli.StringFlag{ 116 Name: "corsdomain", 117 Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')", 118 } 119 ) 120 121 func init() { 122 // Override flag defaults so bzzd can run alongside geth. 123 utils.ListenPortFlag.Value = 30399 124 utils.IPCPathFlag.Value = utils.DirectoryString{Value: "bzzd.ipc"} 125 utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3" 126 127 // Set up the cli app. 128 app.Action = bzzd 129 app.HideVersion = true // we have a command to print the version 130 app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" 131 app.Commands = []cli.Command{ 132 { 133 Action: version, 134 Name: "version", 135 Usage: "Print version numbers", 136 ArgsUsage: " ", 137 Description: ` 138 The output of this command is supposed to be machine-readable. 139 `, 140 }, 141 { 142 Action: upload, 143 Name: "up", 144 Usage: "upload a file or directory to swarm using the HTTP API", 145 ArgsUsage: " <file>", 146 Description: ` 147 "upload a file or directory to swarm using the HTTP API and prints the root hash", 148 `, 149 }, 150 { 151 Action: hash, 152 Name: "hash", 153 Usage: "print the swarm hash of a file or directory", 154 ArgsUsage: " <file>", 155 Description: ` 156 Prints the swarm hash of file or directory. 157 `, 158 }, 159 } 160 161 app.Flags = []cli.Flag{ 162 utils.IdentityFlag, 163 utils.DataDirFlag, 164 utils.BootnodesFlag, 165 utils.KeyStoreDirFlag, 166 utils.ListenPortFlag, 167 utils.NoDiscoverFlag, 168 utils.DiscoveryV5Flag, 169 utils.NetrestrictFlag, 170 utils.NodeKeyFileFlag, 171 utils.NodeKeyHexFlag, 172 utils.MaxPeersFlag, 173 utils.NATFlag, 174 utils.IPCDisabledFlag, 175 utils.IPCApiFlag, 176 utils.IPCPathFlag, 177 // bzzd-specific flags 178 CorsStringFlag, 179 EthAPIFlag, 180 SwarmConfigPathFlag, 181 SwarmSwapEnabledFlag, 182 SwarmSyncEnabledFlag, 183 SwarmPortFlag, 184 SwarmAccountFlag, 185 SwarmNetworkIdFlag, 186 ChequebookAddrFlag, 187 // upload flags 188 SwarmApiFlag, 189 SwarmRecursiveUploadFlag, 190 SwarmWantManifestFlag, 191 SwarmUploadDefaultPath, 192 } 193 app.Flags = append(app.Flags, debug.Flags...) 194 app.Before = func(ctx *cli.Context) error { 195 runtime.GOMAXPROCS(runtime.NumCPU()) 196 return debug.Setup(ctx) 197 } 198 app.After = func(ctx *cli.Context) error { 199 debug.Exit() 200 return nil 201 } 202 } 203 204 func main() { 205 if err := app.Run(os.Args); err != nil { 206 fmt.Fprintln(os.Stderr, err) 207 os.Exit(1) 208 } 209 } 210 211 func version(ctx *cli.Context) error { 212 fmt.Println(strings.Title(clientIdentifier)) 213 fmt.Println("Version:", versionString) 214 if gitCommit != "" { 215 fmt.Println("Git Commit:", gitCommit) 216 } 217 fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name)) 218 fmt.Println("Go Version:", runtime.Version()) 219 fmt.Println("OS:", runtime.GOOS) 220 fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) 221 fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) 222 return nil 223 } 224 225 func bzzd(ctx *cli.Context) error { 226 stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) 227 registerBzzService(ctx, stack) 228 utils.StartNode(stack) 229 networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name) 230 // Add bootnodes as initial peers. 231 if ctx.GlobalIsSet(utils.BootnodesFlag.Name) { 232 bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",") 233 injectBootnodes(stack.Server(), bootnodes) 234 } else { 235 if networkId == 3 { 236 injectBootnodes(stack.Server(), testbetBootNodes) 237 } 238 } 239 240 stack.Wait() 241 return nil 242 } 243 244 func registerBzzService(ctx *cli.Context, stack *node.Node) { 245 prvkey := getAccount(ctx, stack) 246 247 chbookaddr := common.HexToAddress(ctx.GlobalString(ChequebookAddrFlag.Name)) 248 bzzdir := ctx.GlobalString(SwarmConfigPathFlag.Name) 249 if bzzdir == "" { 250 bzzdir = stack.InstanceDir() 251 } 252 bzzconfig, err := bzzapi.NewConfig(bzzdir, chbookaddr, prvkey, ctx.GlobalUint64(SwarmNetworkIdFlag.Name)) 253 if err != nil { 254 utils.Fatalf("unable to configure swarm: %v", err) 255 } 256 bzzport := ctx.GlobalString(SwarmPortFlag.Name) 257 if len(bzzport) > 0 { 258 bzzconfig.Port = bzzport 259 } 260 swapEnabled := ctx.GlobalBool(SwarmSwapEnabledFlag.Name) 261 syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabledFlag.Name) 262 263 ethapi := ctx.GlobalString(EthAPIFlag.Name) 264 cors := ctx.GlobalString(CorsStringFlag.Name) 265 266 boot := func(ctx *node.ServiceContext) (node.Service, error) { 267 var client *ethclient.Client 268 if len(ethapi) > 0 { 269 client, err = ethclient.Dial(ethapi) 270 if err != nil { 271 utils.Fatalf("Can't connect: %v", err) 272 } 273 } 274 return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors) 275 } 276 if err := stack.Register(boot); err != nil { 277 utils.Fatalf("Failed to register the Swarm service: %v", err) 278 } 279 } 280 281 func getAccount(ctx *cli.Context, stack *node.Node) *ecdsa.PrivateKey { 282 keyid := ctx.GlobalString(SwarmAccountFlag.Name) 283 if keyid == "" { 284 utils.Fatalf("Option %q is required", SwarmAccountFlag.Name) 285 } 286 // Try to load the arg as a hex key file. 287 if key, err := crypto.LoadECDSA(keyid); err == nil { 288 glog.V(logger.Info).Infof("swarm account key loaded: %#x", crypto.PubkeyToAddress(key.PublicKey)) 289 return key 290 } 291 // Otherwise try getting it from the keystore. 292 return decryptStoreAccount(stack.AccountManager(), keyid) 293 } 294 295 func decryptStoreAccount(accman *accounts.Manager, account string) *ecdsa.PrivateKey { 296 var a accounts.Account 297 var err error 298 if common.IsHexAddress(account) { 299 a, err = accman.Find(accounts.Account{Address: common.HexToAddress(account)}) 300 } else if ix, ixerr := strconv.Atoi(account); ixerr == nil { 301 a, err = accman.AccountByIndex(ix) 302 } else { 303 utils.Fatalf("Can't find swarm account key %s", account) 304 } 305 if err != nil { 306 utils.Fatalf("Can't find swarm account key: %v", err) 307 } 308 keyjson, err := ioutil.ReadFile(a.File) 309 if err != nil { 310 utils.Fatalf("Can't load swarm account key: %v", err) 311 } 312 for i := 1; i <= 3; i++ { 313 passphrase := promptPassphrase(fmt.Sprintf("Unlocking swarm account %s [%d/3]", a.Address.Hex(), i)) 314 key, err := accounts.DecryptKey(keyjson, passphrase) 315 if err == nil { 316 return key.PrivateKey 317 } 318 } 319 utils.Fatalf("Can't decrypt swarm account key") 320 return nil 321 } 322 323 func promptPassphrase(prompt string) string { 324 if prompt != "" { 325 fmt.Println(prompt) 326 } 327 password, err := console.Stdin.PromptPassword("Passphrase: ") 328 if err != nil { 329 utils.Fatalf("Failed to read passphrase: %v", err) 330 } 331 return password 332 } 333 334 func injectBootnodes(srv *p2p.Server, nodes []string) { 335 for _, url := range nodes { 336 n, err := discover.ParseNode(url) 337 if err != nil { 338 glog.Errorf("invalid bootnode %q", err) 339 continue 340 } 341 srv.AddPeer(n) 342 } 343 }