以太坊私链启动代码分析

By | 2018年7月14日

Ethereum代码分析

本文将以以太坊私链启动为线索进行简单的代码执行步骤介绍

博主水平弱鸡,如有谬误还请高人指出,将感激不尽

 

终端启动命令:

eth –private “myNet” –config ./config.json -d ./data –network-id 123

这一段命令中的参数,都将通过boost::program_options.options_descripion的实例进行添加(具体命令根据功能区分为Client, Transaction, Mining, Networking, ImportExport, General这几个部分)。在此之后,这些参数将在被解析后以键值映射的形式存入一个boost::program_options::variables_map实例,并命名为vm

 

紧接着,使用vm实例的方法对参数进行检查,并根据启动参数进行各项具体操作。

根据本文开头给出的启动命令参数,eth将进行:

  1. 以字符串形式保存数据目录;
  2. 以字符串形式读取config路径并获取json内容存入configJSON变量(string类型)
  3. 将”myNet”赋值给privateChain(string类型)
  4. 将network-id值123赋值给network ID变量(unsigned类型)

这里开始遇到第一个重点——chainParams对象(ChainParams类实例)

ChainParams类定义了对config.json中字符串形式配置参数的解析、合法性校验以及记录等方法,并可对config的参数进行存储。

在这里可以发现,原有使用 –genesis 参数的 genesis.json 配置过程已经被废弃,genesis配置信息被整合进config.json,进行统一解析。

 

在config.json解析完成后,执行m.execute()方法。m是一个MinerCLI实例,MinerCLI被定义在与eth同目录的MinerAux中,可以对挖矿相关参数进行解析(独立于上述boost::program_options处理流程单独进行解析,窃以为这可以被认为是一种矿机解耦操作)execute方法中进行了挖矿线程数量初始化的工作,线程初值设置为UINT_MAX后与实际线程数量取最小值的操作,此处意图不明,不深究。

注:默认情况下,在创世过程中矿机除了实例化自身外并没有进行更多的操作——包括初始化DAG的工作都没有进行。这与以太坊推荐使用独立矿机模块进行GPU挖矿的行为在逻辑上是相符的。

 

接下来是secretPath的设置和keyManager实例的工作。keyManager是高级的密钥管理工具,它使用一个“key”文件和一个“.salt”文件存储密钥加密后的数据并存入secretPath,这个路径在-d参数目录中可见。

然后执行writeFile()方法,其将author值(即创世文件中配置的创世区块author)写入config.rlp文件落盘。(似乎存在问题)

 

然后,进行网络偏好设置——根据是否配置了本身节点公网ip来创建NetworkPreference(NetworkPreference是一个结构体)实例——netPrefs。这里全部的工作是创建上述实例并根据启动参数进行初值设定。当我们指定了自己的公网ip时,netPrefs结构会记录下我们的公网ip,否则为空。另外,在该实例时构造时用到了一个名为upnp的bool变量作为构造参数(upnp用于nat穿透),其默认值为真,构造时会将netPref中的bool型变量traverseNAT设置为真;netPrefs中的discovery会在网络设置为非私链或在eth启动参数中设置了enableDiscovery时被设置为真;bool型的pin用于标注是否只接受可信节点的连接。

 

在eth/main.cpp中约896行,auto nodesState=contents()代码的意义大概是载入序列化后落盘了的网络信息”network.rlp”文件。这个文件在main.cpp代码末尾,在netData非空时被创建——netData是一个web3.saveNetwork实例,其功能是将已知的节点集合序列化。也就是说,过去已有的网络节点信息将被存储在network.rlp中,并在需要时被读入nodesState对象。

 

此时迎来另一个重点对象:web3

web3是WebThreeDirect的实例,其用到了之前出现过的所有准备好的数据(对象等)作为参数进行实例化。

附:WebThreeDirect简介:

  • 其是web3组件交互的主api hub;
  • 其维持一个libp2p Host的运行(用m_workNet管理工作进程)
  • 其中封装了一组p2p协议(但协议的底层libp2pHost是相同的)

其实例化时用到了一个caps集合作为参数。当使用到它时,它只有一个”eth”元素,而WebThreeDirect构造器结构又表明当没有这个eth元素时,m_ethereum对象(其为一个指向eth::Client的智能指针,代表着一个使用以太坊”eth”协议的客户端)不会进行sealEngine的初始化工作。因此不确定添加”eth”的意义——暂时怀疑是一种对Client的解耦操作,为支持其他种类的协议做准备。

在上述WebThreeDirect实例化的正常流程中,有一步调用Worker::startWorking()函数的操作——这个函数的介绍是“启动worker线程”,推测是挖矿相关的功能,具体工作原理不明。这里已进入底层,暂时不再深究。

startWorking()执行后,上述构造器又调用了m_ethereum->setExtraData函数(设置存入已封(sealed)区块的extra data),写入了一些与客户端有关的数据。

在extraData(main中,string类型)非空的情况下,m_ethereum->setExtraData函数会被通过一个指针再次调用(该对象默认为空)

 

接下来程序会根据OperationMode的值(Import或Export)进行对应操作,暂不研究。

 

然后,程序对keyManager实例进行检查,进行与主密码(masterPassword)载入有关的流程。这里暂时没分析明白……根据代码来看,我们平时私链组网时发生的情况基本上是把从约1004~1031行的代码全都绕了过去——因keyManager.exists()为真成功进入第一个分支,然后又因为条件不满足第一个分支里面唯一的一个分支条件而直接打酱油了

 

1033~1039与预售有关,暂未深入研究

 

1041行的 cout<< ethCredits(); 我没有它执行过的印象,不知是否与其使用的是std::ostringstream进行输出有关……

 

接下来设置同时连接到的节点数以及同时接受的连接数。

初始化gasPricer(gas估价器?)

初始化eth::Client类型的指针,指向web3.ethereum()。并进行一系列与参数设置相关的操作(gasPricer,sealer,author,networkId)

 

执行web3.startNetwork(),其本质是p2p::Host的一个实例m_net中的start()函数,作用是启动网络。此处嵌套复杂,稍后将作为分析重点单独写一篇文档。

 

创建指向jsonrpcIpcServer、sessionManager、accountHolder的智能指针。

创建一个地址表

 

然后是一小段与身份验证相关的代码。代码中的的输出内容只在【在ethconsole通过js发送交易时】见到过

 

接下来启动ipc服务,给出会话key

 

1162~1166行,看起来是根据preferredNodes中的值自动添加一波连接到的节点。怀疑可以通过这个途径预设要连接到的节点,或许FISCO-BCOS中节点配置时预先设置的要连接到的字段中的地址就通过这个实现。大概是可以在这里做文章

 

1181行确定,因mining预设值为0,默认启动后是不开始挖矿的。

 

1191行暂时不明。

点击量:719

5 thoughts on “以太坊私链启动代码分析

发表评论

邮箱地址不会被公开。 必填项已用*标注