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 }