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