当前位置:bitcoind.cpp=>main=>AppInit

数据目录

此处的数据目录为比特币中的区块、区块链、交易、交易池、钱包以及P2P网络等数据文件所在目录,该目录涉及我们的比特币核心程序是否可以正确运行,因此其正确设置将是至关重要的。

    try
    {
         .....   
    }
        
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(nullptr, "AppInit()");
    }

即如果try中的代码出现异常,则会被catch捕获。下面分析try中的代码。

if (!fs::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
            return false;
        }
        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;
        }
        // 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;
        }

我们首先看第一行的if语句,在该语句中判断了GetDataDir(false)函数返回的数据路径是否为目录名称,如果不是,则打印指定目录不存在的错误提示信息,并且因为数据目录不正确,而导致比特币核心程序无法正常运行,所以返回false,程序退出。

if语句中fs定义是:namespace fs = boost::filesystem。filesystem库是一种可移植的文件系统操作库,可以跨平台的操作目录、文件等,filesystem库的所有内容定义在boost名字空间的一个下级名字空间里,它叫boost::filesytem。

boost::filesystem::path path("");//初始化

boost::filesystem::is_directory(file_path)//判断file_path是否为目录。

数据目录是否正确的关键在于GetDataDir(false)函数获取的目录信息的正确性。那我们来看GetDataDir函数的具体实现。该函数的实现可以在src/util.cpp中找到。(555lines)

const fs::path &GetDataDir(bool fNetSpecific)
{

    LOCK(csPathCached);

    fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;

    // This can be called during exceptions by LogPrintf(), so we cache the
    // value so we don't have to do memory allocations after that.
    if (!path.empty())
        return path;

    if (gArgs.IsArgSet("-datadir")) {
        path = fs::system_complete(gArgs.GetArg("-datadir", ""));
        if (!fs::is_directory(path)) {
            path = "";
            return path;
        }
    } else {
        path = GetDefaultDataDir();
    }
    if (fNetSpecific)
        path /= BaseParams().DataDir();

    fs::create_directories(path);

    return path;
}

该函数的实现流程图:

                                         比特币源代码--5--bitcoind(main函数)数据目录和配置文件(4)

函数详解如下:

1. 根据fNetSpecific确定路径类型,网络路径或本地路径,由false可知为本地路径。

2. 如果该路径不为空,则直接返回。

3. 如果参数中包含“-datadir”,则获取参数路径信息:GetArg("-datadir", ""),否则,获取默认的数据路径。

4. 判断是否为网络路径,是则获取Path中的BaseParams.DataDir()目录,该目录定义在该目录的定义在 src/chainparamsbase.h。由false可知这一段代码不会执行。

5. 最后创建该数据目录并返回。

总体来说:

如果有path路径,则直接返回这个路径;

如果没有,则查看参数gArgs中是否设置了路径,如果设置且正确(如果设置的是网络目录,则转换成本地路径),则在本地创建这个路径,并返回路径;如果设置但错误,则清空path,返回空目录;

在AppInit函数中,

  if (!fs::is_directory(GetDataDir(false)))

程序中对GetDataDir(false)函数传入的参数为false,即使用本地文件目录,如果未设置“-datadir”参数,程序将执行流程图中的GetDefaultDataDir函数,该函数的实现也位于src/util.cpp中。在该函数中我们可以获得比特币后台进程在Windows、Mac以及unix等操作系统下的默认数据目录。具体如下:

fs::path GetDefaultDataDir()
{
    // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
    // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
    // Mac: ~/Library/Application Support/Bitcoin
    // Unix: ~/.bitcoin
#ifdef WIN32
    // Windows
    return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
#else
    fs::path pathRet;
    char* pszHome = getenv("HOME");
    if (pszHome == nullptr || strlen(pszHome) == 0)
        pathRet = fs::path("/");
    else
        pathRet = fs::path(pszHome);
#ifdef MAC_OSX
    // Mac
    return pathRet / "Library/Application Support/Bitcoin";
#else
    // Unix
    return pathRet / ".bitcoin";
#endif
#endif
}

pathCachedNetSpecific、pathCached定义在util.cpp中:(584)

void ClearDatadirCache()
{
    LOCK(csPathCached);

    pathCached = fs::path();
    pathCachedNetSpecific = fs::path();
}

path = fs::system_complete(gArgs.GetArg("-datadir", ""));

转化路径为完整路径。https://link.jianshu.com/?t=https://msdn.microsoft.com/en-us/library/hh874650(v=vs.120).aspx

path /= BaseParams().DataDir();

其中BaseParams函数定义在chainparamsbase.cpp文件。(67)

const CBaseChainParams& BaseParams()
{
    assert(globalChainBaseParams);
    return *globalChainBaseParams;
}

返回的是*globalChainBaseParams,定义也在这个文件里,(65)

static std::unique_ptr<CBaseChainParams> globalChainBaseParams;

配置文件

完成数据目录的创建后,程序将进入配置文件读取部分。

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;
        }

其中,BITCOIN_CONF_FILENAME定义在src/util.cpp,其值为“bitcoin.conf”,表示配置文件。(90)

const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";

ReadConfigFile函数,顾名思义,读取配置文件。定义于util.h文件,具体实现于util.cpp. (601)

void ArgsManager::ReadConfigFile(const std::string& confPath)

GetArg函数,在其实现中首先判断是否存在"-conf"参数,如果存在,则使用ParseParmeters中参数解析结果中保存的参数值作为配置文件,否则使用默认的“bitcoin.conf”。

在获得配置文件名后,我们可以来分析ReadConfigFile函数实现。在该函数实现了配置文件中参数与参数值的读取操作,并将读取的参数信息存入mapArgs与_mapMultiArgs中。

函数最后是为防止配置文件中设置了数据目录参数datadir,通过ClearDatadirCache()函数将数据文件路径参数设置为空目录,这样下次进入GetDataDir()时,我们将会根据新的datadir创建数据目录。

 

相关文章:

  • 2021-06-10
  • 2022-01-21
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-26
猜你喜欢
  • 2021-11-11
  • 2021-09-25
  • 2021-05-29
  • 2021-06-14
  • 2021-09-13
  • 2022-02-07
  • 2021-10-22
相关资源
相似解决方案