github.com/klaytn/klaytn@v1.10.2/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 "gopkg.in/urfave/cli.v1" 40 "gopkg.in/urfave/cli.v1/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.GlobalString(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 contains(list []cli.Flag, item cli.Flag) bool { 191 for _, flag := range list { 192 if flag.GetName() == item.GetName() { 193 return true 194 } 195 } 196 return false 197 } 198 199 func union(list1, list2 []cli.Flag) []cli.Flag { 200 for _, item := range list2 { 201 if !contains(list1, item) { 202 list1 = append(list1, item) 203 } 204 } 205 return list1 206 } 207 208 func allNodeFlags() []cli.Flag { 209 nodeFlags := []cli.Flag{} 210 nodeFlags = append(nodeFlags, CommonNodeFlags...) 211 nodeFlags = append(nodeFlags, CommonRPCFlags...) 212 nodeFlags = append(nodeFlags, ConsoleFlags...) 213 nodeFlags = append(nodeFlags, debug.Flags...) 214 nodeFlags = union(nodeFlags, KCNFlags) 215 nodeFlags = union(nodeFlags, KPNFlags) 216 nodeFlags = union(nodeFlags, KENFlags) 217 nodeFlags = union(nodeFlags, KSCNFlags) 218 nodeFlags = union(nodeFlags, KSPNFlags) 219 nodeFlags = union(nodeFlags, KSENFlags) 220 return nodeFlags 221 } 222 223 var confFile = "conf" // flag option for yaml file name 224 225 func FlagsFromYaml(ctx *cli.Context) error { 226 if ctx.String(confFile) != "" { 227 if err := altsrc.InitInputSourceWithContext(allNodeFlags(), altsrc.NewYamlSourceFromFlagFunc(confFile))(ctx); err != nil { 228 return err 229 } 230 } 231 return nil 232 } 233 234 func BeforeRunNode(ctx *cli.Context) error { 235 // TODO-klaytn - yaml bug: doesn't affact global flag whther the flag is set or not 236 // You can enable this code after the bug fix 237 // if err := FlagsFromYaml(ctx); err != nil { 238 // return err 239 // } 240 if err := CheckCommands(ctx); err != nil { 241 return err 242 } 243 runtime.GOMAXPROCS(runtime.NumCPU()) 244 logDir := (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") 245 debug.CreateLogDir(logDir) 246 if err := debug.Setup(ctx); err != nil { 247 return err 248 } 249 metricutils.StartMetricCollectionAndExport(ctx) 250 setupNetwork(ctx) 251 return nil 252 } 253 254 // SetupNetwork configures the system for either the main net or some test network. 255 func setupNetwork(ctx *cli.Context) { 256 // TODO(fjl): move target gas limit into config 257 params.TargetGasLimit = ctx.GlobalUint64(utils.TargetGasLimitFlag.Name) 258 } 259 260 func BeforeRunBootnode(ctx *cli.Context) error { 261 if err := FlagsFromYaml(ctx); err != nil { 262 return err 263 } 264 if err := debug.Setup(ctx); err != nil { 265 return err 266 } 267 metricutils.StartMetricCollectionAndExport(ctx) 268 return nil 269 }