github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/geth/main.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:32</date>
    10  //</624450068618940416>
    11  
    12  
    13  //geth是以太坊的官方命令行客户端。
    14  package main
    15  
    16  import (
    17  	"fmt"
    18  	"math"
    19  	"os"
    20  	godebug "runtime/debug"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/elastic/gosigar"
    27  	"github.com/ethereum/go-ethereum/accounts"
    28  	"github.com/ethereum/go-ethereum/accounts/keystore"
    29  	"github.com/ethereum/go-ethereum/cmd/utils"
    30  	"github.com/ethereum/go-ethereum/console"
    31  	"github.com/ethereum/go-ethereum/eth"
    32  	"github.com/ethereum/go-ethereum/ethclient"
    33  	"github.com/ethereum/go-ethereum/internal/debug"
    34  	"github.com/ethereum/go-ethereum/log"
    35  	"github.com/ethereum/go-ethereum/metrics"
    36  	"github.com/ethereum/go-ethereum/node"
    37  	"gopkg.in/urfave/cli.v1"
    38  )
    39  
    40  const (
    41  clientIdentifier = "geth" //要通过网络进行广告的客户端标识符
    42  )
    43  
    44  var (
    45  //git sha1提交发布的哈希(通过链接器标志设置)
    46  	gitCommit = ""
    47  //保存所有命令和标志的应用程序。
    48  	app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
    49  //配置节点的标志
    50  	nodeFlags = []cli.Flag{
    51  		utils.IdentityFlag,
    52  		utils.UnlockedAccountFlag,
    53  		utils.PasswordFileFlag,
    54  		utils.BootnodesFlag,
    55  		utils.BootnodesV4Flag,
    56  		utils.BootnodesV5Flag,
    57  		utils.DataDirFlag,
    58  		utils.KeyStoreDirFlag,
    59  		utils.NoUSBFlag,
    60  		utils.DashboardEnabledFlag,
    61  		utils.DashboardAddrFlag,
    62  		utils.DashboardPortFlag,
    63  		utils.DashboardRefreshFlag,
    64  		utils.EthashCacheDirFlag,
    65  		utils.EthashCachesInMemoryFlag,
    66  		utils.EthashCachesOnDiskFlag,
    67  		utils.EthashDatasetDirFlag,
    68  		utils.EthashDatasetsInMemoryFlag,
    69  		utils.EthashDatasetsOnDiskFlag,
    70  		utils.TxPoolLocalsFlag,
    71  		utils.TxPoolNoLocalsFlag,
    72  		utils.TxPoolJournalFlag,
    73  		utils.TxPoolRejournalFlag,
    74  		utils.TxPoolPriceLimitFlag,
    75  		utils.TxPoolPriceBumpFlag,
    76  		utils.TxPoolAccountSlotsFlag,
    77  		utils.TxPoolGlobalSlotsFlag,
    78  		utils.TxPoolAccountQueueFlag,
    79  		utils.TxPoolGlobalQueueFlag,
    80  		utils.TxPoolLifetimeFlag,
    81  		utils.SyncModeFlag,
    82  		utils.GCModeFlag,
    83  		utils.LightServFlag,
    84  		utils.LightPeersFlag,
    85  		utils.LightKDFFlag,
    86  		utils.WhitelistFlag,
    87  		utils.CacheFlag,
    88  		utils.CacheDatabaseFlag,
    89  		utils.CacheTrieFlag,
    90  		utils.CacheGCFlag,
    91  		utils.TrieCacheGenFlag,
    92  		utils.ListenPortFlag,
    93  		utils.MaxPeersFlag,
    94  		utils.MaxPendingPeersFlag,
    95  		utils.MiningEnabledFlag,
    96  		utils.MinerThreadsFlag,
    97  		utils.MinerLegacyThreadsFlag,
    98  		utils.MinerNotifyFlag,
    99  		utils.MinerGasTargetFlag,
   100  		utils.MinerLegacyGasTargetFlag,
   101  		utils.MinerGasLimitFlag,
   102  		utils.MinerGasPriceFlag,
   103  		utils.MinerLegacyGasPriceFlag,
   104  		utils.MinerEtherbaseFlag,
   105  		utils.MinerLegacyEtherbaseFlag,
   106  		utils.MinerExtraDataFlag,
   107  		utils.MinerLegacyExtraDataFlag,
   108  		utils.MinerRecommitIntervalFlag,
   109  		utils.MinerNoVerfiyFlag,
   110  		utils.NATFlag,
   111  		utils.NoDiscoverFlag,
   112  		utils.DiscoveryV5Flag,
   113  		utils.NetrestrictFlag,
   114  		utils.NodeKeyFileFlag,
   115  		utils.NodeKeyHexFlag,
   116  		utils.DeveloperFlag,
   117  		utils.DeveloperPeriodFlag,
   118  		utils.TestnetFlag,
   119  		utils.RinkebyFlag,
   120  		utils.VMEnableDebugFlag,
   121  		utils.NetworkIdFlag,
   122  		utils.ConstantinopleOverrideFlag,
   123  		utils.RPCCORSDomainFlag,
   124  		utils.RPCVirtualHostsFlag,
   125  		utils.EthStatsURLFlag,
   126  		utils.MetricsEnabledFlag,
   127  		utils.FakePoWFlag,
   128  		utils.NoCompactionFlag,
   129  		utils.GpoBlocksFlag,
   130  		utils.GpoPercentileFlag,
   131  		utils.EWASMInterpreterFlag,
   132  		utils.EVMInterpreterFlag,
   133  		configFileFlag,
   134  	}
   135  
   136  	rpcFlags = []cli.Flag{
   137  		utils.RPCEnabledFlag,
   138  		utils.RPCListenAddrFlag,
   139  		utils.RPCPortFlag,
   140  		utils.RPCApiFlag,
   141  		utils.WSEnabledFlag,
   142  		utils.WSListenAddrFlag,
   143  		utils.WSPortFlag,
   144  		utils.WSApiFlag,
   145  		utils.WSAllowedOriginsFlag,
   146  		utils.IPCDisabledFlag,
   147  		utils.IPCPathFlag,
   148  	}
   149  
   150  	whisperFlags = []cli.Flag{
   151  		utils.WhisperEnabledFlag,
   152  		utils.WhisperMaxMessageSizeFlag,
   153  		utils.WhisperMinPOWFlag,
   154  		utils.WhisperRestrictConnectionBetweenLightClientsFlag,
   155  	}
   156  
   157  	metricsFlags = []cli.Flag{
   158  		utils.MetricsEnableInfluxDBFlag,
   159  		utils.MetricsInfluxDBEndpointFlag,
   160  		utils.MetricsInfluxDBDatabaseFlag,
   161  		utils.MetricsInfluxDBUsernameFlag,
   162  		utils.MetricsInfluxDBPasswordFlag,
   163  		utils.MetricsInfluxDBHostTagFlag,
   164  	}
   165  )
   166  
   167  func init() {
   168  //初始化cli应用程序并启动geth
   169  	app.Action = geth
   170  app.HideVersion = true //我们有打印版本的命令
   171  	app.Copyright = "Copyright 2013-2019 The go-ethereum Authors"
   172  	app.Commands = []cli.Command{
   173  //参见chainCmd.Go:
   174  		initCommand,
   175  		importCommand,
   176  		exportCommand,
   177  		importPreimagesCommand,
   178  		exportPreimagesCommand,
   179  		copydbCommand,
   180  		removedbCommand,
   181  		dumpCommand,
   182  //请参阅monitorCmd.go:
   183  		monitorCommand,
   184  //参见accountCmd.Go:
   185  		accountCommand,
   186  		walletCommand,
   187  //请参阅consoleCmd.Go:
   188  		consoleCommand,
   189  		attachCommand,
   190  		javascriptCommand,
   191  //参见MISCCM.Do:
   192  		makecacheCommand,
   193  		makedagCommand,
   194  		versionCommand,
   195  		bugCommand,
   196  		licenseCommand,
   197  //参见CONG.GO
   198  		dumpConfigCommand,
   199  	}
   200  	sort.Sort(cli.CommandsByName(app.Commands))
   201  
   202  	app.Flags = append(app.Flags, nodeFlags...)
   203  	app.Flags = append(app.Flags, rpcFlags...)
   204  	app.Flags = append(app.Flags, consoleFlags...)
   205  	app.Flags = append(app.Flags, debug.Flags...)
   206  	app.Flags = append(app.Flags, whisperFlags...)
   207  	app.Flags = append(app.Flags, metricsFlags...)
   208  
   209  	app.Before = func(ctx *cli.Context) error {
   210  		logdir := ""
   211  		if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
   212  			logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs")
   213  		}
   214  		if err := debug.Setup(ctx, logdir); err != nil {
   215  			return err
   216  		}
   217  //限制缓存容量并优化垃圾收集器
   218  		var mem gosigar.Mem
   219  		if err := mem.Get(); err == nil {
   220  			allowance := int(mem.Total / 1024 / 1024 / 3)
   221  			if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance {
   222  				log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
   223  				ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance))
   224  			}
   225  		}
   226  //确保go的gc忽略触发器百分比的数据库缓存
   227  		cache := ctx.GlobalInt(utils.CacheFlag.Name)
   228  		gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
   229  
   230  		log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
   231  		godebug.SetGCPercent(int(gogc))
   232  
   233  //如果启用,则启动度量导出
   234  		utils.SetupMetrics(ctx)
   235  
   236  //启动系统运行时度量集合
   237  		go metrics.CollectProcessMetrics(3 * time.Second)
   238  
   239  		return nil
   240  	}
   241  
   242  	app.After = func(ctx *cli.Context) error {
   243  		debug.Exit()
   244  console.Stdin.Close() //重置终端模式。
   245  		return nil
   246  	}
   247  }
   248  
   249  func main() {
   250  	if err := app.Run(os.Args); err != nil {
   251  		fmt.Fprintln(os.Stderr, err)
   252  		os.Exit(1)
   253  	}
   254  }
   255  
   256  //如果没有运行特殊的子命令,geth是进入系统的主要入口点。
   257  //它基于命令行参数创建默认节点并在
   258  //阻塞模式,等待关闭。
   259  func geth(ctx *cli.Context) error {
   260  	if args := ctx.Args(); len(args) > 0 {
   261  		return fmt.Errorf("invalid command: %q", args[0])
   262  	}
   263  	node := makeFullNode(ctx)
   264  	startNode(ctx, node)
   265  	node.Wait()
   266  	return nil
   267  }
   268  
   269  //startnode启动系统节点和所有注册的协议,之后
   270  //它解锁所有请求的帐户,并启动RPC/IPC接口和
   271  //矿工。
   272  func startNode(ctx *cli.Context, stack *node.Node) {
   273  	debug.Memsize.Add("node", stack)
   274  
   275  //启动节点本身
   276  	utils.StartNode(stack)
   277  
   278  //解锁任何特别要求的帐户
   279  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   280  
   281  	passwords := utils.MakePasswordList(ctx)
   282  	unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
   283  	for i, account := range unlocks {
   284  		if trimmed := strings.TrimSpace(account); trimmed != "" {
   285  			unlockAccount(ctx, ks, trimmed, i, passwords)
   286  		}
   287  	}
   288  //注册钱包事件处理程序以打开和自动派生钱包
   289  	events := make(chan accounts.WalletEvent, 16)
   290  	stack.AccountManager().Subscribe(events)
   291  
   292  	go func() {
   293  //创建用于自派生的链状态读取器
   294  		rpcClient, err := stack.Attach()
   295  		if err != nil {
   296  			utils.Fatalf("Failed to attach to self: %v", err)
   297  		}
   298  		stateReader := ethclient.NewClient(rpcClient)
   299  
   300  //打开所有已连接的钱包
   301  		for _, wallet := range stack.AccountManager().Wallets() {
   302  			if err := wallet.Open(""); err != nil {
   303  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   304  			}
   305  		}
   306  //听钱包事件直到终止
   307  		for event := range events {
   308  			switch event.Kind {
   309  			case accounts.WalletArrived:
   310  				if err := event.Wallet.Open(""); err != nil {
   311  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   312  				}
   313  			case accounts.WalletOpened:
   314  				status, _ := event.Wallet.Status()
   315  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   316  
   317  				derivationPath := accounts.DefaultBaseDerivationPath
   318  				if event.Wallet.URL().Scheme == "ledger" {
   319  					derivationPath = accounts.DefaultLedgerBaseDerivationPath
   320  				}
   321  				event.Wallet.SelfDerive(derivationPath, stateReader)
   322  
   323  			case accounts.WalletDropped:
   324  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   325  				event.Wallet.Close()
   326  			}
   327  		}
   328  	}()
   329  //启动辅助服务(如果启用)
   330  	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
   331  //只有当一个完整的以太坊节点正在运行时,挖掘才有意义。
   332  		if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
   333  			utils.Fatalf("Light clients do not support mining")
   334  		}
   335  		var ethereum *eth.Ethereum
   336  		if err := stack.Service(&ethereum); err != nil {
   337  			utils.Fatalf("Ethereum service not running: %v", err)
   338  		}
   339  //将天然气价格设置为CLI的限制,然后开始开采。
   340  		gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name)
   341  		if ctx.IsSet(utils.MinerGasPriceFlag.Name) {
   342  			gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
   343  		}
   344  		ethereum.TxPool().SetGasPrice(gasprice)
   345  
   346  		threads := ctx.GlobalInt(utils.MinerLegacyThreadsFlag.Name)
   347  		if ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
   348  			threads = ctx.GlobalInt(utils.MinerThreadsFlag.Name)
   349  		}
   350  		if err := ethereum.StartMining(threads); err != nil {
   351  			utils.Fatalf("Failed to start mining: %v", err)
   352  		}
   353  	}
   354  }
   355