github.com/ConsenSys/Quorum@v20.10.0+incompatible/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/accounts/pluggable" 35 "github.com/ethereum/go-ethereum/cmd/utils" 36 "github.com/ethereum/go-ethereum/common" 37 "github.com/ethereum/go-ethereum/console" 38 "github.com/ethereum/go-ethereum/eth" 39 "github.com/ethereum/go-ethereum/eth/downloader" 40 "github.com/ethereum/go-ethereum/ethclient" 41 "github.com/ethereum/go-ethereum/internal/debug" 42 "github.com/ethereum/go-ethereum/les" 43 "github.com/ethereum/go-ethereum/log" 44 "github.com/ethereum/go-ethereum/metrics" 45 "github.com/ethereum/go-ethereum/node" 46 "github.com/ethereum/go-ethereum/permission" 47 "github.com/ethereum/go-ethereum/plugin" 48 "gopkg.in/urfave/cli.v1" 49 ) 50 51 const ( 52 clientIdentifier = "geth" // Client identifier to advertise over the network 53 ) 54 55 var ( 56 // Git SHA1 commit hash of the release (set via linker flags) 57 gitCommit = "" 58 gitDate = "" 59 // The app that holds all commands and flags. 60 app = utils.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") 61 // flags that configure the node 62 nodeFlags = []cli.Flag{ 63 utils.IdentityFlag, 64 utils.UnlockedAccountFlag, 65 utils.PasswordFileFlag, 66 utils.BootnodesFlag, 67 utils.BootnodesV4Flag, 68 utils.BootnodesV5Flag, 69 utils.DataDirFlag, 70 utils.AncientFlag, 71 utils.KeyStoreDirFlag, 72 utils.ExternalSignerFlag, 73 utils.NoUSBFlag, 74 utils.SmartCardDaemonPathFlag, 75 utils.OverrideIstanbulFlag, 76 utils.DashboardEnabledFlag, 77 utils.DashboardAddrFlag, 78 utils.DashboardPortFlag, 79 utils.DashboardRefreshFlag, 80 utils.EthashCacheDirFlag, 81 utils.EthashCachesInMemoryFlag, 82 utils.EthashCachesOnDiskFlag, 83 utils.EthashDatasetDirFlag, 84 utils.EthashDatasetsInMemoryFlag, 85 utils.EthashDatasetsOnDiskFlag, 86 utils.TxPoolLocalsFlag, 87 utils.TxPoolNoLocalsFlag, 88 utils.TxPoolJournalFlag, 89 utils.TxPoolRejournalFlag, 90 utils.TxPoolPriceLimitFlag, 91 utils.TxPoolPriceBumpFlag, 92 utils.TxPoolAccountSlotsFlag, 93 utils.TxPoolGlobalSlotsFlag, 94 utils.TxPoolAccountQueueFlag, 95 utils.TxPoolGlobalQueueFlag, 96 utils.TxPoolLifetimeFlag, 97 utils.SyncModeFlag, 98 utils.ExitWhenSyncedFlag, 99 utils.GCModeFlag, 100 utils.LightServeFlag, 101 utils.LightLegacyServFlag, 102 utils.LightIngressFlag, 103 utils.LightEgressFlag, 104 utils.LightMaxPeersFlag, 105 utils.LightLegacyPeersFlag, 106 utils.LightKDFFlag, 107 utils.UltraLightServersFlag, 108 utils.UltraLightFractionFlag, 109 utils.UltraLightOnlyAnnounceFlag, 110 utils.WhitelistFlag, 111 utils.CacheFlag, 112 utils.CacheDatabaseFlag, 113 utils.CacheTrieFlag, 114 utils.CacheGCFlag, 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.DeveloperFlag, 141 utils.DeveloperPeriodFlag, 142 utils.TestnetFlag, 143 utils.RinkebyFlag, 144 utils.GoerliFlag, 145 utils.VMEnableDebugFlag, 146 utils.NetworkIdFlag, 147 utils.EthStatsURLFlag, 148 utils.FakePoWFlag, 149 utils.NoCompactionFlag, 150 utils.GpoBlocksFlag, 151 utils.GpoPercentileFlag, 152 utils.EWASMInterpreterFlag, 153 utils.EVMInterpreterFlag, 154 configFileFlag, 155 // Quorum 156 utils.QuorumImmutabilityThreshold, 157 utils.EnableNodePermissionFlag, 158 utils.RaftModeFlag, 159 utils.RaftBlockTimeFlag, 160 utils.RaftJoinExistingFlag, 161 utils.RaftPortFlag, 162 utils.RaftDNSEnabledFlag, 163 utils.EmitCheckpointsFlag, 164 utils.IstanbulRequestTimeoutFlag, 165 utils.IstanbulBlockPeriodFlag, 166 utils.PluginSettingsFlag, 167 utils.PluginSkipVerifyFlag, 168 utils.PluginLocalVerifyFlag, 169 utils.PluginPublicKeyFlag, 170 utils.AllowedFutureBlockTimeFlag, 171 utils.EVMCallTimeOutFlag, 172 // End-Quorum 173 } 174 175 rpcFlags = []cli.Flag{ 176 utils.RPCEnabledFlag, 177 utils.RPCListenAddrFlag, 178 utils.RPCPortFlag, 179 utils.RPCCORSDomainFlag, 180 utils.RPCVirtualHostsFlag, 181 utils.GraphQLEnabledFlag, 182 utils.GraphQLListenAddrFlag, 183 utils.GraphQLPortFlag, 184 utils.GraphQLCORSDomainFlag, 185 utils.GraphQLVirtualHostsFlag, 186 utils.RPCApiFlag, 187 utils.WSEnabledFlag, 188 utils.WSListenAddrFlag, 189 utils.WSPortFlag, 190 utils.WSApiFlag, 191 utils.WSAllowedOriginsFlag, 192 utils.IPCDisabledFlag, 193 utils.IPCPathFlag, 194 utils.InsecureUnlockAllowedFlag, 195 utils.RPCGlobalGasCap, 196 } 197 198 whisperFlags = []cli.Flag{ 199 utils.WhisperEnabledFlag, 200 utils.WhisperMaxMessageSizeFlag, 201 utils.WhisperMinPOWFlag, 202 utils.WhisperRestrictConnectionBetweenLightClientsFlag, 203 } 204 205 metricsFlags = []cli.Flag{ 206 utils.MetricsEnabledFlag, 207 utils.MetricsEnabledExpensiveFlag, 208 utils.MetricsEnableInfluxDBFlag, 209 utils.MetricsInfluxDBEndpointFlag, 210 utils.MetricsInfluxDBDatabaseFlag, 211 utils.MetricsInfluxDBUsernameFlag, 212 utils.MetricsInfluxDBPasswordFlag, 213 utils.MetricsInfluxDBTagsFlag, 214 } 215 ) 216 217 func init() { 218 // Initialize the CLI app and start Geth 219 app.Action = geth 220 app.HideVersion = true // we have a command to print the version 221 app.Copyright = "Copyright 2013-2019 The go-ethereum Authors" 222 app.Commands = []cli.Command{ 223 // See chaincmd.go: 224 initCommand, 225 importCommand, 226 exportCommand, 227 importPreimagesCommand, 228 exportPreimagesCommand, 229 copydbCommand, 230 removedbCommand, 231 dumpCommand, 232 inspectCommand, 233 // See accountcmd.go: 234 accountCommand, 235 walletCommand, 236 // See consolecmd.go: 237 consoleCommand, 238 attachCommand, 239 javascriptCommand, 240 // See misccmd.go: 241 makecacheCommand, 242 makedagCommand, 243 versionCommand, 244 licenseCommand, 245 // See config.go 246 dumpConfigCommand, 247 // See retesteth.go 248 retestethCommand, 249 } 250 sort.Sort(cli.CommandsByName(app.Commands)) 251 252 app.Flags = append(app.Flags, nodeFlags...) 253 app.Flags = append(app.Flags, rpcFlags...) 254 app.Flags = append(app.Flags, consoleFlags...) 255 app.Flags = append(app.Flags, debug.Flags...) 256 app.Flags = append(app.Flags, whisperFlags...) 257 app.Flags = append(app.Flags, metricsFlags...) 258 259 app.Before = func(ctx *cli.Context) error { 260 logdir := "" 261 if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { 262 logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") 263 } 264 if err := debug.Setup(ctx, logdir); err != nil { 265 return err 266 } 267 return nil 268 } 269 270 app.After = func(ctx *cli.Context) error { 271 debug.Exit() 272 console.Stdin.Close() // Resets terminal mode. 273 return nil 274 } 275 } 276 277 func main() { 278 if err := app.Run(os.Args); err != nil { 279 fmt.Fprintln(os.Stderr, err) 280 os.Exit(1) 281 } 282 } 283 284 // prepare manipulates memory cache allowance and setups metric system. 285 // This function should be called before launching devp2p stack. 286 func prepare(ctx *cli.Context) { 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.TestnetFlag.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 337 node := makeFullNode(ctx) 338 defer node.Close() 339 startNode(ctx, node) 340 341 node.Wait() 342 return nil 343 } 344 345 // startNode boots up the system node and all registered protocols, after which 346 // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the 347 // miner. 348 func startNode(ctx *cli.Context, stack *node.Node) { 349 log.DoEmitCheckpoints = ctx.GlobalBool(utils.EmitCheckpointsFlag.Name) 350 debug.Memsize.Add("node", stack) 351 352 if !quorumValidatePrivateTransactionManager() { 353 utils.Fatalf("the PRIVATE_CONFIG environment variable must be specified for Quorum") 354 } 355 356 // raft mode does not support --exitwhensynced 357 if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) && ctx.GlobalBool(utils.RaftModeFlag.Name) { 358 utils.Fatalf("raft consensus does not support --exitwhensynced") 359 } 360 361 // Start up the node itself 362 utils.StartNode(stack) 363 364 // Now that the plugin manager has been started we register the account plugin with the corresponding account backend. All other account management is disabled when using External Signer 365 if !ctx.IsSet(utils.ExternalSignerFlag.Name) && stack.PluginManager().IsEnabled(plugin.AccountPluginInterfaceName) { 366 b := stack.AccountManager().Backends(pluggable.BackendType)[0].(*pluggable.Backend) 367 if err := stack.PluginManager().AddAccountPluginToBackend(b); err != nil { 368 log.Error("failed to setup account plugin", "err", err) 369 } 370 } 371 372 // Unlock any account specifically requested 373 unlockAccounts(ctx, stack) 374 375 // Register wallet event handlers to open and auto-derive wallets 376 events := make(chan accounts.WalletEvent, 16) 377 stack.AccountManager().Subscribe(events) 378 379 // Create a client to interact with local geth node. 380 rpcClient, err := stack.Attach() 381 if err != nil { 382 utils.Fatalf("Failed to attach to self: %v", err) 383 } 384 ethClient := ethclient.NewClient(rpcClient) 385 386 // Set contract backend for ethereum service if local node 387 // is serving LES requests. 388 if ctx.GlobalInt(utils.LightLegacyServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 { 389 var ethService *eth.Ethereum 390 if err := stack.Service(ðService); err != nil { 391 utils.Fatalf("Failed to retrieve ethereum service: %v", err) 392 } 393 ethService.SetContractBackend(ethClient) 394 } 395 // Set contract backend for les service if local node is 396 // running as a light client. 397 if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { 398 var lesService *les.LightEthereum 399 if err := stack.Service(&lesService); err != nil { 400 utils.Fatalf("Failed to retrieve light ethereum service: %v", err) 401 } 402 lesService.SetContractBackend(ethClient) 403 } 404 405 go func() { 406 // Open any wallets already attached 407 for _, wallet := range stack.AccountManager().Wallets() { 408 if err := wallet.Open(""); err != nil { 409 log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) 410 } 411 } 412 // Listen for wallet event till termination 413 for event := range events { 414 switch event.Kind { 415 case accounts.WalletArrived: 416 if err := event.Wallet.Open(""); err != nil { 417 log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) 418 } 419 case accounts.WalletOpened: 420 status, _ := event.Wallet.Status() 421 log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) 422 423 var derivationPaths []accounts.DerivationPath 424 if event.Wallet.URL().Scheme == "ledger" { 425 derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath) 426 } 427 derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath) 428 429 event.Wallet.SelfDerive(derivationPaths, ethClient) 430 431 case accounts.WalletDropped: 432 log.Info("Old wallet dropped", "url", event.Wallet.URL()) 433 event.Wallet.Close() 434 } 435 } 436 }() 437 438 // Spawn a standalone goroutine for status synchronization monitoring, 439 // close the node when synchronization is complete if user required. 440 if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) { 441 go func() { 442 sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) 443 defer sub.Unsubscribe() 444 for { 445 event := <-sub.Chan() 446 if event == nil { 447 continue 448 } 449 done, ok := event.Data.(downloader.DoneEvent) 450 if !ok { 451 continue 452 } 453 if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute { 454 log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(), 455 "age", common.PrettyAge(timestamp)) 456 stack.Stop() 457 } 458 } 459 }() 460 } 461 462 // Quorum 463 // 464 // checking if permissions is enabled and staring the permissions service 465 if stack.IsPermissionEnabled() { 466 var permissionService *permission.PermissionCtrl 467 if err := stack.Service(&permissionService); err != nil { 468 utils.Fatalf("Permission service not runnning: %v", err) 469 } 470 if err := permissionService.AfterStart(); err != nil { 471 utils.Fatalf("Permission service post construct failure: %v", err) 472 } 473 } 474 475 // Start auxiliary services if enabled 476 if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { 477 // Mining only makes sense if a full Ethereum node is running 478 if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { 479 utils.Fatalf("Light clients do not support mining") 480 } 481 var ethereum *eth.Ethereum 482 if err := stack.Service(ðereum); err != nil { 483 utils.Fatalf("Ethereum service not running: %v", err) 484 } 485 // Set the gas price to the limits from the CLI and start mining 486 gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name) 487 if ctx.IsSet(utils.MinerGasPriceFlag.Name) { 488 gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) 489 } 490 ethereum.TxPool().SetGasPrice(gasprice) 491 492 threads := ctx.GlobalInt(utils.MinerLegacyThreadsFlag.Name) 493 if ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) { 494 threads = ctx.GlobalInt(utils.MinerThreadsFlag.Name) 495 } 496 if err := ethereum.StartMining(threads); err != nil { 497 utils.Fatalf("Failed to start mining: %v", err) 498 } 499 } 500 501 // checks quorum features that depend on the ethereum service 502 quorumValidateEthService(stack, ctx.GlobalBool(utils.RaftModeFlag.Name)) 503 } 504 505 // unlockAccounts unlocks any account specifically requested. 506 func unlockAccounts(ctx *cli.Context, stack *node.Node) { 507 var unlocks []string 508 inputs := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") 509 for _, input := range inputs { 510 if trimmed := strings.TrimSpace(input); trimmed != "" { 511 unlocks = append(unlocks, trimmed) 512 } 513 } 514 // Short circuit if there is no account to unlock. 515 if len(unlocks) == 0 { 516 return 517 } 518 // If insecure account unlocking is not allowed if node's APIs are exposed to external. 519 // Print warning log to user and skip unlocking. 520 if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { 521 utils.Fatalf("Account unlock with HTTP access is forbidden!") 522 } 523 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 524 passwords := utils.MakePasswordList(ctx) 525 for i, account := range unlocks { 526 unlockAccount(ks, account, i, passwords) 527 } 528 }