github.com/jpmorganchase/quorum@v21.1.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/multitenancy" 46 "github.com/ethereum/go-ethereum/node" 47 "github.com/ethereum/go-ethereum/permission" 48 "github.com/ethereum/go-ethereum/plugin" 49 "gopkg.in/urfave/cli.v1" 50 ) 51 52 const ( 53 clientIdentifier = "geth" // Client identifier to advertise over the network 54 ) 55 56 var ( 57 // Git SHA1 commit hash of the release (set via linker flags) 58 gitCommit = "" 59 gitDate = "" 60 // The app that holds all commands and flags. 61 app = utils.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") 62 // flags that configure the node 63 nodeFlags = []cli.Flag{ 64 utils.IdentityFlag, 65 utils.UnlockedAccountFlag, 66 utils.PasswordFileFlag, 67 utils.BootnodesFlag, 68 utils.BootnodesV4Flag, 69 utils.BootnodesV5Flag, 70 utils.DataDirFlag, 71 utils.AncientFlag, 72 utils.KeyStoreDirFlag, 73 utils.ExternalSignerFlag, 74 utils.NoUSBFlag, 75 utils.SmartCardDaemonPathFlag, 76 utils.OverrideIstanbulFlag, 77 utils.DashboardEnabledFlag, 78 utils.DashboardAddrFlag, 79 utils.DashboardPortFlag, 80 utils.DashboardRefreshFlag, 81 utils.EthashCacheDirFlag, 82 utils.EthashCachesInMemoryFlag, 83 utils.EthashCachesOnDiskFlag, 84 utils.EthashDatasetDirFlag, 85 utils.EthashDatasetsInMemoryFlag, 86 utils.EthashDatasetsOnDiskFlag, 87 utils.TxPoolLocalsFlag, 88 utils.TxPoolNoLocalsFlag, 89 utils.TxPoolJournalFlag, 90 utils.TxPoolRejournalFlag, 91 utils.TxPoolPriceLimitFlag, 92 utils.TxPoolPriceBumpFlag, 93 utils.TxPoolAccountSlotsFlag, 94 utils.TxPoolGlobalSlotsFlag, 95 utils.TxPoolAccountQueueFlag, 96 utils.TxPoolGlobalQueueFlag, 97 utils.TxPoolLifetimeFlag, 98 utils.SyncModeFlag, 99 utils.ExitWhenSyncedFlag, 100 utils.GCModeFlag, 101 utils.LightServeFlag, 102 utils.LightLegacyServFlag, 103 utils.LightIngressFlag, 104 utils.LightEgressFlag, 105 utils.LightMaxPeersFlag, 106 utils.LightLegacyPeersFlag, 107 utils.LightKDFFlag, 108 utils.UltraLightServersFlag, 109 utils.UltraLightFractionFlag, 110 utils.UltraLightOnlyAnnounceFlag, 111 utils.WhitelistFlag, 112 utils.CacheFlag, 113 utils.CacheDatabaseFlag, 114 utils.CacheTrieFlag, 115 utils.CacheGCFlag, 116 utils.CacheNoPrefetchFlag, 117 utils.ListenPortFlag, 118 utils.MaxPeersFlag, 119 utils.MaxPendingPeersFlag, 120 utils.MiningEnabledFlag, 121 utils.MinerThreadsFlag, 122 utils.MinerLegacyThreadsFlag, 123 utils.MinerNotifyFlag, 124 utils.MinerGasTargetFlag, 125 utils.MinerLegacyGasTargetFlag, 126 utils.MinerGasLimitFlag, 127 utils.MinerGasPriceFlag, 128 utils.MinerLegacyGasPriceFlag, 129 utils.MinerEtherbaseFlag, 130 utils.MinerLegacyEtherbaseFlag, 131 utils.MinerExtraDataFlag, 132 utils.MinerLegacyExtraDataFlag, 133 utils.MinerRecommitIntervalFlag, 134 utils.MinerNoVerfiyFlag, 135 utils.NATFlag, 136 utils.NoDiscoverFlag, 137 utils.DiscoveryV5Flag, 138 utils.NetrestrictFlag, 139 utils.NodeKeyFileFlag, 140 utils.NodeKeyHexFlag, 141 utils.DeveloperFlag, 142 utils.DeveloperPeriodFlag, 143 utils.TestnetFlag, 144 utils.RinkebyFlag, 145 utils.GoerliFlag, 146 utils.VMEnableDebugFlag, 147 utils.NetworkIdFlag, 148 utils.EthStatsURLFlag, 149 utils.FakePoWFlag, 150 utils.NoCompactionFlag, 151 utils.GpoBlocksFlag, 152 utils.GpoPercentileFlag, 153 utils.EWASMInterpreterFlag, 154 utils.EVMInterpreterFlag, 155 configFileFlag, 156 // Quorum 157 utils.QuorumImmutabilityThreshold, 158 utils.EnableNodePermissionFlag, 159 utils.RaftModeFlag, 160 utils.RaftBlockTimeFlag, 161 utils.RaftJoinExistingFlag, 162 utils.RaftPortFlag, 163 utils.RaftDNSEnabledFlag, 164 utils.EmitCheckpointsFlag, 165 utils.IstanbulRequestTimeoutFlag, 166 utils.IstanbulBlockPeriodFlag, 167 utils.PluginSettingsFlag, 168 utils.PluginSkipVerifyFlag, 169 utils.PluginLocalVerifyFlag, 170 utils.PluginPublicKeyFlag, 171 utils.AllowedFutureBlockTimeFlag, 172 utils.EVMCallTimeOutFlag, 173 utils.MultitenancyFlag, 174 // End-Quorum 175 } 176 177 rpcFlags = []cli.Flag{ 178 utils.RPCEnabledFlag, 179 utils.RPCListenAddrFlag, 180 utils.RPCPortFlag, 181 utils.RPCCORSDomainFlag, 182 utils.RPCVirtualHostsFlag, 183 utils.GraphQLEnabledFlag, 184 utils.GraphQLListenAddrFlag, 185 utils.GraphQLPortFlag, 186 utils.GraphQLCORSDomainFlag, 187 utils.GraphQLVirtualHostsFlag, 188 utils.RPCApiFlag, 189 utils.WSEnabledFlag, 190 utils.WSListenAddrFlag, 191 utils.WSPortFlag, 192 utils.WSApiFlag, 193 utils.WSAllowedOriginsFlag, 194 utils.IPCDisabledFlag, 195 utils.IPCPathFlag, 196 utils.InsecureUnlockAllowedFlag, 197 utils.RPCGlobalGasCap, 198 } 199 200 whisperFlags = []cli.Flag{ 201 utils.WhisperEnabledFlag, 202 utils.WhisperMaxMessageSizeFlag, 203 utils.WhisperMinPOWFlag, 204 utils.WhisperRestrictConnectionBetweenLightClientsFlag, 205 } 206 207 metricsFlags = []cli.Flag{ 208 utils.MetricsEnabledFlag, 209 utils.MetricsEnabledExpensiveFlag, 210 utils.MetricsEnableInfluxDBFlag, 211 utils.MetricsInfluxDBEndpointFlag, 212 utils.MetricsInfluxDBDatabaseFlag, 213 utils.MetricsInfluxDBUsernameFlag, 214 utils.MetricsInfluxDBPasswordFlag, 215 utils.MetricsInfluxDBTagsFlag, 216 } 217 ) 218 219 func init() { 220 // Initialize the CLI app and start Geth 221 app.Action = geth 222 app.HideVersion = true // we have a command to print the version 223 app.Copyright = "Copyright 2013-2019 The go-ethereum Authors" 224 app.Commands = []cli.Command{ 225 // See chaincmd.go: 226 initCommand, 227 importCommand, 228 exportCommand, 229 importPreimagesCommand, 230 exportPreimagesCommand, 231 copydbCommand, 232 removedbCommand, 233 dumpCommand, 234 inspectCommand, 235 // See accountcmd.go: 236 accountCommand, 237 walletCommand, 238 // See consolecmd.go: 239 consoleCommand, 240 attachCommand, 241 javascriptCommand, 242 // See misccmd.go: 243 makecacheCommand, 244 makedagCommand, 245 versionCommand, 246 licenseCommand, 247 // See config.go 248 dumpConfigCommand, 249 // See retesteth.go 250 retestethCommand, 251 } 252 sort.Sort(cli.CommandsByName(app.Commands)) 253 254 app.Flags = append(app.Flags, nodeFlags...) 255 app.Flags = append(app.Flags, rpcFlags...) 256 app.Flags = append(app.Flags, consoleFlags...) 257 app.Flags = append(app.Flags, debug.Flags...) 258 app.Flags = append(app.Flags, whisperFlags...) 259 app.Flags = append(app.Flags, metricsFlags...) 260 261 app.Before = func(ctx *cli.Context) error { 262 logdir := "" 263 if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { 264 logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") 265 } 266 if err := debug.Setup(ctx, logdir); err != nil { 267 return err 268 } 269 return nil 270 } 271 272 app.After = func(ctx *cli.Context) error { 273 debug.Exit() 274 console.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 a full node on mainnet without --cache specified, bump default cache allowance 290 if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) { 291 // Make sure we're not on any supported preconfigured testnet either 292 if !ctx.GlobalIsSet(utils.TestnetFlag.Name) && !ctx.GlobalIsSet(utils.RinkebyFlag.Name) && !ctx.GlobalIsSet(utils.GoerliFlag.Name) && !ctx.GlobalIsSet(utils.DeveloperFlag.Name) { 293 // Nope, we're really on mainnet. Bump that cache up! 294 log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096) 295 ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096)) 296 } 297 } 298 // If we're running a light client on any network, drop the cache to some meaningfully low amount 299 if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) { 300 log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128) 301 ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128)) 302 } 303 // Cap the cache allowance and tune the garbage collector 304 var mem gosigar.Mem 305 // Workaround until OpenBSD support lands into gosigar 306 // Check https://github.com/elastic/gosigar#supported-platforms 307 if runtime.GOOS != "openbsd" { 308 if err := mem.Get(); err == nil { 309 allowance := int(mem.Total / 1024 / 1024 / 3) 310 if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance { 311 log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) 312 ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance)) 313 } 314 } 315 } 316 // Ensure Go's GC ignores the database cache for trigger percentage 317 cache := ctx.GlobalInt(utils.CacheFlag.Name) 318 gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) 319 320 log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) 321 godebug.SetGCPercent(int(gogc)) 322 323 // Start metrics export if enabled 324 utils.SetupMetrics(ctx) 325 326 // Start system runtime metrics collection 327 go metrics.CollectProcessMetrics(3 * time.Second) 328 } 329 330 // geth is the main entry point into the system if no special subcommand is ran. 331 // It creates a default node based on the command line arguments and runs it in 332 // blocking mode, waiting for it to be shut down. 333 func geth(ctx *cli.Context) error { 334 if args := ctx.Args(); len(args) > 0 { 335 return fmt.Errorf("invalid command: %q", args[0]) 336 } 337 prepare(ctx) 338 339 node := makeFullNode(ctx) 340 defer node.Close() 341 startNode(ctx, node) 342 343 node.Wait() 344 return nil 345 } 346 347 // startNode boots up the system node and all registered protocols, after which 348 // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the 349 // miner. 350 // Quorum 351 // - Enrich eth/les service with ContractAuthorizationProvider for multitenancy support if prequisites are met 352 func startNode(ctx *cli.Context, stack *node.Node) { 353 log.DoEmitCheckpoints = ctx.GlobalBool(utils.EmitCheckpointsFlag.Name) 354 debug.Memsize.Add("node", stack) 355 356 if !quorumValidatePrivateTransactionManager() { 357 utils.Fatalf("the PRIVATE_CONFIG environment variable must be specified for Quorum") 358 } 359 360 // raft mode does not support --exitwhensynced 361 if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) && ctx.GlobalBool(utils.RaftModeFlag.Name) { 362 utils.Fatalf("raft consensus does not support --exitwhensynced") 363 } 364 365 // Start up the node itself 366 utils.StartNode(stack) 367 368 // 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 369 if !ctx.IsSet(utils.ExternalSignerFlag.Name) && stack.PluginManager().IsEnabled(plugin.AccountPluginInterfaceName) { 370 b := stack.AccountManager().Backends(pluggable.BackendType)[0].(*pluggable.Backend) 371 if err := stack.PluginManager().AddAccountPluginToBackend(b); err != nil { 372 log.Error("failed to setup account plugin", "err", err) 373 } 374 } 375 376 // Unlock any account specifically requested 377 unlockAccounts(ctx, stack) 378 379 // Register wallet event handlers to open and auto-derive wallets 380 events := make(chan accounts.WalletEvent, 16) 381 stack.AccountManager().Subscribe(events) 382 383 // Create a client to interact with local geth node. 384 rpcClient, err := stack.Attach() 385 if err != nil { 386 utils.Fatalf("Failed to attach to self: %v", err) 387 } 388 ethClient := ethclient.NewClient(rpcClient) 389 390 var ethService *eth.Ethereum 391 if err := stack.Service(ðService); err != nil { 392 utils.Fatalf("Failed to retrieve ethereum service: %v", err) 393 } 394 setContractAuthzProviderFunc := ethService.SetContractAuthorizationProvider 395 // Set contract backend for ethereum service if local node 396 // is serving LES requests. 397 if ctx.GlobalInt(utils.LightLegacyServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 { 398 var ethService *eth.Ethereum 399 if err := stack.Service(ðService); err != nil { 400 utils.Fatalf("Failed to retrieve ethereum service: %v", err) 401 } 402 ethService.SetContractBackend(ethClient) 403 } 404 // Set contract backend for les service if local node is 405 // running as a light client. 406 if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { 407 var lesService *les.LightEthereum 408 if err := stack.Service(&lesService); err != nil { 409 utils.Fatalf("Failed to retrieve light ethereum service: %v", err) 410 } 411 lesService.SetContractBackend(ethClient) 412 setContractAuthzProviderFunc = lesService.SetContractAuthorizationManager 413 } 414 415 // Set ContractAuthorizationProvider if multitenancy flag is on AND plugin security is configured 416 if ctx.GlobalBool(utils.MultitenancyFlag.Name) { 417 if stack.PluginManager().IsEnabled(plugin.SecurityPluginInterfaceName) { 418 log.Info("Node supports multitenancy") 419 setContractAuthzProviderFunc(&multitenancy.DefaultContractAuthorizationProvider{}) 420 } else { 421 utils.Fatalf("multitenancy requires RPC Security Plugin to be configured") 422 } 423 } 424 425 go func() { 426 // Open any wallets already attached 427 for _, wallet := range stack.AccountManager().Wallets() { 428 if err := wallet.Open(""); err != nil { 429 log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) 430 } 431 } 432 // Listen for wallet event till termination 433 for event := range events { 434 switch event.Kind { 435 case accounts.WalletArrived: 436 if err := event.Wallet.Open(""); err != nil { 437 log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) 438 } 439 case accounts.WalletOpened: 440 status, _ := event.Wallet.Status() 441 log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) 442 443 var derivationPaths []accounts.DerivationPath 444 if event.Wallet.URL().Scheme == "ledger" { 445 derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath) 446 } 447 derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath) 448 449 event.Wallet.SelfDerive(derivationPaths, ethClient) 450 451 case accounts.WalletDropped: 452 log.Info("Old wallet dropped", "url", event.Wallet.URL()) 453 event.Wallet.Close() 454 } 455 } 456 }() 457 458 // Spawn a standalone goroutine for status synchronization monitoring, 459 // close the node when synchronization is complete if user required. 460 if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) { 461 go func() { 462 sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) 463 defer sub.Unsubscribe() 464 for { 465 event := <-sub.Chan() 466 if event == nil { 467 continue 468 } 469 done, ok := event.Data.(downloader.DoneEvent) 470 if !ok { 471 continue 472 } 473 if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute { 474 log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(), 475 "age", common.PrettyAge(timestamp)) 476 stack.Stop() 477 } 478 } 479 }() 480 } 481 482 // Quorum 483 // 484 // checking if permissions is enabled and staring the permissions service 485 if stack.Config().EnableNodePermission { 486 stack.Server().SetIsNodePermissioned(permission.IsNodePermissioned) 487 if stack.IsPermissionEnabled() { 488 var permissionService *permission.PermissionCtrl 489 if err := stack.Service(&permissionService); err != nil { 490 utils.Fatalf("Permission service not runnning: %v", err) 491 } 492 if err := permissionService.AfterStart(); err != nil { 493 utils.Fatalf("Permission service post construct failure: %v", err) 494 } 495 } 496 } 497 498 // Start auxiliary services if enabled 499 if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { 500 // Mining only makes sense if a full Ethereum node is running 501 if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { 502 utils.Fatalf("Light clients do not support mining") 503 } 504 var ethereum *eth.Ethereum 505 if err := stack.Service(ðereum); err != nil { 506 utils.Fatalf("Ethereum service not running: %v", err) 507 } 508 // Set the gas price to the limits from the CLI and start mining 509 gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name) 510 if ctx.IsSet(utils.MinerGasPriceFlag.Name) { 511 gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) 512 } 513 ethereum.TxPool().SetGasPrice(gasprice) 514 515 threads := ctx.GlobalInt(utils.MinerLegacyThreadsFlag.Name) 516 if ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) { 517 threads = ctx.GlobalInt(utils.MinerThreadsFlag.Name) 518 } 519 if err := ethereum.StartMining(threads); err != nil { 520 utils.Fatalf("Failed to start mining: %v", err) 521 } 522 } 523 524 // checks quorum features that depend on the ethereum service 525 quorumValidateEthService(stack, ctx.GlobalBool(utils.RaftModeFlag.Name)) 526 } 527 528 // unlockAccounts unlocks any account specifically requested. 529 func unlockAccounts(ctx *cli.Context, stack *node.Node) { 530 var unlocks []string 531 inputs := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") 532 for _, input := range inputs { 533 if trimmed := strings.TrimSpace(input); trimmed != "" { 534 unlocks = append(unlocks, trimmed) 535 } 536 } 537 // Short circuit if there is no account to unlock. 538 if len(unlocks) == 0 { 539 return 540 } 541 // If insecure account unlocking is not allowed if node's APIs are exposed to external. 542 // Print warning log to user and skip unlocking. 543 if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { 544 utils.Fatalf("Account unlock with HTTP access is forbidden!") 545 } 546 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 547 passwords := utils.MakePasswordList(ctx) 548 for i, account := range unlocks { 549 unlockAccount(ks, account, i, passwords) 550 } 551 }