github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/cmd/platon/main.go (about)

     1  // Copyright 2014 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  // platon is the official command-line client for Ethereum.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"math"
    23  	"os"
    24  	"runtime"
    25  	godebug "runtime/debug"
    26  	"sort"
    27  	"strconv"
    28  	"strings"
    29  	"time"
    30  
    31  	"github.com/PlatONnetwork/PlatON-Go/accounts"
    32  	"github.com/PlatONnetwork/PlatON-Go/accounts/keystore"
    33  	"github.com/PlatONnetwork/PlatON-Go/cmd/utils"
    34  	"github.com/PlatONnetwork/PlatON-Go/console"
    35  	"github.com/PlatONnetwork/PlatON-Go/eth"
    36  	"github.com/PlatONnetwork/PlatON-Go/ethclient"
    37  	"github.com/PlatONnetwork/PlatON-Go/internal/debug"
    38  	"github.com/PlatONnetwork/PlatON-Go/log"
    39  	"github.com/PlatONnetwork/PlatON-Go/metrics"
    40  	"github.com/PlatONnetwork/PlatON-Go/node"
    41  	"github.com/elastic/gosigar"
    42  	"gopkg.in/urfave/cli.v1"
    43  )
    44  
    45  const (
    46  	clientIdentifier = "platon" // Client identifier to advertise over the network
    47  )
    48  
    49  var (
    50  	// Git SHA1 commit hash of the release (set via linker flags)
    51  	gitCommit = ""
    52  	// The app that holds all commands and flags.
    53  	app = utils.NewApp(gitCommit, "the platon-go command line interface")
    54  	// flags that configure the node
    55  	nodeFlags = []cli.Flag{
    56  		utils.IdentityFlag,
    57  		utils.UnlockedAccountFlag,
    58  		utils.PasswordFileFlag,
    59  		utils.BootnodesFlag,
    60  		utils.BootnodesV4Flag,
    61  		utils.BootnodesV5Flag,
    62  		utils.DataDirFlag,
    63  		utils.KeyStoreDirFlag,
    64  		utils.NoUSBFlag,
    65  		utils.DashboardEnabledFlag,
    66  		utils.DashboardAddrFlag,
    67  		utils.DashboardPortFlag,
    68  		utils.DashboardRefreshFlag,
    69  		utils.TxPoolLocalsFlag,
    70  		utils.TxPoolNoLocalsFlag,
    71  		utils.TxPoolJournalFlag,
    72  		utils.TxPoolRejournalFlag,
    73  		utils.TxPoolPriceLimitFlag,
    74  		utils.TxPoolPriceBumpFlag,
    75  		utils.TxPoolAccountSlotsFlag,
    76  		utils.TxPoolGlobalSlotsFlag,
    77  		utils.TxPoolAccountQueueFlag,
    78  		utils.TxPoolGlobalQueueFlag,
    79  		utils.TxPoolGlobalTxCountFlag,
    80  		utils.TxPoolLifetimeFlag,
    81  		utils.SyncModeFlag,
    82  		utils.GCModeFlag,
    83  		utils.LightServFlag,
    84  		utils.LightPeersFlag,
    85  		utils.LightKDFFlag,
    86  		utils.CacheFlag,
    87  		utils.CacheDatabaseFlag,
    88  		utils.CacheGCFlag,
    89  		utils.TrieCacheGenFlag,
    90  		utils.ListenPortFlag,
    91  		utils.MaxPeersFlag,
    92  		utils.MaxConsensusPeersFlag,
    93  		utils.MaxPendingPeersFlag,
    94  		utils.MiningEnabledFlag,
    95  		utils.MinerThreadsFlag,
    96  		utils.MinerLegacyThreadsFlag,
    97  		utils.MinerNotifyFlag,
    98  		utils.MinerGasTargetFlag,
    99  		utils.MinerLegacyGasTargetFlag,
   100  		utils.MinerGasLimitFlag,
   101  		utils.MinerGasPriceFlag,
   102  		utils.MinerLegacyGasPriceFlag,
   103  		utils.MinerEtherbaseFlag,
   104  		utils.MinerLegacyEtherbaseFlag,
   105  		utils.MinerExtraDataFlag,
   106  		utils.MinerLegacyExtraDataFlag,
   107  		utils.MinerRecommitIntervalFlag,
   108  		utils.MinerNoVerfiyFlag,
   109  		utils.NATFlag,
   110  		utils.NoDiscoverFlag,
   111  		utils.DiscoveryV5Flag,
   112  		utils.NetrestrictFlag,
   113  		utils.NodeKeyFileFlag,
   114  		utils.NodeKeyHexFlag,
   115  		utils.DeveloperFlag,
   116  		utils.DeveloperPeriodFlag,
   117  		utils.TestnetFlag,
   118  		utils.BetanetFlag,
   119  		utils.InnerTestnetFlag,
   120  		utils.InnerDevnetFlag,
   121  		utils.InnerTimeFlag,
   122  		utils.VMEnableDebugFlag,
   123  		utils.NetworkIdFlag,
   124  		utils.RPCCORSDomainFlag,
   125  		utils.RPCVirtualHostsFlag,
   126  		utils.EthStatsURLFlag,
   127  		utils.MetricsEnabledFlag,
   128  		utils.FakePoWFlag,
   129  		utils.NoCompactionFlag,
   130  		utils.GpoBlocksFlag,
   131  		utils.GpoPercentileFlag,
   132  		utils.EWASMInterpreterFlag,
   133  		utils.EVMInterpreterFlag,
   134  		configFileFlag,
   135  	}
   136  
   137  	rpcFlags = []cli.Flag{
   138  		utils.RPCEnabledFlag,
   139  		utils.RPCListenAddrFlag,
   140  		utils.RPCPortFlag,
   141  		utils.RPCApiFlag,
   142  		utils.WSEnabledFlag,
   143  		utils.WSListenAddrFlag,
   144  		utils.WSPortFlag,
   145  		utils.WSApiFlag,
   146  		utils.WSAllowedOriginsFlag,
   147  		utils.IPCDisabledFlag,
   148  		utils.IPCPathFlag,
   149  	}
   150  
   151  	whisperFlags = []cli.Flag{
   152  		utils.WhisperEnabledFlag,
   153  		utils.WhisperMaxMessageSizeFlag,
   154  		utils.WhisperMinPOWFlag,
   155  		utils.WhisperRestrictConnectionBetweenLightClientsFlag,
   156  	}
   157  
   158  	metricsFlags = []cli.Flag{
   159  		utils.MetricsEnableInfluxDBFlag,
   160  		utils.MetricsInfluxDBEndpointFlag,
   161  		utils.MetricsInfluxDBDatabaseFlag,
   162  		utils.MetricsInfluxDBUsernameFlag,
   163  		utils.MetricsInfluxDBPasswordFlag,
   164  		utils.MetricsInfluxDBHostTagFlag,
   165  	}
   166  
   167  	mpcFlags = []cli.Flag{
   168  		utils.MPCEnabledFlag,
   169  		utils.MPCIceFileFlag,
   170  		utils.MPCActorFlag,
   171  	}
   172  	vcFlags = []cli.Flag{
   173  		utils.VCEnabledFlag,
   174  		utils.VCActorFlag,
   175  		utils.VCPasswordFlag,
   176  	}
   177  )
   178  
   179  func init() {
   180  	// Initialize the CLI app and start Geth
   181  	app.Action = geth
   182  	app.HideVersion = true // we have a command to print the version
   183  	app.Copyright = "Copyright 2019 The PlatON-Go Authors"
   184  	app.Commands = []cli.Command{
   185  		// See chaincmd.go:
   186  		initCommand,
   187  		importCommand,
   188  		exportCommand,
   189  		importPreimagesCommand,
   190  		exportPreimagesCommand,
   191  		copydbCommand,
   192  		removedbCommand,
   193  		dumpCommand,
   194  		// See monitorcmd.go:
   195  		monitorCommand,
   196  		// See accountcmd.go:
   197  		accountCommand,
   198  		walletCommand,
   199  		// See consolecmd.go:
   200  		consoleCommand,
   201  		attachCommand,
   202  		javascriptCommand,
   203  		// See misccmd.go:
   204  		makecacheCommand,
   205  		makedagCommand,
   206  		versionCommand,
   207  		bugCommand,
   208  		licenseCommand,
   209  		// See config.go
   210  		dumpConfigCommand,
   211  	}
   212  	sort.Sort(cli.CommandsByName(app.Commands))
   213  
   214  	app.Flags = append(app.Flags, nodeFlags...)
   215  	app.Flags = append(app.Flags, rpcFlags...)
   216  	app.Flags = append(app.Flags, consoleFlags...)
   217  	app.Flags = append(app.Flags, debug.Flags...)
   218  	app.Flags = append(app.Flags, whisperFlags...)
   219  	app.Flags = append(app.Flags, metricsFlags...)
   220  
   221  	// for mpc
   222  	app.Flags = append(app.Flags, mpcFlags...)
   223  	// for vc
   224  	app.Flags = append(app.Flags, vcFlags...)
   225  
   226  	app.Before = func(ctx *cli.Context) error {
   227  		runtime.GOMAXPROCS(runtime.NumCPU())
   228  
   229  		logdir := ""
   230  		if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
   231  			logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs")
   232  		}
   233  		if err := debug.Setup(ctx, logdir); err != nil {
   234  			return err
   235  		}
   236  
   237  		//init wasm logfile
   238  		if err := debug.SetupWasmLog(ctx); err != nil {
   239  			return err
   240  		}
   241  
   242  		// Cap the cache allowance and tune the garbage collector
   243  		var mem gosigar.Mem
   244  		if err := mem.Get(); err == nil {
   245  			allowance := int(mem.Total / 1024 / 1024 / 3)
   246  			if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance {
   247  				log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
   248  				ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance))
   249  			}
   250  		}
   251  		// Ensure Go's GC ignores the database cache for trigger percentage
   252  		cache := ctx.GlobalInt(utils.CacheFlag.Name)
   253  		gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
   254  
   255  		log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
   256  		godebug.SetGCPercent(int(gogc))
   257  
   258  		// Start metrics export if enabled
   259  		utils.SetupMetrics(ctx)
   260  
   261  		// Start system runtime metrics collection
   262  		go metrics.CollectProcessMetrics(3 * time.Second)
   263  
   264  		return nil
   265  	}
   266  
   267  	app.After = func(ctx *cli.Context) error {
   268  		debug.Exit()
   269  		console.Stdin.Close() // Resets terminal mode.
   270  		return nil
   271  	}
   272  }
   273  
   274  func main() {
   275  	if err := app.Run(os.Args); err != nil {
   276  		fmt.Fprintln(os.Stderr, err)
   277  		os.Exit(1)
   278  	}
   279  }
   280  
   281  // platon is the main entry point into the system if no special subcommand is ran.
   282  // It creates a default node based on the command line arguments and runs it in
   283  // blocking mode, waiting for it to be shut down.
   284  func geth(ctx *cli.Context) error {
   285  	if args := ctx.Args(); len(args) > 0 {
   286  		return fmt.Errorf("invalid command: %q", args[0])
   287  	}
   288  	node := makeFullNode(ctx)
   289  	startNode(ctx, node)
   290  	node.Wait()
   291  	return nil
   292  }
   293  
   294  // startNode boots up the system node and all registered protocols, after which
   295  // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
   296  // miner.
   297  func startNode(ctx *cli.Context, stack *node.Node) {
   298  	debug.Memsize.Add("node", stack)
   299  
   300  	// Start up the node itself
   301  	utils.StartNode(stack)
   302  
   303  	// Unlock any account specifically requested
   304  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   305  
   306  	passwords := utils.MakePasswordList(ctx)
   307  	unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
   308  	for i, account := range unlocks {
   309  		if trimmed := strings.TrimSpace(account); trimmed != "" {
   310  			unlockAccount(ctx, ks, trimmed, i, passwords)
   311  		}
   312  	}
   313  	// Register wallet event handlers to open and auto-derive wallets
   314  	events := make(chan accounts.WalletEvent, 16)
   315  	stack.AccountManager().Subscribe(events)
   316  
   317  	go func() {
   318  		// Create a chain state reader for self-derivation
   319  		rpcClient, err := stack.Attach()
   320  		if err != nil {
   321  			utils.Fatalf("Failed to attach to self: %v", err)
   322  		}
   323  		stateReader := ethclient.NewClient(rpcClient)
   324  
   325  		// Open any wallets already attached
   326  		for _, wallet := range stack.AccountManager().Wallets() {
   327  			if err := wallet.Open(""); err != nil {
   328  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   329  			}
   330  		}
   331  		// Listen for wallet event till termination
   332  		for event := range events {
   333  			switch event.Kind {
   334  			case accounts.WalletArrived:
   335  				if err := event.Wallet.Open(""); err != nil {
   336  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   337  				}
   338  			case accounts.WalletOpened:
   339  				status, _ := event.Wallet.Status()
   340  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   341  
   342  				derivationPath := accounts.DefaultBaseDerivationPath
   343  				if event.Wallet.URL().Scheme == "ledger" {
   344  					derivationPath = accounts.DefaultLedgerBaseDerivationPath
   345  				}
   346  				event.Wallet.SelfDerive(derivationPath, stateReader)
   347  
   348  			case accounts.WalletDropped:
   349  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   350  				event.Wallet.Close()
   351  			}
   352  		}
   353  	}()
   354  	// Start auxiliary services if enabled
   355  	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
   356  		// Mining only makes sense if a full Ethereum node is running
   357  		if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
   358  			utils.Fatalf("Light clients do not support mining")
   359  		}
   360  		var ethereum *eth.Ethereum
   361  		if err := stack.Service(&ethereum); err != nil {
   362  			utils.Fatalf("Ethereum service not running: %v", err)
   363  		}
   364  		// Set the gas price to the limits from the CLI and start mining
   365  		gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name)
   366  		if ctx.IsSet(utils.MinerGasPriceFlag.Name) {
   367  			gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
   368  		}
   369  		ethereum.TxPool().SetGasPrice(gasprice)
   370  
   371  		threads := ctx.GlobalInt(utils.MinerLegacyThreadsFlag.Name)
   372  		if ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
   373  			threads = ctx.GlobalInt(utils.MinerThreadsFlag.Name)
   374  		}
   375  		if err := ethereum.StartMining(threads); err != nil {
   376  			utils.Fatalf("Failed to start mining: %v", err)
   377  		}
   378  	}
   379  }