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