Reading Bitcoin source code 2

Last time I read AppInit in src / bitcoind.cpp, the approximate process is

1,解析-?,-h,-help,-version,输出帮助和版本信息
2,解析-datadir参数,GetDataDir函数判定所指定数据目录是否合法
3,通过-conf参数,ReadConfigFile函数读取配置文件
4,通过-testnet和-regtest参数,ChainNameFromCommandLine函数设置的当前程序运行的网络
5,通过-printtoconsole等参数,InitLogging函数初始化日志记录以及打印方式
6,InitParameterInteraction函数初始化网络参数
7,AppInitBasicSetup函数注册相应的消息以及处理方式
8,AppInitParameterInteraction函数设置区块链运行参数
9,AppInitSanityChecks函数检查比特币运行时所需要的所有的库是否都运行正常
10,通过-daemon参数设置是否后台运行
11,AppInitMain函数运行主应用程序
12,启动失败中断操作和清理工作

The AppInit function code is as follows: The
code is as follows:

    54	//////////////////////////////////////////////////////////////////////////////
    55	//
    56	// Start
    57	//
    58	bool AppInit(int argc, char* argv[])
    59	{
    60	    bool fRet = false;
    61	
    62	    //
    63	    // Parameters
    64	    //
    65	    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
    66	    gArgs.ParseParameters(argc, argv);
    67	     //如果命令行参数是-?,-h,-help,-version的话首先构造版本和usage信息
    68	    // Process help and version before taking care about datadir
    69	    if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") ||  gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version"))
    70	    {
                //构造版本字符串,例如:Bitcoin Core Daemon version v0.16.0rc2
    71	        std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";
    72	
                  //如果是-version,构造追加license信息
    73	        if (gArgs.IsArgSet("-version"))
    74	        {
    75	            strUsage += FormatParagraph(LicenseInfo());
    76	        }
                 //如果是-?,-h,-help,构造追加usage信息
    77	        else
    78	        {
    79	            strUsage += "\n" + _("Usage:") + "\n" +
    80	                  "  bitcoind [options]                     " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";
    81	
    82	            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
    83	        }
    84	
    85	        fprintf(stdout, "%s", strUsage.c_str());
    86	        return true;
    87	    }
    88	
             //检测数据目录
    89	    try
    90	    {
            //解析-datadir参数,通过GetDataDir检测和处理-datadir参数指定的目录
    91	        if (!fs::is_directory(GetDataDir(false)))
    92	        {
    93	            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
    94	            return false;
    95	        }
              //通过-conf读取配置文件
    96	        try
    97	        {
    98	            gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
    99	        } catch (const std::exception& e) {
   100	            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
   101	            return false;
   102	        }
               //检测-testnet和-regtest设置的当前程序运行的网络
   103	        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
   104	        try {
   105	            SelectParams(ChainNameFromCommandLine());
   106	        } catch (const std::exception& e) {
   107	            fprintf(stderr, "Error: %s\n", e.what());
   108	            return false;
   109	        }
   110	
              //不合法的参数字符检测
   111	        // Error out when loose non-argument tokens are encountered on command line
   112	        for (int i = 1; i < argc; i++) {
   113	            if (!IsSwitchChar(argv[i][0])) {
   114	                fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
   115	                return false;
   116	            }
   117	        }
   118

                 //设置-server参数为true,而-server参数表示是否接收RPC命令,
                 //这里因为是bitcoind,默认作为核心服务器接收bitcoin-cli以及bitcoin-tx传送的命令	
   119	        // -server defaults to true for bitcoind but not for the GUI so do this here
   120	        gArgs.SoftSetBoolArg("-server", true);
   121	        // Set this early so that parameter interactions go to console
                  //初始化日志记录以及打印方式
   122	        InitLogging();
                    //初始化网络参数
   123	        InitParameterInteraction();
                   //注册相应的消息以及处理方式
   124	        if (!AppInitBasicSetup())
   125	        {
   126	            // InitError will have been called with detailed error, which ends up on console
   127	            return false;
   128	        }
                 //设置区块链运行参数
   129	        if (!AppInitParameterInteraction())
   130	        {
   131	            // InitError will have been called with detailed error, which ends up on console
   132	            return false;
   133	        }
               //Sanity Check是用来检查比特币运行时所需要的所有的库是否都运行正常
   134	        if (!AppInitSanityChecks())
   135	        {
   136	            // InitError will have been called with detailed error, which ends up on console
   137	            return false;
   138	        }
             //通过-daemon参数设置是否后台运行
   139	        if (gArgs.GetBoolArg("-daemon", false))
   140	        {
   141	#if HAVE_DECL_DAEMON
   142	            fprintf(stdout, "Bitcoin server starting\n");
   143	
   144	            // Daemonize
   145	            if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
   146	                fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
   147	                return false;
   148	            }
   149	#else
   150	            fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
   151	            return false;
   152	#endif // HAVE_DECL_DAEMON
   153	        }
                  //后台运行后锁定数据目录
   154	        // Lock data directory after daemonization
   155	        if (!AppInitLockDataDirectory())
   156	        {
   157	            // If locking the data directory failed, exit immediately
   158	            return false;
   159	        }
                   //运行主应用程序
   160	        fRet = AppInitMain();
   161	    }
   162	    catch (const std::exception& e) {
   163	        PrintExceptionContinue(&e, "AppInit()");
   164	    } catch (...) {
   165	        PrintExceptionContinue(nullptr, "AppInit()");
   166	    }
   167
              //如果返回值fRet为false,那么强制结束所有线程;否则就等待所有线程运行结束
   168	    if (!fRet)
   169	    {
   170	        Interrupt();
   171	    } else {
   172	        WaitForShutdown();
   173	    }
            //最后通过ShutDown()完成清理工作
   174	    Shutdown();
   175	
   176	    return fRet;
   177	}
   178	

Probably browsed the realization of the following AppInit function, and found that most of them are parsing the command line parameters of bitcoind. First, parse the-?, -h, -help help information and -version version information, execute the GetDataDir function on line 91 to check whether the data directory Legal, set by the -datadir parameter, the directory mainly stores synchronized block information, wallet information, configuration information, etc. Almost all blockchain operation information is saved here, this function is implemented in src / util.cpp ,code show as below:

581	static fs::path pathCached;
   582	static fs::path pathCachedNetSpecific;
   583	static CCriticalSection csPathCached;
   584	
   585	const fs::path &GetDataDir(bool fNetSpecific)
   586	{
   587	
   588	    LOCK(csPathCached);
   589	
             //判断fNetSpecific是否为true,true使用pathCachedNetSpecific(网络路径),否则使用
             //pathCached(本地路径)
   590	    fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
   591	
              //如果path不为空,返回path
   592	    // This can be called during exceptions by LogPrintf(), so we cache the
   593	    // value so we don't have to do memory allocations after that.
   594	    if (!path.empty())
   595	        return path;
   596	
              //如果有通过-datadir参数指定目录
   597	    if (gArgs.IsArgSet("-datadir")) {
   598	        path = fs::system_complete(gArgs.GetArg("-datadir", ""));
                        //检测参数传入的路径是否为目录,不为目录的话,置空path返回
   599	        if (!fs::is_directory(path)) {
   600	            path = "";
   601	            return path;
   602	        }
              //如果没有通过-datadir参数指定目录,使用GetDefaultDataDir获取默认目录
   603	    } else {
   604	        path = GetDefaultDataDir();
   605	    }
              //如果事网络路径,修改path为BaseParams().DataDir();
   606	    if (fNetSpecific)
   607	        path /= BaseParams().DataDir();
   608	
                     //创建wallets目录
   609	    if (fs::create_directories(path)) {
   610	        // This is the first run, create wallets subdirectory too
   611	        fs::create_directories(path / "wallets");
   612	    }
   613	
   614	    return path;
   615	}

AppInit function line 105: SelectParams (ChainNameFromCommandLine ()); There are three types of networks that the current program runs: Main, Testnet, Regtest
ChainNameFromCommandLine function, implemented in src / chainparamsbase.cpp, the code is as follows

    90	std::string ChainNameFromCommandLine()
    91	{
            //获取命令行-regtest参数,是否为私有网
    92	    bool fRegTest = gArgs.GetBoolArg("-regtest", false);
            //获取命令行-testnet参数,是否为测试网
    93	    bool fTestNet = gArgs.GetBoolArg("-testnet", false);
    94     //不能同时配置两个参数
    95	    if (fTestNet && fRegTest)
    96	        throw std::runtime_error("Invalid combination of -regtest and -testnet.");
           //如果为私网,返回私网
    97	    if (fRegTest)
    98	        return CBaseChainParams::REGTEST;
           //如果为测试网,返回测试网
    99	    if (fTestNet)
   100	        return CBaseChainParams::TESTNET;
           //不是以上两种的返回主网
   101	    return CBaseChainParams::MAIN;
   102	}

ChainNameFromCommandLine
AppInit function line 122: InitLogging function, initial logging and printing method, implemented in src / init.cpp, the code is as follows

void InitLogging()
{
   //通过-printtoconsole参数设置是否打印日志到终端
    fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false);
    //通过-logtimestamps参数设置每一条输出信息附带时间戳,默认值为附带
    fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
   //通过-logtimemicros设置时间戳精确到微秒精度,默认不附加
    fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
   //通过-logips设置输出信息中附加ip地址,默认不附加
    fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);

    LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
    std::string version_string = FormatFullVersion();
#ifdef DEBUG
    version_string += " (debug build)";
#else
    version_string += " (release build)";
#endif
    LogPrintf(PACKAGE_NAME " version %s\n", version_string);
}

AppInit function line 123: InitParameterInteraction (); Other functions after initializing the network parameter function, continue to the next chapter

Published 30 original articles · praised 74 · 230,000 views +

Guess you like

Origin blog.csdn.net/ruiyiin/article/details/104633236