github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/cmd/geth/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  // geth is the official command-line client for Ethereum.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/accounts"
    29  	"github.com/ethereum/go-ethereum/accounts/keystore"
    30  	"github.com/ethereum/go-ethereum/cmd/utils"
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/console/prompt"
    33  	"github.com/ethereum/go-ethereum/eth"
    34  	"github.com/ethereum/go-ethereum/eth/downloader"
    35  	"github.com/ethereum/go-ethereum/ethclient"
    36  	"github.com/ethereum/go-ethereum/internal/debug"
    37  	"github.com/ethereum/go-ethereum/internal/ethapi"
    38  	"github.com/ethereum/go-ethereum/internal/flags"
    39  	"github.com/ethereum/go-ethereum/log"
    40  	"github.com/ethereum/go-ethereum/metrics"
    41  	"github.com/ethereum/go-ethereum/node"
    42  	"gopkg.in/urfave/cli.v1"
    43  )
    44  
    45  const (
    46  	clientIdentifier     = "bor" // Client identifier to advertise over the network
    47  	repositoryIdentifier = "go-bor"
    48  )
    49  
    50  var (
    51  	// Git SHA1 commit hash of the release (set via linker flags)
    52  	gitCommit = ""
    53  	gitDate   = ""
    54  	// The app that holds all commands and flags.
    55  	app = flags.NewApp(gitCommit, gitDate, fmt.Sprintf("the %s command line interface", repositoryIdentifier))
    56  	// flags that configure the node
    57  	nodeFlags = []cli.Flag{
    58  		utils.BorLogsFlag,
    59  		utils.IdentityFlag,
    60  		utils.UnlockedAccountFlag,
    61  		utils.PasswordFileFlag,
    62  		utils.BootnodesFlag,
    63  		utils.DataDirFlag,
    64  		utils.AncientFlag,
    65  		utils.MinFreeDiskSpaceFlag,
    66  		utils.KeyStoreDirFlag,
    67  		utils.ExternalSignerFlag,
    68  		utils.NoUSBFlag,
    69  		utils.USBFlag,
    70  		utils.SmartCardDaemonPathFlag,
    71  		utils.OverrideLondonFlag,
    72  		utils.EthashCacheDirFlag,
    73  		utils.EthashCachesInMemoryFlag,
    74  		utils.EthashCachesOnDiskFlag,
    75  		utils.EthashCachesLockMmapFlag,
    76  		utils.EthashDatasetDirFlag,
    77  		utils.EthashDatasetsInMemoryFlag,
    78  		utils.EthashDatasetsOnDiskFlag,
    79  		utils.EthashDatasetsLockMmapFlag,
    80  		utils.TxPoolLocalsFlag,
    81  		utils.TxPoolNoLocalsFlag,
    82  		utils.TxPoolJournalFlag,
    83  		utils.TxPoolRejournalFlag,
    84  		utils.TxPoolPriceLimitFlag,
    85  		utils.TxPoolPriceBumpFlag,
    86  		utils.TxPoolAccountSlotsFlag,
    87  		utils.TxPoolGlobalSlotsFlag,
    88  		utils.TxPoolAccountQueueFlag,
    89  		utils.TxPoolGlobalQueueFlag,
    90  		utils.TxPoolLifetimeFlag,
    91  		utils.SyncModeFlag,
    92  		utils.ExitWhenSyncedFlag,
    93  		utils.GCModeFlag,
    94  		utils.SnapshotFlag,
    95  		utils.TxLookupLimitFlag,
    96  		utils.LightServeFlag,
    97  		utils.LightIngressFlag,
    98  		utils.LightEgressFlag,
    99  		utils.LightMaxPeersFlag,
   100  		utils.LightNoPruneFlag,
   101  		utils.LightKDFFlag,
   102  		utils.UltraLightServersFlag,
   103  		utils.UltraLightFractionFlag,
   104  		utils.UltraLightOnlyAnnounceFlag,
   105  		utils.LightNoSyncServeFlag,
   106  		utils.WhitelistFlag,
   107  		utils.BloomFilterSizeFlag,
   108  		utils.CacheFlag,
   109  		utils.CacheDatabaseFlag,
   110  		utils.CacheTrieFlag,
   111  		utils.CacheTrieJournalFlag,
   112  		utils.CacheTrieRejournalFlag,
   113  		utils.CacheGCFlag,
   114  		utils.CacheSnapshotFlag,
   115  		utils.CacheNoPrefetchFlag,
   116  		utils.CachePreimagesFlag,
   117  		utils.ListenPortFlag,
   118  		utils.MaxPeersFlag,
   119  		utils.MaxPendingPeersFlag,
   120  		utils.MiningEnabledFlag,
   121  		utils.MinerThreadsFlag,
   122  		utils.MinerNotifyFlag,
   123  		utils.LegacyMinerGasTargetFlag,
   124  		utils.MinerGasLimitFlag,
   125  		utils.MinerGasPriceFlag,
   126  		utils.MinerEtherbaseFlag,
   127  		utils.MinerExtraDataFlag,
   128  		utils.MinerRecommitIntervalFlag,
   129  		utils.MinerNoVerifyFlag,
   130  		utils.NATFlag,
   131  		utils.NoDiscoverFlag,
   132  		utils.DiscoveryV5Flag,
   133  		utils.NetrestrictFlag,
   134  		utils.NodeKeyFileFlag,
   135  		utils.NodeKeyHexFlag,
   136  		utils.DNSDiscoveryFlag,
   137  		utils.MainnetFlag,
   138  		utils.DeveloperFlag,
   139  		utils.DeveloperPeriodFlag,
   140  		utils.RopstenFlag,
   141  		utils.RinkebyFlag,
   142  		utils.GoerliFlag,
   143  		utils.MumbaiFlag,
   144  		utils.BorMainnetFlag,
   145  		utils.VMEnableDebugFlag,
   146  		utils.NetworkIdFlag,
   147  		utils.EthStatsURLFlag,
   148  		utils.FakePoWFlag,
   149  		utils.NoCompactionFlag,
   150  		utils.GpoBlocksFlag,
   151  		utils.GpoPercentileFlag,
   152  		utils.GpoMaxGasPriceFlag,
   153  		utils.GpoIgnoreGasPriceFlag,
   154  		utils.MinerNotifyFullFlag,
   155  		configFileFlag,
   156  		utils.CatalystFlag,
   157  	}
   158  
   159  	rpcFlags = []cli.Flag{
   160  		utils.HTTPEnabledFlag,
   161  		utils.HTTPListenAddrFlag,
   162  		utils.HTTPPortFlag,
   163  		utils.HTTPCORSDomainFlag,
   164  		utils.HTTPVirtualHostsFlag,
   165  		utils.GraphQLEnabledFlag,
   166  		utils.GraphQLCORSDomainFlag,
   167  		utils.GraphQLVirtualHostsFlag,
   168  		utils.HTTPApiFlag,
   169  		utils.HTTPPathPrefixFlag,
   170  		utils.WSEnabledFlag,
   171  		utils.WSListenAddrFlag,
   172  		utils.WSPortFlag,
   173  		utils.WSApiFlag,
   174  		utils.WSAllowedOriginsFlag,
   175  		utils.WSPathPrefixFlag,
   176  		utils.IPCDisabledFlag,
   177  		utils.IPCPathFlag,
   178  		utils.InsecureUnlockAllowedFlag,
   179  		utils.RPCGlobalGasCapFlag,
   180  		utils.RPCGlobalEVMTimeoutFlag,
   181  		utils.RPCGlobalTxFeeCapFlag,
   182  		utils.AllowUnprotectedTxs,
   183  	}
   184  
   185  	metricsFlags = []cli.Flag{
   186  		utils.MetricsEnabledFlag,
   187  		utils.MetricsEnabledExpensiveFlag,
   188  		utils.MetricsHTTPFlag,
   189  		utils.MetricsPortFlag,
   190  		utils.MetricsEnableInfluxDBFlag,
   191  		utils.MetricsInfluxDBEndpointFlag,
   192  		utils.MetricsInfluxDBDatabaseFlag,
   193  		utils.MetricsInfluxDBUsernameFlag,
   194  		utils.MetricsInfluxDBPasswordFlag,
   195  		utils.MetricsInfluxDBTagsFlag,
   196  		utils.MetricsEnableInfluxDBV2Flag,
   197  		utils.MetricsInfluxDBTokenFlag,
   198  		utils.MetricsInfluxDBBucketFlag,
   199  		utils.MetricsInfluxDBOrganizationFlag,
   200  	}
   201  )
   202  
   203  func init() {
   204  	// Initialize the CLI app and start Geth
   205  	app.Action = geth
   206  	app.HideVersion = true // we have a command to print the version
   207  	app.Copyright = "Copyright 2013-2021 The go-ethereum Authors"
   208  	app.Commands = []cli.Command{
   209  		// See chaincmd.go:
   210  		initCommand,
   211  		importCommand,
   212  		exportCommand,
   213  		importPreimagesCommand,
   214  		exportPreimagesCommand,
   215  		removedbCommand,
   216  		dumpCommand,
   217  		dumpGenesisCommand,
   218  		// See accountcmd.go:
   219  		accountCommand,
   220  		walletCommand,
   221  		// See consolecmd.go:
   222  		consoleCommand,
   223  		attachCommand,
   224  		javascriptCommand,
   225  		// See misccmd.go:
   226  		makecacheCommand,
   227  		makedagCommand,
   228  		versionCommand,
   229  		versionCheckCommand,
   230  		licenseCommand,
   231  		// See config.go
   232  		dumpConfigCommand,
   233  		// see dbcmd.go
   234  		dbCommand,
   235  		// See cmd/utils/flags_legacy.go
   236  		utils.ShowDeprecated,
   237  		// See snapshot.go
   238  		snapshotCommand,
   239  	}
   240  	sort.Sort(cli.CommandsByName(app.Commands))
   241  
   242  	app.Flags = append(app.Flags, nodeFlags...)
   243  	app.Flags = append(app.Flags, rpcFlags...)
   244  	app.Flags = append(app.Flags, consoleFlags...)
   245  	app.Flags = append(app.Flags, debug.Flags...)
   246  	app.Flags = append(app.Flags, metricsFlags...)
   247  
   248  	// add bor flags
   249  	app.Flags = append(app.Flags, utils.BorFlags...)
   250  
   251  	app.Before = func(ctx *cli.Context) error {
   252  		return debug.Setup(ctx)
   253  	}
   254  	app.After = func(ctx *cli.Context) error {
   255  		debug.Exit()
   256  		prompt.Stdin.Close() // Resets terminal mode.
   257  		return nil
   258  	}
   259  }
   260  
   261  func main() {
   262  	if err := app.Run(os.Args); err != nil {
   263  		fmt.Fprintln(os.Stderr, err)
   264  		os.Exit(1)
   265  	}
   266  }
   267  
   268  // prepare manipulates memory cache allowance and setups metric system.
   269  // This function should be called before launching devp2p stack.
   270  func prepare(ctx *cli.Context) {
   271  	// If we're running a known preset, log it for convenience.
   272  	switch {
   273  	case ctx.GlobalIsSet(utils.RopstenFlag.Name):
   274  		log.Info("Starting Geth on Ropsten testnet...")
   275  
   276  	case ctx.GlobalIsSet(utils.RinkebyFlag.Name):
   277  		log.Info("Starting Geth on Rinkeby testnet...")
   278  
   279  	case ctx.GlobalIsSet(utils.GoerliFlag.Name):
   280  		log.Info("Starting Geth on Görli testnet...")
   281  
   282  	case ctx.GlobalIsSet(utils.MumbaiFlag.Name):
   283  		log.Info("Starting Bor on Mumbai testnet...")
   284  
   285  	case ctx.GlobalIsSet(utils.BorMainnetFlag.Name):
   286  		log.Info("Starting Bor on Bor mainnet...")
   287  
   288  	case ctx.GlobalIsSet(utils.DeveloperFlag.Name):
   289  		log.Info("Starting Geth in ephemeral dev mode...")
   290  
   291  	case !ctx.GlobalIsSet(utils.NetworkIdFlag.Name):
   292  		log.Info("Starting Geth on Ethereum mainnet...")
   293  	}
   294  	// If we're a full node on mainnet without --cache specified, bump default cache allowance
   295  	if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) {
   296  		// Make sure we're not on any supported preconfigured testnet either
   297  		if !ctx.GlobalIsSet(utils.RopstenFlag.Name) && !ctx.GlobalIsSet(utils.RinkebyFlag.Name) && !ctx.GlobalIsSet(utils.GoerliFlag.Name) && !ctx.GlobalIsSet(utils.MumbaiFlag.Name) && !ctx.GlobalIsSet(utils.DeveloperFlag.Name) {
   298  			// Nope, we're really on mainnet. Bump that cache up!
   299  			log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096)
   300  			ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096))
   301  		}
   302  	}
   303  	// If we're running a light client on any network, drop the cache to some meaningfully low amount
   304  	if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) {
   305  		log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128)
   306  		ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128))
   307  	}
   308  
   309  	// Start metrics export if enabled
   310  	utils.SetupMetrics(ctx)
   311  
   312  	// Start system runtime metrics collection
   313  	go metrics.CollectProcessMetrics(3 * time.Second)
   314  }
   315  
   316  // geth is the main entry point into the system if no special subcommand is ran.
   317  // It creates a default node based on the command line arguments and runs it in
   318  // blocking mode, waiting for it to be shut down.
   319  func geth(ctx *cli.Context) error {
   320  	if args := ctx.Args(); len(args) > 0 {
   321  		return fmt.Errorf("invalid command: %q", args[0])
   322  	}
   323  
   324  	prepare(ctx)
   325  	stack, backend := makeFullNode(ctx)
   326  	defer stack.Close()
   327  
   328  	startNode(ctx, stack, backend)
   329  	stack.Wait()
   330  	return nil
   331  }
   332  
   333  // startNode boots up the system node and all registered protocols, after which
   334  // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
   335  // miner.
   336  func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
   337  	debug.Memsize.Add("node", stack)
   338  
   339  	// Start up the node itself
   340  	utils.StartNode(ctx, stack)
   341  
   342  	// Unlock any account specifically requested
   343  	unlockAccounts(ctx, stack)
   344  
   345  	// Register wallet event handlers to open and auto-derive wallets
   346  	events := make(chan accounts.WalletEvent, 16)
   347  	stack.AccountManager().Subscribe(events)
   348  
   349  	// Create a client to interact with local geth node.
   350  	rpcClient, err := stack.Attach()
   351  	if err != nil {
   352  		utils.Fatalf("Failed to attach to self: %v", err)
   353  	}
   354  	ethClient := ethclient.NewClient(rpcClient)
   355  
   356  	go func() {
   357  		// Open any wallets already attached
   358  		for _, wallet := range stack.AccountManager().Wallets() {
   359  			if err := wallet.Open(""); err != nil {
   360  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   361  			}
   362  		}
   363  		// Listen for wallet event till termination
   364  		for event := range events {
   365  			switch event.Kind {
   366  			case accounts.WalletArrived:
   367  				if err := event.Wallet.Open(""); err != nil {
   368  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   369  				}
   370  			case accounts.WalletOpened:
   371  				status, _ := event.Wallet.Status()
   372  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   373  
   374  				var derivationPaths []accounts.DerivationPath
   375  				if event.Wallet.URL().Scheme == "ledger" {
   376  					derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath)
   377  				}
   378  				derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath)
   379  
   380  				event.Wallet.SelfDerive(derivationPaths, ethClient)
   381  
   382  			case accounts.WalletDropped:
   383  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   384  				event.Wallet.Close()
   385  			}
   386  		}
   387  	}()
   388  
   389  	// Spawn a standalone goroutine for status synchronization monitoring,
   390  	// close the node when synchronization is complete if user required.
   391  	if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) {
   392  		go func() {
   393  			sub := stack.EventMux().Subscribe(downloader.DoneEvent{})
   394  			defer sub.Unsubscribe()
   395  			for {
   396  				event := <-sub.Chan()
   397  				if event == nil {
   398  					continue
   399  				}
   400  				done, ok := event.Data.(downloader.DoneEvent)
   401  				if !ok {
   402  					continue
   403  				}
   404  				if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute {
   405  					log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(),
   406  						"age", common.PrettyAge(timestamp))
   407  					stack.Close()
   408  				}
   409  			}
   410  		}()
   411  	}
   412  
   413  	// Start auxiliary services if enabled
   414  	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
   415  		// Mining only makes sense if a full Ethereum node is running
   416  		if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
   417  			utils.Fatalf("Light clients do not support mining")
   418  		}
   419  		ethBackend, ok := backend.(*eth.EthAPIBackend)
   420  		if !ok {
   421  			utils.Fatalf("Ethereum service not running")
   422  		}
   423  		// Set the gas price to the limits from the CLI and start mining
   424  		gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
   425  		ethBackend.TxPool().SetGasPrice(gasprice)
   426  		// start mining
   427  		threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
   428  		if err := ethBackend.StartMining(threads); err != nil {
   429  			utils.Fatalf("Failed to start mining: %v", err)
   430  		}
   431  	}
   432  }
   433  
   434  // unlockAccounts unlocks any account specifically requested.
   435  func unlockAccounts(ctx *cli.Context, stack *node.Node) {
   436  	var unlocks []string
   437  	inputs := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
   438  	for _, input := range inputs {
   439  		if trimmed := strings.TrimSpace(input); trimmed != "" {
   440  			unlocks = append(unlocks, trimmed)
   441  		}
   442  	}
   443  	// Short circuit if there is no account to unlock.
   444  	if len(unlocks) == 0 {
   445  		return
   446  	}
   447  	// If insecure account unlocking is not allowed if node's APIs are exposed to external.
   448  	// Print warning log to user and skip unlocking.
   449  	if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() {
   450  		utils.Fatalf("Account unlock with HTTP access is forbidden!")
   451  	}
   452  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   453  	passwords := utils.MakePasswordList(ctx)
   454  	for i, account := range unlocks {
   455  		unlockAccount(ks, account, i, passwords)
   456  	}
   457  }