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  }