zoukankan      html  css  js  c++  java
  • [ethereum源码分析](4) ethereum运行开启console

    前言

    上一章我们介绍了  ethereum初始化指令 ,包括了系统是如何调用指令和指令的执行。在本章节我们将会介绍 geth --datadir dev/data/02 --networkid 666 console 指令。

    指令分析

    指令: geth --datadir dev/data/02 --networkid 666 console  

    介绍:上面的指令主要的工作为:

    • 运行eth程序
    • 开启控制台

    分析:

    •  --datadir :指定eth的数据存储地址为 dev/data/02 
    •  --networkid :指定eth的网络编号为 666 ,与其他eth网络区分,这个是建立公网的关键。

    代码分析

    接下来就让我们进入代码分析阶段,至于系统是如何执行命令的在前一章已经介绍过了,这里就不多在做介绍。

    通过上一章的介绍我们知道,eth系统会执行以下的指令:

    consoleCommand = cli.Command{
            Action:   utils.MigrateFlags( localConsole ),
            Name:     "console",
            Usage:    "Start an interactive JavaScript environment",
            Flags:    append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...),
            Category: "CONSOLE COMMANDS",
            Description: `
    The Geth console is an interactive shell for the JavaScript runtime environment
    which exposes a node admin interface as well as the Ðapp JavaScript API.
    See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`,
        }

    上面就是我们 command 指令的数据结构,由上面的代码可知,最终代码会执行 localConsole 这个函数,那么下面就让我们来跟进这个函数:

    // localConsole starts a new geth node, attaching a JavaScript console to it at the
    // same time.
    func localConsole(ctx *cli.Context) error {
        // Create and start the node based on the CLI flags
        node := makeFullNode(ctx)//初始化一些配置信息
        startNode(ctx, node)//开启节点
        defer node.Stop()
    
        // Attach to the newly started node and start the JavaScript console
        client, err := node.Attach()
        if err != nil {
            utils.Fatalf("Failed to attach to the inproc geth: %v", err)
        }
        config := console.Config{
            DataDir: utils.MakeDataDir(ctx),
            DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
            Client:  client,
            Preload: utils.MakeConsolePreloads(ctx),
        }
    
        console, err := console.New(config)
        if err != nil {
            utils.Fatalf("Failed to start the JavaScript console: %v", err)
        }
        defer console.Stop(false)
    
        // If only a short execution was requested, evaluate and return
        if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
            console.Evaluate(script)
            return nil
        }
        // Otherwise print the welcome screen and enter interactive mode
        console.Welcome()
        console.Interactive()//进入命令行
    
        return nil
    }

    上面的代码首先执行了 makeFullNode(ctx) 。下面让我们来跟进代码:

    func makeFullNode(ctx *cli.Context) *node.Node {
        stack, cfg := makeConfigNode(ctx)//在这里构造了一个节点
    
        utils.RegisterEthService(stack, &cfg.Eth)
    
        if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
            utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
        }
        // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
        shhEnabled := enableWhisper(ctx)
        shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
        if shhEnabled || shhAutoEnabled {
            if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) {
                cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name))
            }
            if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
                cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name)
            }
            utils.RegisterShhService(stack, &cfg.Shh)
        }
    
        // Add the Ethereum Stats daemon if requested.
        if cfg.Ethstats.URL != "" {
            utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
        }
        return stack
    }

     上面的代码首先构造了一个节点,那么他是如何去构造这个节点的呢,让我们来看一看 makeConfigNode(ctx) 这个函数:

    func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
        // Load defaults.
        cfg := gethConfig{
            Eth:       eth.DefaultConfig,//配置eth的一些基本信息,里面设置了NetWorkId(默认值为1,这也是eth的主网)的信息
            Shh:       whisper.DefaultConfig,//里面配置了两个参数:1.MaxMessageSize 2.MinimumAcceptedPOW(POW:Proof of Work,工作量证明),暂时不知道有什么用处?
            Node:      defaultNodeConfig(),//这了初始化了节点的配置,主要有网络的一些配置,还有就是数据的存储路径
            Dashboard: dashboard.DefaultConfig,//仪表盘的配置:端口号,刷新时间
        }
    
        // Load config file.
        if file := ctx.GlobalString(configFileFlag.Name); file != "" {
            if err := loadConfig(file, &cfg); err != nil {
                utils.Fatalf("%v", err)
            }
        }
    
        // Apply flags.
        utils.SetNodeConfig(ctx, &cfg.Node)//这里设置了P2P,IPC,HTTP,WS,DataDir,KeyStoreDir的值
        stack, err := node.New(&cfg.Node)
        if err != nil {
            utils.Fatalf("Failed to create the protocol stack: %v", err)
        }
        utils.SetEthConfig(ctx, stack, &cfg.Eth)//这里设置NetWorkId的值
        if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
            cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
        }
    
        utils.SetShhConfig(ctx, stack, &cfg.Shh)
        utils.SetDashboardConfig(ctx, &cfg.Dashboard)
    
        return stack, cfg
    }

    当 makeFullNode(ctx)  执行完以后,接下来执行的就是 startNode(ctx, node) ,它的代码如下:

    // startNode boots up the system node and all registered protocols, after which
    // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
    // miner.
    func startNode(ctx *cli.Context, stack *node.Node) {
        debug.Memsize.Add("node", stack)
    
        // Start up the node itself
        utils.StartNode(stack)//开启节点,主要做了开启P2P网络,开启UDP监听(监听30303端口),开启RLPx监听。
    
        // Unlock any account specifically requested
        ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
    
        passwords := utils.MakePasswordList(ctx)
        unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
        for i, account := range unlocks {
            if trimmed := strings.TrimSpace(account); trimmed != "" {
                unlockAccount(ctx, ks, trimmed, i, passwords)
            }
        }
        // Register wallet event handlers to open and auto-derive wallets
        events := make(chan accounts.WalletEvent, 16)
        stack.AccountManager().Subscribe(events)
    
        go func() {
            // Create a chain state reader for self-derivation
            rpcClient, err := stack.Attach()
            if err != nil {
                utils.Fatalf("Failed to attach to self: %v", err)
            }
            stateReader := ethclient.NewClient(rpcClient)
    
            // Open any wallets already attached
            for _, wallet := range stack.AccountManager().Wallets() {
                if err := wallet.Open(""); err != nil {
                    log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
                }
            }
            // Listen for wallet event till termination
            for event := range events {
                switch event.Kind {
                case accounts.WalletArrived:
                    if err := event.Wallet.Open(""); err != nil {
                        log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
                    }
                case accounts.WalletOpened:
                    status, _ := event.Wallet.Status()
                    log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
    
                    if event.Wallet.URL().Scheme == "ledger" {
                        event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader)
                    } else {
                        event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
                    }
    
                case accounts.WalletDropped:
                    log.Info("Old wallet dropped", "url", event.Wallet.URL())
                    event.Wallet.Close()
                }
            }
        }()
        // Start auxiliary services if enabled
        if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
            // Mining only makes sense if a full Ethereum node is running
            if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
                utils.Fatalf("Light clients do not support mining")
            }
            var ethereum *eth.Ethereum
            if err := stack.Service(&ethereum); err != nil {
                utils.Fatalf("Ethereum service not running: %v", err)
            }
            // Use a reduced number of threads if requested
            if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
                type threaded interface {
                    SetThreads(threads int)
                }
                if th, ok := ethereum.Engine().(threaded); ok {
                    th.SetThreads(threads)
                }
            }
            // Set the gas price to the limits from the CLI and start mining
            ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
            if err := ethereum.StartMining(true); err != nil {
                utils.Fatalf("Failed to start mining: %v", err)
            }
        }
    }
  • 相关阅读:
    sql删除注意的问题
    lua创建文件
    linux部分常用命令
    已知账户和密码进行远程桌面
    excel2013超链接进不去,提示“您的组织策略不允许...”
    2019-2020-1 20199321《Linux内核原理与分析》第七周作业
    《深入理解计算机系统》第一章读书笔记 20199321
    《文献管理与信息分析》速读笔记
    《深入理解计算机系统》速读笔记
    《构建之法现代软件工程》速读笔记
  • 原文地址:https://www.cnblogs.com/cafebabe-yun/p/9392341.html
Copyright © 2011-2022 走看看