github.com/ethereum/go-ethereum@v1.16.1/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 a command-line client for Ethereum.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"slices"
    24  	"sort"
    25  	"strconv"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/accounts"
    29  	"github.com/ethereum/go-ethereum/cmd/utils"
    30  	"github.com/ethereum/go-ethereum/common"
    31  	"github.com/ethereum/go-ethereum/console/prompt"
    32  	"github.com/ethereum/go-ethereum/eth/downloader"
    33  	"github.com/ethereum/go-ethereum/ethclient"
    34  	"github.com/ethereum/go-ethereum/internal/debug"
    35  	"github.com/ethereum/go-ethereum/internal/flags"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"github.com/ethereum/go-ethereum/node"
    38  	"go.uber.org/automaxprocs/maxprocs"
    39  
    40  	// Force-load the tracer engines to trigger registration
    41  	_ "github.com/ethereum/go-ethereum/eth/tracers/js"
    42  	_ "github.com/ethereum/go-ethereum/eth/tracers/live"
    43  	_ "github.com/ethereum/go-ethereum/eth/tracers/native"
    44  
    45  	"github.com/urfave/cli/v2"
    46  )
    47  
    48  const (
    49  	clientIdentifier = "geth" // Client identifier to advertise over the network
    50  )
    51  
    52  var (
    53  	// flags that configure the node
    54  	nodeFlags = slices.Concat([]cli.Flag{
    55  		utils.IdentityFlag,
    56  		utils.UnlockedAccountFlag,
    57  		utils.PasswordFileFlag,
    58  		utils.BootnodesFlag,
    59  		utils.MinFreeDiskSpaceFlag,
    60  		utils.KeyStoreDirFlag,
    61  		utils.ExternalSignerFlag,
    62  		utils.NoUSBFlag, // deprecated
    63  		utils.USBFlag,
    64  		utils.SmartCardDaemonPathFlag,
    65  		utils.OverrideOsaka,
    66  		utils.OverrideVerkle,
    67  		utils.EnablePersonal, // deprecated
    68  		utils.TxPoolLocalsFlag,
    69  		utils.TxPoolNoLocalsFlag,
    70  		utils.TxPoolJournalFlag,
    71  		utils.TxPoolRejournalFlag,
    72  		utils.TxPoolPriceLimitFlag,
    73  		utils.TxPoolPriceBumpFlag,
    74  		utils.TxPoolAccountSlotsFlag,
    75  		utils.TxPoolGlobalSlotsFlag,
    76  		utils.TxPoolAccountQueueFlag,
    77  		utils.TxPoolGlobalQueueFlag,
    78  		utils.TxPoolLifetimeFlag,
    79  		utils.BlobPoolDataDirFlag,
    80  		utils.BlobPoolDataCapFlag,
    81  		utils.BlobPoolPriceBumpFlag,
    82  		utils.SyncModeFlag,
    83  		utils.SyncTargetFlag,
    84  		utils.ExitWhenSyncedFlag,
    85  		utils.GCModeFlag,
    86  		utils.SnapshotFlag,
    87  		utils.TxLookupLimitFlag, // deprecated
    88  		utils.TransactionHistoryFlag,
    89  		utils.ChainHistoryFlag,
    90  		utils.LogHistoryFlag,
    91  		utils.LogNoHistoryFlag,
    92  		utils.LogExportCheckpointsFlag,
    93  		utils.StateHistoryFlag,
    94  		utils.LightKDFFlag,
    95  		utils.EthRequiredBlocksFlag,
    96  		utils.LegacyWhitelistFlag, // deprecated
    97  		utils.CacheFlag,
    98  		utils.CacheDatabaseFlag,
    99  		utils.CacheTrieFlag,
   100  		utils.CacheTrieJournalFlag,   // deprecated
   101  		utils.CacheTrieRejournalFlag, // deprecated
   102  		utils.CacheGCFlag,
   103  		utils.CacheSnapshotFlag,
   104  		utils.CacheNoPrefetchFlag,
   105  		utils.CachePreimagesFlag,
   106  		utils.CacheLogSizeFlag,
   107  		utils.FDLimitFlag,
   108  		utils.CryptoKZGFlag,
   109  		utils.ListenPortFlag,
   110  		utils.DiscoveryPortFlag,
   111  		utils.MaxPeersFlag,
   112  		utils.MaxPendingPeersFlag,
   113  		utils.MiningEnabledFlag, // deprecated
   114  		utils.MinerGasLimitFlag,
   115  		utils.MinerGasPriceFlag,
   116  		utils.MinerEtherbaseFlag, // deprecated
   117  		utils.MinerExtraDataFlag,
   118  		utils.MinerRecommitIntervalFlag,
   119  		utils.MinerPendingFeeRecipientFlag,
   120  		utils.MinerNewPayloadTimeoutFlag, // deprecated
   121  		utils.NATFlag,
   122  		utils.NoDiscoverFlag,
   123  		utils.DiscoveryV4Flag,
   124  		utils.DiscoveryV5Flag,
   125  		utils.LegacyDiscoveryV5Flag, // deprecated
   126  		utils.NetrestrictFlag,
   127  		utils.NodeKeyFileFlag,
   128  		utils.NodeKeyHexFlag,
   129  		utils.DNSDiscoveryFlag,
   130  		utils.DeveloperFlag,
   131  		utils.DeveloperGasLimitFlag,
   132  		utils.DeveloperPeriodFlag,
   133  		utils.VMEnableDebugFlag,
   134  		utils.VMTraceFlag,
   135  		utils.VMTraceJsonConfigFlag,
   136  		utils.NetworkIdFlag,
   137  		utils.EthStatsURLFlag,
   138  		utils.GpoBlocksFlag,
   139  		utils.GpoPercentileFlag,
   140  		utils.GpoMaxGasPriceFlag,
   141  		utils.GpoIgnoreGasPriceFlag,
   142  		configFileFlag,
   143  		utils.LogDebugFlag,
   144  		utils.LogBacktraceAtFlag,
   145  		utils.BeaconApiFlag,
   146  		utils.BeaconApiHeaderFlag,
   147  		utils.BeaconThresholdFlag,
   148  		utils.BeaconNoFilterFlag,
   149  		utils.BeaconConfigFlag,
   150  		utils.BeaconGenesisRootFlag,
   151  		utils.BeaconGenesisTimeFlag,
   152  		utils.BeaconCheckpointFlag,
   153  		utils.BeaconCheckpointFileFlag,
   154  	}, utils.NetworkFlags, utils.DatabaseFlags)
   155  
   156  	rpcFlags = []cli.Flag{
   157  		utils.HTTPEnabledFlag,
   158  		utils.HTTPListenAddrFlag,
   159  		utils.HTTPPortFlag,
   160  		utils.HTTPCORSDomainFlag,
   161  		utils.AuthListenFlag,
   162  		utils.AuthPortFlag,
   163  		utils.AuthVirtualHostsFlag,
   164  		utils.JWTSecretFlag,
   165  		utils.HTTPVirtualHostsFlag,
   166  		utils.GraphQLEnabledFlag,
   167  		utils.GraphQLCORSDomainFlag,
   168  		utils.GraphQLVirtualHostsFlag,
   169  		utils.HTTPApiFlag,
   170  		utils.HTTPPathPrefixFlag,
   171  		utils.WSEnabledFlag,
   172  		utils.WSListenAddrFlag,
   173  		utils.WSPortFlag,
   174  		utils.WSApiFlag,
   175  		utils.WSAllowedOriginsFlag,
   176  		utils.WSPathPrefixFlag,
   177  		utils.IPCDisabledFlag,
   178  		utils.IPCPathFlag,
   179  		utils.InsecureUnlockAllowedFlag,
   180  		utils.RPCGlobalGasCapFlag,
   181  		utils.RPCGlobalEVMTimeoutFlag,
   182  		utils.RPCGlobalTxFeeCapFlag,
   183  		utils.AllowUnprotectedTxs,
   184  		utils.BatchRequestLimit,
   185  		utils.BatchResponseMaxSize,
   186  	}
   187  
   188  	metricsFlags = []cli.Flag{
   189  		utils.MetricsEnabledFlag,
   190  		utils.MetricsEnabledExpensiveFlag,
   191  		utils.MetricsHTTPFlag,
   192  		utils.MetricsPortFlag,
   193  		utils.MetricsEnableInfluxDBFlag,
   194  		utils.MetricsInfluxDBEndpointFlag,
   195  		utils.MetricsInfluxDBDatabaseFlag,
   196  		utils.MetricsInfluxDBUsernameFlag,
   197  		utils.MetricsInfluxDBPasswordFlag,
   198  		utils.MetricsInfluxDBTagsFlag,
   199  		utils.MetricsEnableInfluxDBV2Flag,
   200  		utils.MetricsInfluxDBTokenFlag,
   201  		utils.MetricsInfluxDBBucketFlag,
   202  		utils.MetricsInfluxDBOrganizationFlag,
   203  	}
   204  )
   205  
   206  var app = flags.NewApp("the go-ethereum command line interface")
   207  
   208  func init() {
   209  	// Initialize the CLI app and start Geth
   210  	app.Action = geth
   211  	app.Commands = []*cli.Command{
   212  		// See chaincmd.go:
   213  		initCommand,
   214  		importCommand,
   215  		exportCommand,
   216  		importHistoryCommand,
   217  		exportHistoryCommand,
   218  		importPreimagesCommand,
   219  		removedbCommand,
   220  		dumpCommand,
   221  		dumpGenesisCommand,
   222  		pruneHistoryCommand,
   223  		downloadEraCommand,
   224  		// See accountcmd.go:
   225  		accountCommand,
   226  		walletCommand,
   227  		// See consolecmd.go:
   228  		consoleCommand,
   229  		attachCommand,
   230  		javascriptCommand,
   231  		// See misccmd.go:
   232  		versionCommand,
   233  		versionCheckCommand,
   234  		licenseCommand,
   235  		// See config.go
   236  		dumpConfigCommand,
   237  		// see dbcmd.go
   238  		dbCommand,
   239  		// See cmd/utils/flags_legacy.go
   240  		utils.ShowDeprecated,
   241  		// See snapshot.go
   242  		snapshotCommand,
   243  		// See verkle.go
   244  		verkleCommand,
   245  	}
   246  	if logTestCommand != nil {
   247  		app.Commands = append(app.Commands, logTestCommand)
   248  	}
   249  	sort.Sort(cli.CommandsByName(app.Commands))
   250  
   251  	app.Flags = slices.Concat(
   252  		nodeFlags,
   253  		rpcFlags,
   254  		consoleFlags,
   255  		debug.Flags,
   256  		metricsFlags,
   257  	)
   258  	flags.AutoEnvVars(app.Flags, "GETH")
   259  
   260  	app.Before = func(ctx *cli.Context) error {
   261  		maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota.
   262  		flags.MigrateGlobalFlags(ctx)
   263  		if err := debug.Setup(ctx); err != nil {
   264  			return err
   265  		}
   266  		flags.CheckEnvVars(ctx, app.Flags, "GETH")
   267  		return nil
   268  	}
   269  	app.After = func(ctx *cli.Context) error {
   270  		debug.Exit()
   271  		prompt.Stdin.Close() // Resets terminal mode.
   272  		return nil
   273  	}
   274  }
   275  
   276  func main() {
   277  	if err := app.Run(os.Args); err != nil {
   278  		fmt.Fprintln(os.Stderr, err)
   279  		os.Exit(1)
   280  	}
   281  }
   282  
   283  // prepare manipulates memory cache allowance and setups metric system.
   284  // This function should be called before launching devp2p stack.
   285  func prepare(ctx *cli.Context) {
   286  	// If we're running a known preset, log it for convenience.
   287  	switch {
   288  	case ctx.IsSet(utils.SepoliaFlag.Name):
   289  		log.Info("Starting Geth on Sepolia testnet...")
   290  
   291  	case ctx.IsSet(utils.HoleskyFlag.Name):
   292  		log.Info("Starting Geth on Holesky testnet...")
   293  
   294  	case ctx.IsSet(utils.HoodiFlag.Name):
   295  		log.Info("Starting Geth on Hoodi testnet...")
   296  
   297  	case !ctx.IsSet(utils.NetworkIdFlag.Name):
   298  		log.Info("Starting Geth on Ethereum mainnet...")
   299  	}
   300  	// If we're a full node on mainnet without --cache specified, bump default cache allowance
   301  	if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
   302  		// Make sure we're not on any supported preconfigured testnet either
   303  		if !ctx.IsSet(utils.HoleskyFlag.Name) &&
   304  			!ctx.IsSet(utils.SepoliaFlag.Name) &&
   305  			!ctx.IsSet(utils.HoodiFlag.Name) &&
   306  			!ctx.IsSet(utils.DeveloperFlag.Name) {
   307  			// Nope, we're really on mainnet. Bump that cache up!
   308  			log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
   309  			ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096))
   310  		}
   311  	}
   312  }
   313  
   314  // geth is the main entry point into the system if no special subcommand is run.
   315  // It creates a default node based on the command line arguments and runs it in
   316  // blocking mode, waiting for it to be shut down.
   317  func geth(ctx *cli.Context) error {
   318  	if args := ctx.Args().Slice(); len(args) > 0 {
   319  		return fmt.Errorf("invalid command: %q", args[0])
   320  	}
   321  
   322  	prepare(ctx)
   323  	stack := makeFullNode(ctx)
   324  	defer stack.Close()
   325  
   326  	startNode(ctx, stack, false)
   327  	stack.Wait()
   328  	return nil
   329  }
   330  
   331  // startNode boots up the system node and all registered protocols, after which
   332  // it starts the RPC/IPC interfaces and the miner.
   333  func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
   334  	// Start up the node itself
   335  	utils.StartNode(ctx, stack, isConsole)
   336  
   337  	if ctx.IsSet(utils.UnlockedAccountFlag.Name) {
   338  		log.Warn(`The "unlock" flag has been deprecated and has no effect`)
   339  	}
   340  
   341  	// Register wallet event handlers to open and auto-derive wallets
   342  	events := make(chan accounts.WalletEvent, 16)
   343  	stack.AccountManager().Subscribe(events)
   344  
   345  	// Create a client to interact with local geth node.
   346  	rpcClient := stack.Attach()
   347  	ethClient := ethclient.NewClient(rpcClient)
   348  
   349  	go func() {
   350  		// Open any wallets already attached
   351  		for _, wallet := range stack.AccountManager().Wallets() {
   352  			if err := wallet.Open(""); err != nil {
   353  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   354  			}
   355  		}
   356  		// Listen for wallet event till termination
   357  		for event := range events {
   358  			switch event.Kind {
   359  			case accounts.WalletArrived:
   360  				if err := event.Wallet.Open(""); err != nil {
   361  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   362  				}
   363  			case accounts.WalletOpened:
   364  				status, _ := event.Wallet.Status()
   365  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   366  
   367  				var derivationPaths []accounts.DerivationPath
   368  				if event.Wallet.URL().Scheme == "ledger" {
   369  					derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath)
   370  				}
   371  				derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath)
   372  
   373  				event.Wallet.SelfDerive(derivationPaths, ethClient)
   374  
   375  			case accounts.WalletDropped:
   376  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   377  				event.Wallet.Close()
   378  			}
   379  		}
   380  	}()
   381  
   382  	// Spawn a standalone goroutine for status synchronization monitoring,
   383  	// close the node when synchronization is complete if user required.
   384  	if ctx.Bool(utils.ExitWhenSyncedFlag.Name) {
   385  		go func() {
   386  			sub := stack.EventMux().Subscribe(downloader.DoneEvent{})
   387  			defer sub.Unsubscribe()
   388  			for {
   389  				event := <-sub.Chan()
   390  				if event == nil {
   391  					continue
   392  				}
   393  				done, ok := event.Data.(downloader.DoneEvent)
   394  				if !ok {
   395  					continue
   396  				}
   397  				if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute {
   398  					log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(),
   399  						"age", common.PrettyAge(timestamp))
   400  					stack.Close()
   401  				}
   402  			}
   403  		}()
   404  	}
   405  }