github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/cmd/quickchain/main.go (about)

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