主程序初始化

比特币源码分析(三) - 主程序初始化

https://blog.csdn.net/yzpbright/article/details/81165546

本文是以一个整体的角度分析程序初始化过程中所做的操作,整个初始化过程如果要分开来细讲可以写好几篇,后面一系列文章会具体展开分析关键逻辑的源码。

主程序的入口函数main()在bitcoind.cpp文件中:

int main(int argc, char* argv[])
{
    SetupEnvironment();

    // Connect bitcoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

一步一步分析下。
一、SetupEnvironment() ,设置运行环境
二、noui_connect(),连接bitcoind信号处理器
三、AppInit(argc, argv), 应用初始化,这里有大量的初始化操作,接下来一步一步分析下这个函数的源码:

1.解析运行输入的参数,保存在 mapArgs 这个map容器中

    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
    gArgs.ParseParameters(argc, argv);
  • 1
  • 2

2.处理查询帮助信息和版本信息的命令

    // Process help and version before taking care about datadir
    if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") ||  gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version"))
    {
        std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (gArgs.IsArgSet("-version"))
        {
            strUsage += FormatParagraph(LicenseInfo());
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  bitcoind [options]                     " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return true;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3.检查应用的数据目录

        if (!fs::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
            return false;
        }
  • 1
  • 2
  • 3
  • 4
  • 5

4.读取配置文件

        try
        {
            gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
        } catch (const std::exception& e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

5.检查判断是主网还是测试网络,并设置区块链的全局参数

        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        try {
            SelectParams(ChainNameFromCommandLine());
        } catch (const std::exception& e) {
            fprintf(stderr, "Error: %s\n", e.what());
            return false;
        }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

6.设置server标识为true,即启用RPC服务

扫描二维码关注公众号,回复: 6094811 查看本文章
        // -server defaults to true for bitcoind but not for the GUI so do this here
        gArgs.SoftSetBoolArg("-server", true);
  • 1
  • 2

7.初始化日志

        // Set this early so that parameter interactions go to console
        InitLogging();       
  • 1
  • 2

8.初始化参数交互,即根据规则将一些设置的参数转化为设置其他参数

       InitParameterInteraction();
  • 1

8.建立Bitcoin Core的基础上下文环境

        if (!AppInitBasicSetup())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
  • 1
  • 2
  • 3
  • 4
  • 5

9.初始化参数交互,根据设置的参数做一些逻辑条件判断,根据情况显示相应的警告信息或者异常信息,也会有相关计算,将结果存储在内部变量中

        if (!AppInitParameterInteraction())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
  • 1
  • 2
  • 3
  • 4
  • 5

10.完整性检查

        if (!AppInitSanityChecks())
        {
            // InitError will have been called with detailed error, which ends up on console
            return false;
        }
  • 1
  • 2
  • 3
  • 4
  • 5

11.判断是否需要在后台运行(Daemonize)

        if (gArgs.GetBoolArg("-daemon", false))
        {
			#if HAVE_DECL_DAEMON
            fprintf(stdout, "Bitcoin server starting\n");

            // Daemonize
            if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
                fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
                return false;
            }
			#else
            fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
            return false;
			#endif // HAVE_DECL_DAEMON
        }       

12.锁住Bitcoin Core数据目录

        // Lock data directory after daemonization
        if (!AppInitLockDataDirectory())
        {
            // If locking the data directory failed, exit immediately
            return false;
        }

13.Bitcoin Core的主要初始化工作

        fRet = AppInitMain();
  • 1

14.监结束程序的请求,若有结束程序的请求,则完成结束程序的相关操作

    if (!fRet)
    {
        Interrupt();
    } else {
        WaitForShutdown();
    }
    Shutdown();

P2P网络相关

CConnman
该类在src/net.h中声明,在src/net.cpp中实现。

class CConnman
{
public:

    enum NumConnections {
        CONNECTIONS_NONE = 0,
        CONNECTIONS_IN = (1U << 0),
        CONNECTIONS_OUT = (1U << 1),
        CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
    };

    struct Options
    {
        ServiceFlags nLocalServices = NODE_NONE;
        int nMaxConnections = 0;
        int nMaxOutbound = 0;
        int nMaxAddnode = 0;
        int nMaxFeeler = 0;
        int nBestHeight = 0;
        CClientUIInterface* uiInterface = nullptr;
        NetEventsInterface* m_msgproc = nullptr;
        unsigned int nSendBufferMaxSize = 0;
        unsigned int nReceiveFloodSize = 0;
        uint64_t nMaxOutboundTimeframe = 0;
        uint64_t nMaxOutboundLimit = 0;
        std::vector<std::string> vSeedNodes;
        std::vector<CSubNet> vWhitelistedRange;
        std::vector<CService> vBinds, vWhiteBinds;
        bool m_use_addrman_outgoing = true;
        std::vector<std::string> m_specified_outgoing;
        std::vector<std::string> m_added_nodes;
    };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

该类是网络连接管理类,比较庞大,负责节点的启动、结束,推送消息,接收其他节点的连接等。

PeerLogicValidation
该类多重继承了两个接口类:CValidationInterface, 和 NetEventsInterface 。
CValidationInterface,主要是通知交易和区块相关的状态的改变。
NetEventsInterface,主要是处理从其他节点接收到的消息,发送消息,

/**
 * Interface for message handling
 */
class NetEventsInterface
{
public:
    virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
    virtual bool SendMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
    virtual void InitializeNode(CNode* pnode) = 0;
    virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0;
};

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

除此之外,该类新增了几个方法,用于处理过期信息和剔除多余的对等节点

    void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
    void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
    void EvictExtraOutboundPeers(int64_t time_in_seconds);
 

猜你喜欢

转载自blog.csdn.net/TuxedoLinux/article/details/89761338
今日推荐