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  }