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