github.com/aquanetwork/aquachain@v1.7.8/cmd/aquachain/main.go (about)

     1  // Copyright 2014 The aquachain Authors
     2  // This file is part of aquachain.
     3  //
     4  // aquachain 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  // aquachain 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 aquachain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // aquachain is the official command-line client for AquaChain.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"runtime"
    24  	"sort"
    25  	"strings"
    26  	"time"
    27  
    28  	"gitlab.com/aquachain/aquachain/aqua"
    29  	"gitlab.com/aquachain/aquachain/aqua/accounts"
    30  	"gitlab.com/aquachain/aquachain/aqua/accounts/keystore"
    31  	"gitlab.com/aquachain/aquachain/cmd/utils"
    32  	"gitlab.com/aquachain/aquachain/common/log"
    33  	"gitlab.com/aquachain/aquachain/common/metrics"
    34  	"gitlab.com/aquachain/aquachain/internal/debug"
    35  	"gitlab.com/aquachain/aquachain/node"
    36  	"gitlab.com/aquachain/aquachain/opt/aquaclient"
    37  	"gitlab.com/aquachain/aquachain/opt/console"
    38  	"gopkg.in/urfave/cli.v1"
    39  )
    40  
    41  const (
    42  	clientIdentifier = "aquachain" // Client identifier to advertise over the network
    43  )
    44  
    45  var (
    46  	// Git SHA1 commit hash of the release (set via linker flags)
    47  	gitCommit = ""
    48  	// The app that holds all commands and flags.
    49  	app = utils.NewApp(gitCommit, "the aquachain command line interface")
    50  	// flags that configure the node
    51  	nodeFlags = []cli.Flag{
    52  		utils.IdentityFlag,
    53  		utils.UnlockedAccountFlag,
    54  		utils.PasswordFileFlag,
    55  		utils.BootnodesFlag,
    56  		utils.BootnodesV4Flag,
    57  		utils.BootnodesV5Flag,
    58  		utils.DataDirFlag,
    59  		utils.KeyStoreDirFlag,
    60  		utils.UseUSBFlag,
    61  		utils.AquahashCacheDirFlag,
    62  		utils.AquahashCachesInMemoryFlag,
    63  		utils.AquahashCachesOnDiskFlag,
    64  		utils.AquahashDatasetDirFlag,
    65  		utils.AquahashDatasetsInMemoryFlag,
    66  		utils.AquahashDatasetsOnDiskFlag,
    67  		utils.TxPoolNoLocalsFlag,
    68  		utils.TxPoolJournalFlag,
    69  		utils.TxPoolRejournalFlag,
    70  		utils.TxPoolPriceLimitFlag,
    71  		utils.TxPoolPriceBumpFlag,
    72  		utils.TxPoolAccountSlotsFlag,
    73  		utils.TxPoolGlobalSlotsFlag,
    74  		utils.TxPoolAccountQueueFlag,
    75  		utils.TxPoolGlobalQueueFlag,
    76  		utils.TxPoolLifetimeFlag,
    77  		utils.FastSyncFlag,
    78  		utils.SyncModeFlag,
    79  		utils.GCModeFlag,
    80  		utils.CacheFlag,
    81  		utils.CacheDatabaseFlag,
    82  		utils.CacheGCFlag,
    83  		utils.TrieCacheGenFlag,
    84  		utils.ListenPortFlag,
    85  		utils.MaxPeersFlag,
    86  		utils.MaxPendingPeersFlag,
    87  		utils.AquabaseFlag,
    88  		utils.GasPriceFlag,
    89  		utils.MinerThreadsFlag,
    90  		utils.MiningEnabledFlag,
    91  		utils.TargetGasLimitFlag,
    92  		utils.NATFlag,
    93  		utils.NoDiscoverFlag,
    94  		utils.OfflineFlag,
    95  		utils.DiscoveryV5Flag,
    96  		utils.NetrestrictFlag,
    97  		utils.NodeKeyFileFlag,
    98  		utils.NodeKeyHexFlag,
    99  		utils.DeveloperFlag,
   100  		utils.DeveloperPeriodFlag,
   101  		utils.TestnetFlag,
   102  		utils.Testnet2Flag,
   103  		utils.VMEnableDebugFlag,
   104  		utils.NetworkIdFlag,
   105  		utils.AquaStatsURLFlag,
   106  		utils.MetricsEnabledFlag,
   107  		utils.FakePoWFlag,
   108  		utils.NoCompactionFlag,
   109  		utils.GpoBlocksFlag,
   110  		utils.GpoPercentileFlag,
   111  		utils.ExtraDataFlag,
   112  		configFileFlag,
   113  	}
   114  
   115  	rpcFlags = []cli.Flag{
   116  		utils.RPCEnabledFlag,
   117  		utils.RPCUnlockFlag,
   118  		utils.RPCCORSDomainFlag,
   119  		utils.RPCVirtualHostsFlag,
   120  		utils.RPCListenAddrFlag,
   121  		utils.RPCAllowIPFlag,
   122  		utils.RPCPortFlag,
   123  		utils.RPCApiFlag,
   124  		utils.WSEnabledFlag,
   125  		utils.WSListenAddrFlag,
   126  		utils.WSPortFlag,
   127  		utils.WSApiFlag,
   128  		utils.WSAllowedOriginsFlag,
   129  		utils.IPCDisabledFlag,
   130  		utils.IPCPathFlag,
   131  	}
   132  
   133  	whisperFlags = []cli.Flag{
   134  		utils.WhisperEnabledFlag,
   135  		utils.WhisperMaxMessageSizeFlag,
   136  		utils.WhisperMinPOWFlag,
   137  	}
   138  )
   139  
   140  func init() {
   141  	// Initialize the CLI app and start AquaChain
   142  	app.Action = localConsole // default command is 'console'
   143  
   144  	app.HideVersion = true // we have a command to print the version
   145  	app.Copyright = "Copyright 2018 The Aquachain Authors"
   146  	app.Commands = []cli.Command{
   147  		// See chaincmd.go:
   148  		initCommand,
   149  		importCommand,
   150  		exportCommand,
   151  		copydbCommand,
   152  		removedbCommand,
   153  		dumpCommand,
   154  		// See monitorcmd.go:
   155  		monitorCommand,
   156  		// See accountcmd.go:
   157  		accountCommand,
   158  
   159  		// See walletcmd.go
   160  		walletCommand,
   161  		paperCommand,
   162  		// See consolecmd.go:
   163  		consoleCommand,
   164  		daemonCommand, // previously default
   165  		attachCommand,
   166  		javascriptCommand,
   167  		// See misccmd.go:
   168  		makecacheCommand,
   169  		makedagCommand,
   170  		versionCommand,
   171  		bugCommand,
   172  		licenseCommand,
   173  		// See config.go
   174  		dumpConfigCommand,
   175  	}
   176  	sort.Sort(cli.CommandsByName(app.Commands))
   177  
   178  	app.Flags = append(app.Flags, nodeFlags...)
   179  	app.Flags = append(app.Flags, rpcFlags...)
   180  	app.Flags = append(app.Flags, consoleFlags...)
   181  	app.Flags = append(app.Flags, debug.Flags...)
   182  	app.Flags = append(app.Flags, whisperFlags...)
   183  
   184  	app.Before = func(ctx *cli.Context) error {
   185  		runtime.GOMAXPROCS(runtime.NumCPU())
   186  		if err := debug.Setup(ctx); err != nil {
   187  			return err
   188  		}
   189  		// Start system runtime metrics collection
   190  		go metrics.CollectProcessMetrics(3 * time.Second)
   191  
   192  		utils.SetupNetwork(ctx)
   193  		return nil
   194  	}
   195  
   196  	app.After = func(ctx *cli.Context) error {
   197  		debug.Exit()
   198  		console.Stdin.Close() // Resets terminal mode.
   199  		return nil
   200  	}
   201  }
   202  
   203  func main() {
   204  	if err := app.Run(os.Args); err != nil {
   205  		fmt.Fprintln(os.Stderr, err)
   206  		os.Exit(1)
   207  	}
   208  }
   209  
   210  // daemonCommand is the main entry point into the system if the 'daemon' subcommand
   211  // is ran. It creates a default node based on the command line arguments
   212  // and runs it in blocking mode, waiting for it to be shut down.
   213  func daemonStart(ctx *cli.Context) error {
   214  	node := makeFullNode(ctx)
   215  	startNode(ctx, node)
   216  	node.Wait()
   217  	return nil
   218  }
   219  
   220  // startNode boots up the system node and all registered protocols, after which
   221  // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
   222  // miner.
   223  func startNode(ctx *cli.Context, stack *node.Node) {
   224  	// Start up the node itself
   225  	utils.StartNode(stack)
   226  
   227  	// Unlock any account specifically requested
   228  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   229  
   230  	passwords := utils.MakePasswordList(ctx)
   231  	unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
   232  	for i, account := range unlocks {
   233  		if trimmed := strings.TrimSpace(account); trimmed != "" {
   234  			unlockAccount(ctx, ks, trimmed, i, passwords)
   235  		}
   236  	}
   237  	// Register wallet event handlers to open and auto-derive wallets
   238  	events := make(chan accounts.WalletEvent, 16)
   239  	stack.AccountManager().Subscribe(events)
   240  
   241  	go func() {
   242  		// Create an chain state reader for self-derivation
   243  		rpcClient, err := stack.Attach()
   244  		if err != nil {
   245  			utils.Fatalf("Failed to attach to self: %v", err)
   246  		}
   247  		stateReader := aquaclient.NewClient(rpcClient)
   248  
   249  		// Open any wallets already attached
   250  		for _, wallet := range stack.AccountManager().Wallets() {
   251  			if err := wallet.Open(""); err != nil {
   252  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   253  			}
   254  		}
   255  		// Listen for wallet event till termination
   256  		for event := range events {
   257  			switch event.Kind {
   258  			case accounts.WalletArrived:
   259  				if err := event.Wallet.Open(""); err != nil {
   260  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   261  				}
   262  			case accounts.WalletOpened:
   263  				status, _ := event.Wallet.Status()
   264  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   265  
   266  				if event.Wallet.URL().Scheme == "ledger" {
   267  					event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader)
   268  				} else {
   269  					event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
   270  				}
   271  
   272  			case accounts.WalletDropped:
   273  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   274  				event.Wallet.Close()
   275  			}
   276  		}
   277  	}()
   278  	// Start auxiliary services if enabled
   279  	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
   280  		var aquachain *aqua.AquaChain
   281  		if err := stack.Service(&aquachain); err != nil {
   282  			utils.Fatalf("Aquachain service not running: %v", err)
   283  		}
   284  		// Use a reduced number of threads if requested
   285  		if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
   286  			type threaded interface {
   287  				SetThreads(threads int)
   288  			}
   289  			if th, ok := aquachain.Engine().(threaded); ok {
   290  				th.SetThreads(threads)
   291  			}
   292  		}
   293  		// Set the gas price to the limits from the CLI and start mining
   294  		aquachain.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
   295  		if err := aquachain.StartMining(true); err != nil {
   296  			utils.Fatalf("Failed to start mining: %v", err)
   297  		}
   298  	}
   299  }