github.com/XinFinOrg/xdcchain@v1.1.0/cmd/XDC/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 package main 18 19 import ( 20 "fmt" 21 "math" 22 "os" 23 godebug "runtime/debug" 24 "sort" 25 "strconv" 26 "strings" 27 "time" 28 29 "github.com/elastic/gosigar" 30 "github.com/ethereum/go-ethereum/accounts" 31 "github.com/ethereum/go-ethereum/accounts/keystore" 32 "github.com/ethereum/go-ethereum/cmd/utils" 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/consensus/XDPoS" 35 "github.com/ethereum/go-ethereum/console" 36 "github.com/ethereum/go-ethereum/core" 37 "github.com/ethereum/go-ethereum/eth" 38 "github.com/ethereum/go-ethereum/ethclient" 39 "github.com/ethereum/go-ethereum/internal/debug" 40 "github.com/ethereum/go-ethereum/log" 41 "github.com/ethereum/go-ethereum/metrics" 42 "github.com/ethereum/go-ethereum/node" 43 cli "gopkg.in/urfave/cli.v1" 44 ) 45 46 const ( 47 clientIdentifier = "XDC" // Client identifier to advertise over the network 48 ) 49 50 var ( 51 // Git SHA1 commit hash of the release (set via linker flags) 52 gitCommit = "" 53 // The app that holds all commands and flags. 54 app = utils.NewApp(gitCommit, "the XDCchain command line interface") 55 // flags that configure the node 56 nodeFlags = []cli.Flag{ 57 utils.IdentityFlag, 58 utils.UnlockedAccountFlag, 59 utils.PasswordFileFlag, 60 utils.BootnodesFlag, 61 utils.BootnodesV4Flag, 62 utils.BootnodesV5Flag, 63 utils.DataDirFlag, 64 utils.KeyStoreDirFlag, 65 //utils.NoUSBFlag, 66 //utils.DashboardEnabledFlag, 67 //utils.DashboardAddrFlag, 68 //utils.DashboardPortFlag, 69 //utils.DashboardRefreshFlag, 70 //utils.EthashCacheDirFlag, 71 //utils.EthashCachesInMemoryFlag, 72 //utils.EthashCachesOnDiskFlag, 73 //utils.EthashDatasetDirFlag, 74 //utils.EthashDatasetsInMemoryFlag, 75 //utils.EthashDatasetsOnDiskFlag, 76 utils.TxPoolLocalsFlag, 77 utils.TxPoolNoLocalsFlag, 78 utils.TxPoolJournalFlag, 79 utils.TxPoolRejournalFlag, 80 utils.TxPoolPriceLimitFlag, 81 utils.TxPoolPriceBumpFlag, 82 utils.TxPoolAccountSlotsFlag, 83 utils.TxPoolGlobalSlotsFlag, 84 utils.TxPoolAccountQueueFlag, 85 utils.TxPoolGlobalQueueFlag, 86 utils.TxPoolLifetimeFlag, 87 utils.SyncModeFlag, 88 utils.GCModeFlag, 89 //utils.LightServFlag, 90 //utils.LightPeersFlag, 91 //utils.LightKDFFlag, 92 utils.WhitelistFlag, 93 //utils.CacheFlag, 94 //utils.CacheDatabaseFlag, 95 utils.CacheTrieFlag, 96 //utils.CacheGCFlag, 97 //utils.TrieCacheGenFlag, 98 utils.ListenPortFlag, 99 utils.MaxPeersFlag, 100 utils.MaxPendingPeersFlag, 101 utils.StakingEnabledFlag, 102 utils.StakerThreadsFlag, 103 utils.StakerLegacyThreadsFlag, 104 utils.MinerNotifyFlag, 105 utils.MinerGasTargetFlag, 106 utils.MinerLegacyGasTargetFlag, 107 utils.MinerGasLimitFlag, 108 utils.MinerGasPriceFlag, 109 utils.MinerLegacyGasPriceFlag, 110 utils.MinerEtherbaseFlag, 111 utils.MinerLegacyEtherbaseFlag, 112 utils.MinerExtraDataFlag, 113 utils.MinerLegacyExtraDataFlag, 114 utils.MinerRecommitIntervalFlag, 115 utils.MinerNoVerfiyFlag, 116 utils.NATFlag, 117 utils.NoDiscoverFlag, 118 //utils.DiscoveryV5Flag, 119 //utils.NetrestrictFlag, 120 utils.NodeKeyFileFlag, 121 utils.NodeKeyHexFlag, 122 //utils.DeveloperFlag, 123 //utils.DeveloperPeriodFlag, 124 //utils.TestnetFlag, 125 //utils.RinkebyFlag, 126 //utils.GoerliFlag, 127 //utils.VMEnableDebugFlag, 128 utils.XDCTestnetFlag, 129 utils.NetworkIdFlag, 130 utils.ConstantinopleOverrideFlag, 131 utils.RPCCORSDomainFlag, 132 utils.RPCVirtualHostsFlag, 133 utils.EthStatsURLFlag, 134 utils.MetricsEnabledFlag, 135 //utils.FakePoWFlag, 136 //utils.NoCompactionFlag, 137 //utils.GpoBlocksFlag, 138 //utils.GpoPercentileFlag, 139 utils.EWASMInterpreterFlag, 140 utils.EVMInterpreterFlag, 141 configFileFlag, 142 utils.AnnounceTxsFlag, 143 utils.StoreRewardFlag, 144 utils.RollbackFlag, 145 } 146 147 rpcFlags = []cli.Flag{ 148 utils.RPCEnabledFlag, 149 utils.RPCListenAddrFlag, 150 utils.RPCPortFlag, 151 utils.RPCApiFlag, 152 utils.WSEnabledFlag, 153 utils.WSListenAddrFlag, 154 utils.WSPortFlag, 155 utils.WSApiFlag, 156 utils.WSAllowedOriginsFlag, 157 utils.IPCDisabledFlag, 158 utils.IPCPathFlag, 159 utils.RPCGlobalGasCap, 160 } 161 162 whisperFlags = []cli.Flag{ 163 utils.WhisperEnabledFlag, 164 utils.WhisperMaxMessageSizeFlag, 165 utils.WhisperMinPOWFlag, 166 utils.WhisperRestrictConnectionBetweenLightClientsFlag, 167 } 168 169 metricsFlags = []cli.Flag{ 170 utils.MetricsEnableInfluxDBFlag, 171 utils.MetricsInfluxDBEndpointFlag, 172 utils.MetricsInfluxDBDatabaseFlag, 173 utils.MetricsInfluxDBUsernameFlag, 174 utils.MetricsInfluxDBPasswordFlag, 175 utils.MetricsInfluxDBTagsFlag, 176 } 177 ) 178 179 func init() { 180 // Initialize the CLI app and start XDC 181 app.Action = XDC 182 app.HideVersion = true // we have a command to print the version 183 app.Copyright = "Copyright (c) 2018 XDCchain" 184 app.Commands = []cli.Command{ 185 // See chaincmd.go: 186 initCommand, 187 importCommand, 188 exportCommand, 189 removedbCommand, 190 dumpCommand, 191 // See accountcmd.go: 192 accountCommand, 193 walletCommand, 194 // See consolecmd.go: 195 consoleCommand, 196 attachCommand, 197 javascriptCommand, 198 // See misccmd.go: 199 versionCommand, 200 // See config.go 201 dumpConfigCommand, 202 } 203 sort.Sort(cli.CommandsByName(app.Commands)) 204 205 app.Flags = append(app.Flags, nodeFlags...) 206 app.Flags = append(app.Flags, rpcFlags...) 207 app.Flags = append(app.Flags, consoleFlags...) 208 app.Flags = append(app.Flags, debug.Flags...) 209 //app.Flags = append(app.Flags, whisperFlags...) 210 app.Flags = append(app.Flags, metricsFlags...) 211 212 app.Before = func(ctx *cli.Context) error { 213 logdir := "" 214 if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { 215 logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") 216 } 217 if err := debug.Setup(ctx, logdir); err != nil { 218 return err 219 } 220 // Cap the cache allowance and tune the garbage collector 221 var mem gosigar.Mem 222 if err := mem.Get(); err == nil { 223 allowance := int(mem.Total / 1024 / 1024 / 3) 224 if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance { 225 log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) 226 ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance)) 227 } 228 } 229 // Ensure Go's GC ignores the database cache for trigger percentage 230 cache := ctx.GlobalInt(utils.CacheFlag.Name) 231 gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) 232 233 log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) 234 godebug.SetGCPercent(int(gogc)) 235 236 // Start metrics export if enabled 237 utils.SetupMetrics(ctx) 238 239 // Start system runtime metrics collection 240 go metrics.CollectProcessMetrics(3 * time.Second) 241 242 return nil 243 } 244 245 app.After = func(ctx *cli.Context) error { 246 debug.Exit() 247 console.Stdin.Close() // Resets terminal mode. 248 return nil 249 } 250 } 251 252 func main() { 253 if err := app.Run(os.Args); err != nil { 254 fmt.Fprintln(os.Stderr, err) 255 os.Exit(1) 256 } 257 } 258 259 // XDC is the main entry point into the system if no special subcommand is ran. 260 // It creates a default node based on the command line arguments and runs it in 261 // blocking mode, waiting for it to be shut down. 262 func XDC(ctx *cli.Context) error { 263 if args := ctx.Args(); len(args) > 0 { 264 return fmt.Errorf("invalid command: %q", args[0]) 265 } 266 node, cfg := makeFullNode(ctx) 267 startNode(ctx, node, cfg) 268 node.Wait() 269 return nil 270 } 271 272 // startNode boots up the system node and all registered protocols, after which 273 // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the 274 // miner. 275 func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) { 276 debug.Memsize.Add("node", stack) 277 278 // Start up the node itself 279 utils.StartNode(stack) 280 281 // Unlock any account specifically requested 282 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 283 284 if ctx.GlobalIsSet(utils.UnlockedAccountFlag.Name) { 285 cfg.Account.Unlocks = strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") 286 } 287 288 if ctx.GlobalIsSet(utils.PasswordFileFlag.Name) { 289 cfg.Account.Passwords = utils.MakePasswordList(ctx) 290 } 291 292 for i, account := range cfg.Account.Unlocks { 293 if trimmed := strings.TrimSpace(account); trimmed != "" { 294 unlockAccount(ctx, ks, trimmed, i, cfg.Account.Passwords) 295 } 296 } 297 // Register wallet event handlers to open and auto-derive wallets 298 events := make(chan accounts.WalletEvent, 16) 299 stack.AccountManager().Subscribe(events) 300 301 go func() { 302 // Create a chain state reader for self-derivation 303 rpcClient, err := stack.Attach() 304 if err != nil { 305 utils.Fatalf("Failed to attach to self: %v", err) 306 } 307 stateReader := ethclient.NewClient(rpcClient) 308 309 // Open any wallets already attached 310 for _, wallet := range stack.AccountManager().Wallets() { 311 if err := wallet.Open(""); err != nil { 312 log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) 313 } 314 } 315 // Listen for wallet event till termination 316 for event := range events { 317 switch event.Kind { 318 case accounts.WalletArrived: 319 if err := event.Wallet.Open(""); err != nil { 320 log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) 321 } 322 case accounts.WalletOpened: 323 status, _ := event.Wallet.Status() 324 log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) 325 326 derivationPath := accounts.DefaultBaseDerivationPath 327 if event.Wallet.URL().Scheme == "ledger" { 328 derivationPath = accounts.DefaultLedgerBaseDerivationPath 329 } 330 event.Wallet.SelfDerive(derivationPath, stateReader) 331 332 case accounts.WalletDropped: 333 log.Info("Old wallet dropped", "url", event.Wallet.URL()) 334 event.Wallet.Close() 335 } 336 } 337 }() 338 // Start auxiliary services if enabled 339 340 // Mining only makes sense if a full Ethereum node is running 341 if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { 342 utils.Fatalf("Light clients do not support staking") 343 } 344 var ethereum *eth.Ethereum 345 if err := stack.Service(ðereum); err != nil { 346 utils.Fatalf("Ethereum service not running: %v", err) 347 } 348 if _, ok := ethereum.Engine().(*XDPoS.XDPoS); ok { 349 go func() { 350 started := false 351 ok := false 352 var err error 353 if common.IsTestnet { 354 ok, err = ethereum.ValidateMasternodeTestnet() 355 if err != nil { 356 utils.Fatalf("Can't verify masternode permission: %v", err) 357 } 358 } else { 359 ok, err = ethereum.ValidateMasternode() 360 if err != nil { 361 utils.Fatalf("Can't verify masternode permission: %v", err) 362 } 363 } 364 if ok { 365 log.Info("Masternode found. Enabling staking mode...") 366 gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name) 367 if ctx.IsSet(utils.MinerGasPriceFlag.Name) { 368 gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) 369 } 370 ethereum.TxPool().SetGasPrice(gasprice) 371 372 threads := ctx.GlobalInt(utils.StakerLegacyThreadsFlag.Name) 373 if ctx.GlobalIsSet(utils.StakerThreadsFlag.Name) { 374 threads = ctx.GlobalInt(utils.StakerThreadsFlag.Name) 375 } 376 if err := ethereum.StartStaking(threads); err != nil { 377 utils.Fatalf("Failed to start staking: %v", err) 378 } 379 started = true 380 log.Info("Enabled staking node!!!") 381 } 382 defer close(core.CheckpointCh) 383 for range core.CheckpointCh { 384 log.Info("Checkpoint!!! It's time to reconcile node's state...") 385 if common.IsTestnet { 386 ok, err = ethereum.ValidateMasternodeTestnet() 387 if err != nil { 388 utils.Fatalf("Can't verify masternode permission: %v", err) 389 } 390 } else { 391 ok, err = ethereum.ValidateMasternode() 392 if err != nil { 393 utils.Fatalf("Can't verify masternode permission: %v", err) 394 } 395 } 396 if !ok { 397 if started { 398 log.Info("Only masternode can propose and verify blocks. Cancelling staking on this node...") 399 ethereum.StopStaking() 400 started = false 401 log.Info("Cancelled mining mode!!!") 402 } 403 } else if !started { 404 log.Info("Masternode found. Enabling staking mode...") 405 // Set the gas price to the limits from the CLI and start mining 406 gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name) 407 if ctx.IsSet(utils.MinerGasPriceFlag.Name) { 408 gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) 409 } 410 ethereum.TxPool().SetGasPrice(gasprice) 411 412 threads := ctx.GlobalInt(utils.StakerLegacyThreadsFlag.Name) 413 if ctx.GlobalIsSet(utils.StakerThreadsFlag.Name) { 414 threads = ctx.GlobalInt(utils.StakerThreadsFlag.Name) 415 } 416 if err := ethereum.StartStaking(threads); err != nil { 417 utils.Fatalf("Failed to start staking: %v", err) 418 } 419 started = true 420 log.Info("Enabled staking node!!!") 421 } 422 } 423 }() 424 } 425 }