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