github.com/klaytn/klaytn@v1.12.1/cmd/utils/nodecmd/defaultcmd.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // go-ethereum is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // go-ethereum is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from cmd/geth/main.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package nodecmd 22 23 import ( 24 "fmt" 25 "os" 26 "runtime" 27 "strings" 28 29 "github.com/klaytn/klaytn/accounts" 30 "github.com/klaytn/klaytn/accounts/keystore" 31 "github.com/klaytn/klaytn/api/debug" 32 "github.com/klaytn/klaytn/client" 33 "github.com/klaytn/klaytn/cmd/utils" 34 "github.com/klaytn/klaytn/log" 35 metricutils "github.com/klaytn/klaytn/metrics/utils" 36 "github.com/klaytn/klaytn/node" 37 "github.com/klaytn/klaytn/node/cn" 38 "github.com/klaytn/klaytn/params" 39 "github.com/urfave/cli/v2" 40 "github.com/urfave/cli/v2/altsrc" 41 ) 42 43 // runKlaytnNode is the main entry point into the system if no special subcommand is ran. 44 // It creates a default node based on the command line arguments and runs it in 45 // blocking mode, waiting for it to be shut down. 46 func RunKlaytnNode(ctx *cli.Context) error { 47 fullNode := MakeFullNode(ctx) 48 startNode(ctx, fullNode) 49 fullNode.Wait() 50 return nil 51 } 52 53 func MakeFullNode(ctx *cli.Context) *node.Node { 54 stack, cfg := utils.MakeConfigNode(ctx) 55 56 if utils.NetworkTypeFlag.Value == utils.SCNNetworkType && cfg.ServiceChain.EnabledSubBridge { 57 if !cfg.CN.NoAccountCreation { 58 logger.Warn("generated accounts can't be synced with the parent chain since account creation is enabled") 59 } 60 switch cfg.ServiceChain.ServiceChainConsensus { 61 case "istanbul": 62 utils.RegisterCNService(stack, &cfg.CN) 63 case "clique": 64 logger.Crit("using clique consensus type is not allowed anymore!") 65 default: 66 logger.Crit("unknown consensus type for the service chain", "consensus", cfg.ServiceChain.ServiceChainConsensus) 67 } 68 } else { 69 utils.RegisterCNService(stack, &cfg.CN) 70 } 71 utils.RegisterService(stack, &cfg.ServiceChain) 72 utils.RegisterDBSyncerService(stack, &cfg.DB) 73 utils.RegisterChainDataFetcherService(stack, &cfg.ChainDataFetcher) 74 return stack 75 } 76 77 // startNode boots up the system node and all registered protocols, after which 78 // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the 79 // miner. 80 func startNode(ctx *cli.Context, stack *node.Node) { 81 debug.Memsize.Add("node", stack) 82 83 // Ntp time check 84 if err := node.NtpCheckWithLocal(stack); err != nil { 85 log.Fatalf("System time should be synchronized: %v", err) 86 } 87 88 // Start up the node itself 89 utils.StartNode(stack) 90 91 // Register wallet event handlers to open and auto-derive wallets 92 events := make(chan accounts.WalletEvent, 16) 93 stack.AccountManager().Subscribe(events) 94 95 go func() { 96 // Create a chain state reader for self-derivation 97 rpcClient, err := stack.Attach() 98 if err != nil { 99 log.Fatalf("Failed to attach to self: %v", err) 100 } 101 stateReader := client.NewClient(rpcClient) 102 103 // Open any wallets already attached 104 for _, wallet := range stack.AccountManager().Wallets() { 105 if err := wallet.Open(""); err != nil { 106 logger.Error("Failed to open wallet", "url", wallet.URL(), "err", err) 107 } 108 } 109 // Listen for wallet event till termination 110 for event := range events { 111 switch event.Kind { 112 case accounts.WalletArrived: 113 if err := event.Wallet.Open(""); err != nil { 114 logger.Error("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) 115 } 116 case accounts.WalletOpened: 117 status, _ := event.Wallet.Status() 118 logger.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) 119 120 if event.Wallet.URL().Scheme == "ledger" { 121 event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader) 122 } else { 123 event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader) 124 } 125 126 case accounts.WalletDropped: 127 logger.Info("Old wallet dropped", "url", event.Wallet.URL()) 128 event.Wallet.Close() 129 } 130 } 131 }() 132 133 if utils.NetworkTypeFlag.Value == utils.SCNNetworkType && utils.ServiceChainConsensusFlag.Value == "clique" { 134 logger.Crit("using clique consensus type is not allowed anymore!") 135 } else { 136 startKlaytnAuxiliaryService(ctx, stack) 137 } 138 139 // Unlock any account specifically requested 140 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 141 142 passwords := utils.MakePasswordList(ctx) 143 unlocks := strings.Split(ctx.String(utils.UnlockedAccountFlag.Name), ",") 144 for i, account := range unlocks { 145 if trimmed := strings.TrimSpace(account); trimmed != "" { 146 UnlockAccount(ctx, ks, trimmed, i, passwords) 147 } 148 } 149 } 150 151 func startKlaytnAuxiliaryService(ctx *cli.Context, stack *node.Node) { 152 var cn *cn.CN 153 if err := stack.Service(&cn); err != nil { 154 log.Fatalf("Klaytn service not running: %v", err) 155 } 156 157 // TODO-Klaytn-NodeCmd disable accept tx before finishing sync. 158 if err := cn.StartMining(false); err != nil { 159 log.Fatalf("Failed to start mining: %v", err) 160 } 161 } 162 163 func CommandNotExist(ctx *cli.Context, s string) { 164 cli.ShowAppHelp(ctx) 165 fmt.Printf("Error: Unknown command \"%v\"\n", s) 166 os.Exit(1) 167 } 168 169 func OnUsageError(context *cli.Context, err error, isSubcommand bool) error { 170 cli.ShowAppHelp(context) 171 return err 172 } 173 174 func CheckCommands(ctx *cli.Context) error { 175 valid := false 176 for _, cmd := range ctx.App.Commands { 177 if cmd.Name == ctx.Args().First() { 178 valid = true 179 } 180 } 181 182 if !valid && ctx.Args().Present() { 183 cli.ShowAppHelp(ctx) 184 return fmt.Errorf("Unknown command \"%v\"\n", ctx.Args().First()) 185 } 186 187 return nil 188 } 189 190 func FlagsFromYaml(ctx *cli.Context) error { 191 confFile := "conf" // flag option for yaml file name 192 if ctx.String(confFile) != "" { 193 if err := altsrc.InitInputSourceWithContext(utils.AllNodeFlags(), altsrc.NewYamlSourceFromFlagFunc(confFile))(ctx); err != nil { 194 return err 195 } 196 } 197 return nil 198 } 199 200 func BeforeRunNode(ctx *cli.Context) error { 201 if err := FlagsFromYaml(ctx); err != nil { 202 return err 203 } 204 MigrateGlobalFlags(ctx) 205 if err := CheckCommands(ctx); err != nil { 206 return err 207 } 208 runtime.GOMAXPROCS(runtime.NumCPU()) 209 logDir := (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") 210 debug.CreateLogDir(logDir) 211 if err := debug.Setup(ctx); err != nil { 212 return err 213 } 214 metricutils.StartMetricCollectionAndExport(ctx) 215 setupNetwork(ctx) 216 return nil 217 } 218 219 // setupNetwork configures the system for either the main net or some test network. 220 func setupNetwork(ctx *cli.Context) { 221 params.TargetGasLimit = ctx.Uint64(utils.TargetGasLimitFlag.Name) 222 } 223 224 func BeforeRunBootnode(ctx *cli.Context) error { 225 if err := FlagsFromYaml(ctx); err != nil { 226 return err 227 } 228 MigrateGlobalFlags(ctx) 229 if err := debug.Setup(ctx); err != nil { 230 return err 231 } 232 metricutils.StartMetricCollectionAndExport(ctx) 233 return nil 234 } 235 236 var migrationApplied = map[*cli.Command]struct{}{} 237 238 // migrateGlobalFlags makes all global flag values available in the 239 // context. This should be called as early as possible in app.Before. 240 // 241 // Example: 242 // 243 // ken account new --keystore /tmp/mykeystore --lightkdf 244 // 245 // is equivalent after calling this method with: 246 // 247 // ken --keystore /tmp/mykeystore --lightkdf account new 248 // 249 // i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf) 250 // will return true even if --lightkdf is set as a global option. 251 // 252 // This function may become unnecessary when https://github.com/urfave/cli/pull/1245 is merged. 253 func MigrateGlobalFlags(ctx *cli.Context) { 254 var iterate func(cs []*cli.Command, fn func(*cli.Command)) 255 iterate = func(cs []*cli.Command, fn func(*cli.Command)) { 256 for _, cmd := range cs { 257 if _, ok := migrationApplied[cmd]; ok { 258 continue 259 } 260 migrationApplied[cmd] = struct{}{} 261 fn(cmd) 262 iterate(cmd.Subcommands, fn) 263 } 264 } 265 266 // This iterates over all commands and wraps their action function. 267 iterate(ctx.App.Commands, func(cmd *cli.Command) { 268 if cmd.Action == nil { 269 return 270 } 271 272 action := cmd.Action 273 cmd.Action = func(ctx *cli.Context) error { 274 doMigrateFlags(ctx) 275 return action(ctx) 276 } 277 }) 278 } 279 280 func doMigrateFlags(ctx *cli.Context) { 281 for _, name := range ctx.FlagNames() { 282 for _, parent := range ctx.Lineage()[1:] { 283 if parent.IsSet(name) { 284 ctx.Set(name, parent.String(name)) 285 break 286 } 287 } 288 } 289 }