github.com/theQRL/go-zond@v0.2.1/cmd/gzond/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 // gzond is the official command-line client for Zond. 18 package main 19 20 import ( 21 "fmt" 22 "os" 23 "sort" 24 "strconv" 25 "strings" 26 "time" 27 28 "github.com/theQRL/go-zond/accounts" 29 "github.com/theQRL/go-zond/accounts/keystore" 30 "github.com/theQRL/go-zond/cmd/utils" 31 "github.com/theQRL/go-zond/common" 32 "github.com/theQRL/go-zond/console/prompt" 33 "github.com/theQRL/go-zond/internal/debug" 34 "github.com/theQRL/go-zond/internal/flags" 35 "github.com/theQRL/go-zond/log" 36 "github.com/theQRL/go-zond/metrics" 37 "github.com/theQRL/go-zond/node" 38 "github.com/theQRL/go-zond/zond/downloader" 39 "github.com/theQRL/go-zond/zondclient" 40 41 // Force-load the tracer engines to trigger registration 42 _ "github.com/theQRL/go-zond/zond/tracers/js" 43 _ "github.com/theQRL/go-zond/zond/tracers/native" 44 "go.uber.org/automaxprocs/maxprocs" 45 46 "github.com/urfave/cli/v2" 47 ) 48 49 const ( 50 clientIdentifier = "gzond" // Client identifier to advertise over the network 51 ) 52 53 var ( 54 // flags that configure the node 55 nodeFlags = flags.Merge([]cli.Flag{ 56 utils.IdentityFlag, 57 utils.UnlockedAccountFlag, 58 utils.PasswordFileFlag, 59 utils.BootnodesFlag, 60 utils.MinFreeDiskSpaceFlag, 61 utils.KeyStoreDirFlag, 62 utils.ExternalSignerFlag, 63 // TODO(now.youtrack.cloud/issue/TGZ-4) 64 // utils.USBFlag, 65 // TODO(now.youtrack.cloud/issue/TGZ-1) 66 // utils.SmartCardDaemonPathFlag, 67 utils.TxPoolLocalsFlag, 68 utils.TxPoolNoLocalsFlag, 69 utils.TxPoolJournalFlag, 70 utils.TxPoolRejournalFlag, 71 utils.TxPoolPriceLimitFlag, 72 utils.TxPoolPriceBumpFlag, 73 utils.TxPoolAccountSlotsFlag, 74 utils.TxPoolGlobalSlotsFlag, 75 utils.TxPoolAccountQueueFlag, 76 utils.TxPoolGlobalQueueFlag, 77 utils.TxPoolLifetimeFlag, 78 utils.SyncModeFlag, 79 utils.SyncTargetFlag, 80 utils.ExitWhenSyncedFlag, 81 utils.GCModeFlag, 82 utils.SnapshotFlag, 83 utils.TransactionHistoryFlag, 84 utils.StateSchemeFlag, 85 utils.StateHistoryFlag, 86 utils.LightKDFFlag, 87 utils.ZondRequiredBlocksFlag, 88 utils.BloomFilterSizeFlag, 89 utils.CacheFlag, 90 utils.CacheDatabaseFlag, 91 utils.CacheTrieFlag, 92 utils.CacheGCFlag, 93 utils.CacheSnapshotFlag, 94 utils.CacheNoPrefetchFlag, 95 utils.CachePreimagesFlag, 96 utils.CacheLogSizeFlag, 97 utils.FDLimitFlag, 98 utils.ListenPortFlag, 99 utils.DiscoveryPortFlag, 100 utils.MaxPeersFlag, 101 utils.MaxPendingPeersFlag, 102 utils.MinerGasLimitFlag, 103 utils.MinerGasPriceFlag, 104 utils.MinerExtraDataFlag, 105 utils.MinerRecommitIntervalFlag, 106 utils.MinerPendingFeeRecipientFlag, 107 utils.NATFlag, 108 utils.NoDiscoverFlag, 109 utils.DiscoveryV4Flag, 110 utils.DiscoveryV5Flag, 111 utils.NetrestrictFlag, 112 utils.NodeKeyFileFlag, 113 utils.NodeKeyHexFlag, 114 utils.DNSDiscoveryFlag, 115 utils.DeveloperFlag, 116 utils.DeveloperGasLimitFlag, 117 utils.DeveloperPeriodFlag, 118 utils.VMEnableDebugFlag, 119 utils.NetworkIdFlag, 120 utils.ZondStatsURLFlag, 121 utils.NoCompactionFlag, 122 utils.GpoBlocksFlag, 123 utils.GpoPercentileFlag, 124 utils.GpoMaxGasPriceFlag, 125 utils.GpoIgnoreGasPriceFlag, 126 configFileFlag, 127 }, utils.NetworkFlags, utils.DatabasePathFlags) 128 129 rpcFlags = []cli.Flag{ 130 utils.HTTPEnabledFlag, 131 utils.HTTPListenAddrFlag, 132 utils.HTTPPortFlag, 133 utils.HTTPCORSDomainFlag, 134 utils.AuthListenFlag, 135 utils.AuthPortFlag, 136 utils.AuthVirtualHostsFlag, 137 utils.JWTSecretFlag, 138 utils.HTTPVirtualHostsFlag, 139 utils.GraphQLEnabledFlag, 140 utils.GraphQLCORSDomainFlag, 141 utils.GraphQLVirtualHostsFlag, 142 utils.HTTPApiFlag, 143 utils.HTTPPathPrefixFlag, 144 utils.WSEnabledFlag, 145 utils.WSListenAddrFlag, 146 utils.WSPortFlag, 147 utils.WSApiFlag, 148 utils.WSAllowedOriginsFlag, 149 utils.WSPathPrefixFlag, 150 utils.IPCDisabledFlag, 151 utils.IPCPathFlag, 152 utils.InsecureUnlockAllowedFlag, 153 utils.RPCGlobalGasCapFlag, 154 utils.RPCGlobalZVMTimeoutFlag, 155 utils.RPCGlobalTxFeeCapFlag, 156 utils.BatchRequestLimit, 157 utils.BatchResponseMaxSize, 158 } 159 160 metricsFlags = []cli.Flag{ 161 utils.MetricsEnabledFlag, 162 utils.MetricsEnabledExpensiveFlag, 163 utils.MetricsHTTPFlag, 164 utils.MetricsPortFlag, 165 utils.MetricsEnableInfluxDBFlag, 166 utils.MetricsInfluxDBEndpointFlag, 167 utils.MetricsInfluxDBDatabaseFlag, 168 utils.MetricsInfluxDBUsernameFlag, 169 utils.MetricsInfluxDBPasswordFlag, 170 utils.MetricsInfluxDBTagsFlag, 171 utils.MetricsEnableInfluxDBV2Flag, 172 utils.MetricsInfluxDBTokenFlag, 173 utils.MetricsInfluxDBBucketFlag, 174 utils.MetricsInfluxDBOrganizationFlag, 175 } 176 ) 177 178 var app = flags.NewApp("the go-zond command line interface") 179 180 func init() { 181 // Initialize the CLI app and start Gzond 182 app.Action = gzond 183 app.Copyright = "Copyright 2013-2023 The go-zond Authors" 184 app.Commands = []*cli.Command{ 185 // See chaincmd.go: 186 initCommand, 187 importCommand, 188 exportCommand, 189 removedbCommand, 190 dumpCommand, 191 dumpGenesisCommand, 192 // See accountcmd.go: 193 accountCommand, 194 // See consolecmd.go: 195 consoleCommand, 196 attachCommand, 197 // See misccmd.go: 198 versionCommand, 199 versionCheckCommand, 200 licenseCommand, 201 // See config.go 202 dumpConfigCommand, 203 // see dbcmd.go 204 dbCommand, 205 // See cmd/utils/flags_legacy.go 206 utils.ShowDeprecated, 207 // See snapshot.go 208 snapshotCommand, 209 } 210 sort.Sort(cli.CommandsByName(app.Commands)) 211 212 app.Flags = flags.Merge( 213 nodeFlags, 214 rpcFlags, 215 consoleFlags, 216 debug.Flags, 217 metricsFlags, 218 ) 219 flags.AutoEnvVars(app.Flags, "GZOND") 220 221 app.Before = func(ctx *cli.Context) error { 222 maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota. 223 flags.MigrateGlobalFlags(ctx) 224 if err := debug.Setup(ctx); err != nil { 225 return err 226 } 227 flags.CheckEnvVars(ctx, app.Flags, "GZOND") 228 return nil 229 } 230 app.After = func(ctx *cli.Context) error { 231 debug.Exit() 232 prompt.Stdin.Close() // Resets terminal mode. 233 return nil 234 } 235 } 236 237 func main() { 238 if err := app.Run(os.Args); err != nil { 239 fmt.Fprintln(os.Stderr, err) 240 os.Exit(1) 241 } 242 } 243 244 // prepare manipulates memory cache allowance and setups metric system. 245 // This function should be called before launching devp2p stack. 246 func prepare(ctx *cli.Context) { 247 // If we're running a known preset, log it for convenience. 248 switch { 249 case ctx.IsSet(utils.BetaNetFlag.Name): 250 log.Info("Starting Gzond on BetaNet testnet...") 251 252 case ctx.IsSet(utils.TestnetFlag.Name): 253 log.Info("Starting Gzond on Testnet 1...") 254 255 case ctx.IsSet(utils.DeveloperFlag.Name): 256 log.Info("Starting Gzond in ephemeral dev mode...") 257 log.Warn(`You are running Gzond in --dev mode. Please note the following: 258 259 1. This mode is only intended for fast, iterative development without assumptions on 260 security or persistence. 261 2. The database is created in memory unless specified otherwise. Therefore, shutting down 262 your computer or losing power will wipe your entire block data and chain state for 263 your dev environment. 264 3. A random, pre-allocated developer account will be available and unlocked as 265 zond.coinbase, which can be used for testing. The random dev account is temporary, 266 stored on a ramdisk, and will be lost if your machine is restarted. 267 4. Mining is enabled by default. However, the client will only seal blocks if transactions 268 are pending in the mempool. The miner's minimum accepted gas price is 1. 269 5. Networking is disabled; there is no listen-address, the maximum number of peers is set 270 to 0, and discovery is disabled. 271 `) 272 273 case !ctx.IsSet(utils.NetworkIdFlag.Name): 274 log.Info("Starting Gzond on Zond mainnet...") 275 } 276 // If we're a full node on mainnet without --cache specified, bump default cache allowance 277 if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { 278 // Make sure we're not on any supported preconfigured testnet either 279 if !ctx.IsSet(utils.DeveloperFlag.Name) { 280 // Nope, we're really on mainnet. Bump that cache up! 281 log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096) 282 ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096)) 283 } 284 } 285 286 // Start metrics export if enabled 287 utils.SetupMetrics(ctx) 288 289 // Start system runtime metrics collection 290 go metrics.CollectProcessMetrics(3 * time.Second) 291 } 292 293 // gzond is the main entry point into the system if no special subcommand is run. 294 // It creates a default node based on the command line arguments and runs it in 295 // blocking mode, waiting for it to be shut down. 296 func gzond(ctx *cli.Context) error { 297 if args := ctx.Args().Slice(); len(args) > 0 { 298 return fmt.Errorf("invalid command: %q", args[0]) 299 } 300 301 prepare(ctx) 302 stack, _ := makeFullNode(ctx) 303 defer stack.Close() 304 305 startNode(ctx, stack, false) 306 stack.Wait() 307 return nil 308 } 309 310 // startNode boots up the system node and all registered protocols, after which 311 // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the 312 // miner. 313 func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) { 314 // Start up the node itself 315 utils.StartNode(ctx, stack, isConsole) 316 317 // Unlock any account specifically requested 318 unlockAccounts(ctx, stack) 319 320 // Register wallet event handlers to open and auto-derive wallets 321 events := make(chan accounts.WalletEvent, 16) 322 stack.AccountManager().Subscribe(events) 323 324 // Create a client to interact with local gzond node. 325 rpcClient := stack.Attach() 326 zondClient := zondclient.NewClient(rpcClient) 327 328 go func() { 329 // Open any wallets already attached 330 for _, wallet := range stack.AccountManager().Wallets() { 331 if err := wallet.Open(""); err != nil { 332 log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) 333 } 334 } 335 // Listen for wallet event till termination 336 for event := range events { 337 switch event.Kind { 338 case accounts.WalletArrived: 339 if err := event.Wallet.Open(""); err != nil { 340 log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) 341 } 342 case accounts.WalletOpened: 343 status, _ := event.Wallet.Status() 344 log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) 345 346 var derivationPaths []accounts.DerivationPath 347 if event.Wallet.URL().Scheme == "ledger" { 348 derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath) 349 } 350 derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath) 351 352 event.Wallet.SelfDerive(derivationPaths, zondClient) 353 354 case accounts.WalletDropped: 355 log.Info("Old wallet dropped", "url", event.Wallet.URL()) 356 event.Wallet.Close() 357 } 358 } 359 }() 360 361 // Spawn a standalone goroutine for status synchronization monitoring, 362 // close the node when synchronization is complete if user required. 363 if ctx.Bool(utils.ExitWhenSyncedFlag.Name) { 364 go func() { 365 sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) 366 defer sub.Unsubscribe() 367 for { 368 event := <-sub.Chan() 369 if event == nil { 370 continue 371 } 372 done, ok := event.Data.(downloader.DoneEvent) 373 if !ok { 374 continue 375 } 376 if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute { 377 log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(), 378 "age", common.PrettyAge(timestamp)) 379 stack.Close() 380 } 381 } 382 }() 383 } 384 } 385 386 // unlockAccounts unlocks any account specifically requested. 387 func unlockAccounts(ctx *cli.Context, stack *node.Node) { 388 var unlocks []string 389 inputs := strings.Split(ctx.String(utils.UnlockedAccountFlag.Name), ",") 390 for _, input := range inputs { 391 if trimmed := strings.TrimSpace(input); trimmed != "" { 392 unlocks = append(unlocks, trimmed) 393 } 394 } 395 // Short circuit if there is no account to unlock. 396 if len(unlocks) == 0 { 397 return 398 } 399 // If insecure account unlocking is not allowed if node's APIs are exposed to external. 400 // Print warning log to user and skip unlocking. 401 if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { 402 utils.Fatalf("Account unlock with HTTP access is forbidden!") 403 } 404 backends := stack.AccountManager().Backends(keystore.KeyStoreType) 405 if len(backends) == 0 { 406 log.Warn("Failed to unlock accounts, keystore is not available") 407 return 408 } 409 ks := backends[0].(*keystore.KeyStore) 410 passwords := utils.MakePasswordList(ctx) 411 for i, account := range unlocks { 412 unlockAccount(ks, account, i, passwords) 413 } 414 }