读懂比特币—bitcoin代码分析(三)

发布时间:2024年01月24日

今天分析一下比特币代码:bitcoin/src/init.cpp 中的这个函数:
AppInitParameterInteraction,用于初始化客户端启动时配置文件或者启动命令接收的参数进行解析判断,用于设置客户端的运行环境参数。

bool AppInitParameterInteraction(const ArgsManager& args)
{
    const CChainParams& chainparams = Params();
    // ********************************************************* Step 2: parameter interactions

    // also see: InitParameterInteraction()

    // Error if network-specific options (-addnode, -connect, etc) are
    // specified in default section of config file, but not overridden
    // on the command line or in this chain's section of the config file.
    ChainType chain = args.GetChainType();
    if (chain == ChainType::SIGNET) {
        LogPrintf("Signet derived magic (message start): %s\n", HexStr(chainparams.MessageStart()));
    }
    bilingual_str errors;
    for (const auto& arg : args.GetUnsuitableSectionOnlyArgs()) {
        errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, ChainTypeToString(chain), ChainTypeToString(chain));
    }

    if (!errors.empty()) {
        return InitError(errors);
    }

    // Warn if unrecognized section name are present in the config file.
    bilingual_str warnings;
    for (const auto& section : args.GetUnrecognizedSections()) {
        warnings += strprintf(Untranslated("%s:%i ") + _("Section [%s] is not recognized.") + Untranslated("\n"), section.m_file, section.m_line, section.m_name);
    }

    if (!warnings.empty()) {
        InitWarning(warnings);
    }

    if (!fs::is_directory(args.GetBlocksDirPath())) {
        return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", "")));
    }

    // parse and validate enabled filter types
    std::string blockfilterindex_value = args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
    if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
        g_enabled_filter_types = AllBlockFilterTypes();
    } else if (blockfilterindex_value != "0") {
        const std::vector<std::string> names = args.GetArgs("-blockfilterindex");
        for (const auto& name : names) {
            BlockFilterType filter_type;
            if (!BlockFilterTypeByName(name, filter_type)) {
                return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name));
            }
            g_enabled_filter_types.insert(filter_type);
        }
    }

    // Signal NODE_P2P_V2 if BIP324 v2 transport is enabled.
    if (args.GetBoolArg("-v2transport", DEFAULT_V2_TRANSPORT)) {
        nLocalServices = ServiceFlags(nLocalServices | NODE_P2P_V2);
    }

    // Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled.
    if (args.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
        if (g_enabled_filter_types.count(BlockFilterType::BASIC) != 1) {
            return InitError(_("Cannot set -peerblockfilters without -blockfilterindex."));
        }

        nLocalServices = ServiceFlags(nLocalServices | NODE_COMPACT_FILTERS);
    }

    if (args.GetIntArg("-prune", 0)) {
        if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
            return InitError(_("Prune mode is incompatible with -txindex."));
        if (args.GetBoolArg("-reindex-chainstate", false)) {
            return InitError(_("Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead."));
        }
    }

    // If -forcednsseed is set to true, ensure -dnsseed has not been set to false
    if (args.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED) && !args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED)){
        return InitError(_("Cannot set -forcednsseed to true when setting -dnsseed to false."));
    }

    // -bind and -whitebind can't be set when not listening
    size_t nUserBind = args.GetArgs("-bind").size() + args.GetArgs("-whitebind").size();
    if (nUserBind != 0 && !args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
        return InitError(Untranslated("Cannot set -bind or -whitebind together with -listen=0"));
    }

    // if listen=0, then disallow listenonion=1
    if (!args.GetBoolArg("-listen", DEFAULT_LISTEN) && args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) {
        return InitError(Untranslated("Cannot set -listen=0 together with -listenonion=1"));
    }

    // Make sure enough file descriptors are available
    int nBind = std::max(nUserBind, size_t(1));
    nUserMaxConnections = args.GetIntArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
    nMaxConnections = std::max(nUserMaxConnections, 0);

    nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS + nBind + NUM_FDS_MESSAGE_CAPTURE);

#ifdef USE_POLL
    int fd_max = nFD;
#else
    int fd_max = FD_SETSIZE;
#endif
    // Trim requested connection counts, to fit into system limitations
    // <int> in std::min<int>(...) to work around FreeBSD compilation issue described in #2695
    nMaxConnections = std::max(std::min<int>(nMaxConnections, fd_max - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS - NUM_FDS_MESSAGE_CAPTURE), 0);
    if (nFD < MIN_CORE_FILEDESCRIPTORS)
        return InitError(_("Not enough file descriptors available."));
    nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS - NUM_FDS_MESSAGE_CAPTURE, nMaxConnections);

    if (nMaxConnections < nUserMaxConnections)
        InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));

    // ********************************************************* Step 3: parameter-to-internal-flags
    auto result = init::SetLoggingCategories(args);
    if (!result) return InitError(util::ErrorString(result));
    result = init::SetLoggingLevel(args);
    if (!result) return InitError(util::ErrorString(result));

    nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
    if (nConnectTimeout <= 0) {
        nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
    }

    peer_connect_timeout = args.GetIntArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT);
    if (peer_connect_timeout <= 0) {
        return InitError(Untranslated("peertimeout must be a positive integer."));
    }

    // Sanity check argument for min fee for including tx in block
    // TODO: Harmonize which arguments need sanity checking and where that happens
    if (args.IsArgSet("-blockmintxfee")) {
        if (!ParseMoney(args.GetArg("-blockmintxfee", ""))) {
            return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", "")));
        }
    }

    nBytesPerSigOp = args.GetIntArg("-bytespersigop", nBytesPerSigOp);

    if (!g_wallet_init_interface.ParameterInteraction()) return false;

    // Option to startup with mocktime set (used for regression testing):
    SetMockTime(args.GetIntArg("-mocktime", 0)); // SetMockTime(0) is a no-op

    if (args.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
        nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);

    // Also report errors from parsing before daemonization
    {
        kernel::Notifications notifications{};
        ChainstateManager::Options chainman_opts_dummy{
            .chainparams = chainparams,
            .datadir = args.GetDataDirNet(),
            .notifications = notifications,
        };
        auto chainman_result{ApplyArgsManOptions(args, chainman_opts_dummy)};
        if (!chainman_result) {
            return InitError(util::ErrorString(chainman_result));
        }
        BlockManager::Options blockman_opts_dummy{
            .chainparams = chainman_opts_dummy.chainparams,
            .blocks_dir = args.GetBlocksDirPath(),
            .notifications = chainman_opts_dummy.notifications,
        };
        auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
        if (!blockman_result) {
            return InitError(util::ErrorString(blockman_result));
        }
    }

    return true;
}

这段代码是比特币中的初始化函数
AppInitParameterInteraction?的一部分,用于处理命令行参数之间的交互和设置一些内部标志。让我们逐步解读这段代码:

以下是代码的详细解读:

1. 获取链参数

const CChainParams& chainparams = Params(); 获取当前链的参数,比特币支持多条链,这里通过 Params() 函数获取当前链的参数。

2. 网络配置设置

ChainType chain = args.GetChainType(); 通过 args 参数管理器获取当前链的类型。

如果链的类型是 SIGNET,则记录关于 MessageStart 的信息到日志中。

3. 错误检查

遍历命令行参数中仅适用于特定区块链网络的选项(
args.GetUnsuitableSectionOnlyArgs())。

如果这些网络特定的选项在配置文件的默认部分设置,但在命令行或链配置文件的相应部分未被覆盖,则生成错误信息。

4. 错误处理

如果存在错误信息,通过 InitError 函数返回错误并终止初始化过程。

5. 警告检查

遍历命令行参数中未被识别的配置文件部分(
args.GetUnrecognizedSections())。

如果存在未被识别的部分,生成相应的警告信息。

6. 目录存在性检查

检查指定的区块数据目录是否存在,如果不存在则返回错误。

7. 启用的过滤器类型设置

解析和验证启用的区块过滤器类型,根据 -blockfilterindex 参数设置。

如果参数为空或为 "1",则启用所有区块过滤器类型;如果为 "0",则禁用所有区块过滤器类型。

如果参数为其他值,将按照参数列表启用相应的区块过滤器类型。

8. 设置 P2P 协议版本

如果启用了 BIP324 v2 传输协议(-v2transport 参数),则设置本地服务标志为 NODE_P2P_V2。

9. 设置 Compact Filters 标志

如果启用了 -peerblockfilters 且基本过滤器索引已启用,设置本地服务标志为 NODE_COMPACT_FILTERS。

10. 配置文件参数检查

  • 如果启用了 -prune 模式,检查与之不兼容的其他参数。
  • 如果启用了 -forcednsseed 为真,确保 -dnsseed 不为假。
  1. 监听地址设置检查
  • 检查是否设置了 -bind 或 -whitebind,如果设置了且 -listen 为假,则返回错误。
  1. 系统文件描述符限制检查
  • 确保有足够的文件描述符可用,计算并设置最大连接数限制。
  1. 日志设置
  • 调用 init::SetLoggingCategories 和 init::SetLoggingLevel 函数,设置日志类别和级别。
  1. 连接超时设置
  • 设置连接超时时间。
  1. 处理 Peer 连接超时设置
  • 设置 Peer 连接的超时时间,如果小于等于0,则返回错误。
  1. 区块奖励最小费用检查
  • 对 -blockmintxfee 参数进行合法性检查,确保其为合法的金额格式。
  1. 每个签名操作的字节数设置
  • 设置每个签名操作的字节数。
  1. 钱包初始化接口设置
  • 调用钱包初始化接口的 g_wallet_init_interface.ParameterInteraction() 函数,如果返回假则返回错误。
  1. 模拟时间设置
  • 设置模拟时间,用于回归测试。
  1. Peer Bloom 过滤器设置
  • 如果启用了 -peerbloomfilters 参数,则设置本地服务标志为 NODE_BLOOM。
  1. 应用参数至区块链管理器和区块管理器
  • 使用 ApplyArgsManOptions 函数应用参数至区块链管理器和区块管理器。
  1. 函数返回
  • 如果没有发生错误,返回 true 表示初始化成功。
  • 如果整个初始化过程没有遇到任何错误,最终返回 true 表示初始化成功。

这个函数主要负责处理命令行参数之间的交互,设置一些内部标志,检查配置文件的正确性,以及对一些系统和网络相关的参数进行合法性检查。如果在这个过程中遇到错误,函数将返回 false 并带有相应的错误信息。

总体而言,
AppInitParameterInteraction 函数是比特币初始化过程中的一个重要步骤,确保比特币节点在启动时正确配置和处理各种参数,以确保其正常运行和参与网络。

下面需要重点解释说明一下这个对象:const ArgsManager& args

ArgsManager:参数管理类的说明

class ArgsManager
{
public:
    /**
     * Flags controlling how config and command line arguments are validated and
     * interpreted.
     */
    enum Flags : uint32_t {
        ALLOW_ANY = 0x01,         //!< disable validation
        // ALLOW_BOOL = 0x02,     //!< unimplemented, draft implementation in #16545
        // ALLOW_INT = 0x04,      //!< unimplemented, draft implementation in #16545
        // ALLOW_STRING = 0x08,   //!< unimplemented, draft implementation in #16545
        // ALLOW_LIST = 0x10,     //!< unimplemented, draft implementation in #16545
        DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
        DISALLOW_ELISION = 0x40,  //!< disallow -foo syntax that doesn't assign any value

        DEBUG_ONLY = 0x100,
        /* Some options would cause cross-contamination if values for
         * mainnet were used while running on regtest/testnet (or vice-versa).
         * Setting them as NETWORK_ONLY ensures that sharing a config file
         * between mainnet and regtest/testnet won't cause problems due to these
         * parameters by accident. */
        NETWORK_ONLY = 0x200,
        // This argument's value is sensitive (such as a password).
        SENSITIVE = 0x400,
        COMMAND = 0x800,
    };

protected:
    struct Arg
    {
        std::string m_help_param;
        std::string m_help_text;
        unsigned int m_flags;
    };

    mutable RecursiveMutex cs_args;
    common::Settings m_settings GUARDED_BY(cs_args);
    std::vector<std::string> m_command GUARDED_BY(cs_args);
    std::string m_network GUARDED_BY(cs_args);
    std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
    std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
    bool m_accept_any_command GUARDED_BY(cs_args){true};
    std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
    std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
    mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
    mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
    mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);

    [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);

    /**
     * Returns true if settings values from the default section should be used,
     * depending on the current network and whether the setting is
     * network-specific.
     */
    bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);

 public:
    /**
     * Get setting value.
     *
     * Result will be null if setting was unset, true if "-setting" argument was passed
     * false if "-nosetting" argument was passed, and a string if a "-setting=value"
     * argument was passed.
     */
    common::SettingsValue GetSetting(const std::string& arg) const;

    /**
     * Get list of setting values.
     */
    std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const;

    ArgsManager();
    ~ArgsManager();

    /**
     * Select the network in use
     */
    void SelectConfigNetwork(const std::string& network);

    [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);

    /**
     * Return config file path (read-only)
     */
    fs::path GetConfigFilePath() const;
    void SetConfigFilePath(fs::path);
    [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);

    /**
     * Log warnings for options in m_section_only_args when
     * they are specified in the default section but not overridden
     * on the command line or in a network-specific section in the
     * config file.
     */
    std::set<std::string> GetUnsuitableSectionOnlyArgs() const;

    /**
     * Log warnings for unrecognized section names in the config file.
     */
    std::list<SectionInfo> GetUnrecognizedSections() const;

    struct Command {
        /** The command (if one has been registered with AddCommand), or empty */
        std::string command;
        /**
         * If command is non-empty: Any args that followed it
         * If command is empty: The unregistered command and any args that followed it
         */
        std::vector<std::string> args;
    };
    /**
     * Get the command and command args (returns std::nullopt if no command provided)
     */
    std::optional<const Command> GetCommand() const;

    /**
     * Get blocks directory path
     *
     * @return Blocks path which is network specific
     */
    fs::path GetBlocksDirPath() const;

    /**
     * Get data directory path
     *
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
     */
    fs::path GetDataDirBase() const { return GetDataDir(false); }

    /**
     * Get data directory path with appended network identifier
     *
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
     */
    fs::path GetDataDirNet() const { return GetDataDir(true); }

    /**
     * Clear cached directory paths
     */
    void ClearPathCache();

    /**
     * Return a vector of strings of the given argument
     *
     * @param strArg Argument to get (e.g. "-foo")
     * @return command-line arguments
     */
    std::vector<std::string> GetArgs(const std::string& strArg) const;

    /**
     * Return true if the given argument has been manually set
     *
     * @param strArg Argument to get (e.g. "-foo")
     * @return true if the argument has been set
     */
    bool IsArgSet(const std::string& strArg) const;

    /**
     * Return true if the argument was originally passed as a negated option,
     * i.e. -nofoo.
     *
     * @param strArg Argument to get (e.g. "-foo")
     * @return true if the argument was passed negated
     */
    bool IsArgNegated(const std::string& strArg) const;

    /**
     * Return string argument or default value
     *
     * @param strArg Argument to get (e.g. "-foo")
     * @param strDefault (e.g. "1")
     * @return command-line argument or default value
     */
    std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
    std::optional<std::string> GetArg(const std::string& strArg) const;

    /**
     * Return path argument or default value
     *
     * @param arg Argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir")
     * @param default_value Optional default value to return instead of the empty path.
     * @return normalized path if argument is set, with redundant "." and ".."
     * path components and trailing separators removed (see patharg unit test
     * for examples or implementation for details). If argument is empty or not
     * set, default_value is returned unchanged.
     */
    fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const;

    /**
     * Return integer argument or default value
     *
     * @param strArg Argument to get (e.g. "-foo")
     * @param nDefault (e.g. 1)
     * @return command-line argument (0 if invalid number) or default value
     */
    int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
    std::optional<int64_t> GetIntArg(const std::string& strArg) const;

    /**
     * Return boolean argument or default value
     *
     * @param strArg Argument to get (e.g. "-foo")
     * @param fDefault (true or false)
     * @return command-line argument or default value
     */
    bool GetBoolArg(const std::string& strArg, bool fDefault) const;
    std::optional<bool> GetBoolArg(const std::string& strArg) const;

    /**
     * Set an argument if it doesn't already have a value
     *
     * @param strArg Argument to set (e.g. "-foo")
     * @param strValue Value (e.g. "1")
     * @return true if argument gets set, false if it already had a value
     */
    bool SoftSetArg(const std::string& strArg, const std::string& strValue);

    /**
     * Set a boolean argument if it doesn't already have a value
     *
     * @param strArg Argument to set (e.g. "-foo")
     * @param fValue Value (e.g. false)
     * @return true if argument gets set, false if it already had a value
     */
    bool SoftSetBoolArg(const std::string& strArg, bool fValue);

    // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
    // been set. Also called directly in testing.
    void ForceSetArg(const std::string& strArg, const std::string& strValue);

    /**
     * Returns the appropriate chain type from the program arguments.
     * @return ChainType::MAIN by default; raises runtime error if an invalid
     * combination, or unknown chain is given.
     */
    ChainType GetChainType() const;

    /**
     * Returns the appropriate chain type string from the program arguments.
     * @return ChainType::MAIN string by default; raises runtime error if an
     * invalid combination is given.
     */
    std::string GetChainTypeString() const;

    /**
     * Add argument
     */
    void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);

    /**
     * Add subcommand
     */
    void AddCommand(const std::string& cmd, const std::string& help);

    /**
     * Add many hidden arguments
     */
    void AddHiddenArgs(const std::vector<std::string>& args);

    /**
     * Clear available arguments
     */
    void ClearArgs() {
        LOCK(cs_args);
        m_available_args.clear();
        m_network_only_args.clear();
    }

    /**
     * Get the help string
     */
    std::string GetHelpMessage() const;

    /**
     * Return Flags for known arg.
     * Return nullopt for unknown arg.
     */
    std::optional<unsigned int> GetArgFlags(const std::string& name) const;

    /**
     * Get settings file path, or return false if read-write settings were
     * disabled with -nosettings.
     */
    bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const;

    /**
     * Read settings file. Push errors to vector, or log them if null.
     */
    bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);

    /**
     * Write settings file or backup settings file. Push errors to vector, or
     * log them if null.
     */
    bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const;

    /**
     * Get current setting from config file or read/write settings file,
     * ignoring nonpersistent command line or forced settings values.
     */
    common::SettingsValue GetPersistentSetting(const std::string& name) const;

    /**
     * Access settings with lock held.
     */
    template <typename Fn>
    void LockSettings(Fn&& fn)
    {
        LOCK(cs_args);
        fn(m_settings);
    }

    /**
     * Log the config file options and the command line arguments,
     * useful for troubleshooting.
     */
    void LogArgs() const;

private:
    /**
     * Get data directory path
     *
     * @param net_specific Append network identifier to the returned path
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
     */
    fs::path GetDataDir(bool net_specific) const;

    /**
     * Return -regtest/-signet/-testnet/-chain= setting as a ChainType enum if a
     * recognized chain type was set, or as a string if an unrecognized chain
     * name was set. Raise an exception if an invalid combination of flags was
     * provided.
     */
    std::variant<ChainType, std::string> GetChainArg() const;

    // Helper function for LogArgs().
    void logArgsPrefix(
        const std::string& prefix,
        const std::string& section,
        const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
};

这是一个 C++ 类的定义,名为 ArgsManager。下面逐个部分进行详细解读:

1. Flags 枚举:

enum Flags : uint32_t 定义了一系列用于配置和命令行参数验证及解释的标志。这些标志用于指示参数的类型、允许的值等。

2. Arg 结构体:

struct Arg 包含了参数的帮助信息 (m_help_param)、帮助文本 (m_help_text) 和标志 (m_flags)。

3. 成员变量:

mutable RecursiveMutex cs_args; 用于保护多线程操作的互斥锁。

common::Settings m_settings GUARDED_BY(cs_args); 存储参数的设置值。

std::vector<std::string> m_command GUARDED_BY(cs_args); 存储命令行参数。

其他成员变量用于存储配置文件路径、网络标识、可用参数、命令等信息。

4. 成员函数:

bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); 从输入流中读取配置文件。

bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args); 判断是否使用默认配置。

common::SettingsValue GetSetting(const std::string& arg) const; 获取设置值。

其他函数用于获取不同类型的参数值,如路径、整数、布尔值等。

void SelectConfigNetwork(const std::string& network); 选择配置文件中的网络标识。

bool ParseParameters(int argc, const char* const argv[], std::string& error); 解析命令行参数。

fs::path GetConfigFilePath() const; 获取配置文件路径。

其他函数用于读取、写入、获取配置文件信息等。

5. 命令处理:

struct Command 用于表示命令及其参数。

std::optional<const Command> GetCommand() const; 获取命令及其参数。

6. 路径处理:

fs::path GetDataDir(bool net_specific) const; 获取数据目录路径。

7. 参数设置:

void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat); 添加参数。

void AddCommand(const std::string& cmd, const std::string& help); 添加命令。

void ClearArgs(); 清除可用参数。

std::string GetHelpMessage() const; 获取帮助信息。

std::optional<unsigned int> GetArgFlags(const std::string& name) const; 获取参数标志。

8. 文件读写:

bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const; 获取设置文件路径。

bool ReadSettingsFile(std::vector<std::string>* errors = nullptr); 读取设置文件。

bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const; 写入设置文件。

9. 链类型处理:

ChainType GetChainType() const; 获取链类型。

std::string GetChainTypeString() const; 获取链类型的字符串表示。

std::variant<ChainType, std::string> GetChainArg() const; 获取链参数。

10. 参数日志:

void LogArgs() const; 记录配置文件和命令行参数,用于排查问题。

11. 锁定设置:

template <typename Fn> void LockSettings(Fn&& fn) 通过锁定互斥锁执行一段代码。

该类的目的是提供一个灵活的参数管理器,支持命令行参数的解析、配置文件的读写、参数值的获取等功能,同时支持多线程环境下的安全操作。类中包含了丰富的方法和成员变量,以满足比特币程序对参数管理的需求。

如果看不懂,下面是更加超详细的解读:

  1. 日志处理:
  2. void logArgsPrefix(const std::string& prefix, const std::string& section, const std::map<std::string, std::vector<common::SettingsValue>>& args) const; 是 LogArgs 函数的辅助函数,用于记录配置文件和命令行参数的前缀信息。
  3. 解读具体函数:
  • bool SoftSetArg(const std::string& strArg, const std::string& strValue); 和 bool SoftSetBoolArg(const std::string& strArg, bool fValue); 用于设置参数值,如果参数已经有值则返回 false。
  • void ForceSetArg(const std::string& strArg, const std::string& strValue); 用于强制设置参数值,不管是否已经有值。
  • bool IsArgSet(const std::string& strArg) const; 检查给定的参数是否已经被设置。
  • bool IsArgNegated(const std::string& strArg) const; 检查给定的参数是否以否定形式存在(例如,-nofoo)。
  • std::string GetArg(const std::string& strArg, const std::string& strDefault) const; 获取字符串类型的参数值,如果参数未设置,则返回默认值。
  • std::optional<std::string> GetArg(const std::string& strArg) const; 获取字符串类型的参数值,如果参数未设置,则返回空。
  • fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const; 获取路径类型的参数值,可以指定默认值。
  • int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const; 获取整数类型的参数值,如果参数未设置,则返回默认值。
  • std::optional<int64_t> GetIntArg(const std::string& strArg) const; 获取整数类型的参数值,如果参数未设置,则返回空。
  • bool GetBoolArg(const std::string& strArg, bool fDefault) const; 获取布尔类型的参数值,如果参数未设置,则返回默认值。
  • std::optional<bool> GetBoolArg(const std::string& strArg) const; 获取布尔类型的参数值,如果参数未设置,则返回空。
  • std::vector<std::string> GetArgs(const std::string& strArg) const; 获取一组参数的值。
  • ChainType GetChainType() const; 获取链类型,是主链、测试链还是其他。
  • std::string GetChainTypeString() const; 获取链类型的字符串表示。
  • void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat); 添加新的参数。
  • void AddCommand(const std::string& cmd, const std::string& help); 添加新的命令。
  • void AddHiddenArgs(const std::vector<std::string>& args); 添加隐藏的参数。
  • void ClearArgs(); 清除所有已添加的参数。
  • std::optional<const Command> GetCommand() const; 获取命令及其参数。
  • std::string GetHelpMessage() const; 获取帮助信息。
  • std::optional<unsigned int> GetArgFlags(const std::string& name) const; 获取参数的标志。
  • void LogArgs() const; 记录配置文件和命令行参数,用于调试和排查问题。
  • bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const; 获取设置文件的路径。
  • bool ReadSettingsFile(std::vector<std::string>* errors = nullptr); 读取设置文件。
  • bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const; 写入设置文件。
  • common::SettingsValue GetPersistentSetting(const std::string& name) const; 获取持久化设置,即从配置文件中读取的设置值。
  • template <typename Fn> void LockSettings(Fn&& fn) 通过锁定互斥锁执行一段代码。
  • std::variant<ChainType, std::string> GetChainArg() const; 用于获取命令行参数中指定的链类型。如果指定了有效的链类型(例如 -regtest、-testnet 等),则返回相应的 ChainType 枚举值;如果指定了未知的链类型,返回链的字符串表示;如果未指定链类型,则返回默认的 ChainType::MAIN。
  • GetDataDir(bool net_specific) 函数
  • fs::path GetDataDir(bool net_specific) const; 用于获取数据目录路径。根据 net_specific 参数,可以选择返回具有网络标识符的路径或不带网络标识符的路径。这个函数在不同网络上运行时用于确定数据目录。
  • ReadConfigFiles(std::string& error, bool ignore_invalid_keys) 函数
  • bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false); 用于读取配置文件。它会读取默认配置文件以及任何通过 -conf 命令行选项指定的其他配置文件。通过 ignore_invalid_keys 参数,可以选择是否忽略配置文件中的无效键。
  • GetConfigFilePath() 函数:fs::path GetConfigFilePath() const; 返回配置文件的路径。这个路径是只读的,用户可以通过 -conf 选项指定配置文件的位置。
  • SelectConfigNetwork(const std::string& network) 函数:void SelectConfigNetwork(const std::string& network); 用于选择当前使用的网络。根据给定的网络标识符,它将相应的网络参数应用于配置管理器。
  • ParseParameters(int argc, const char* const argv[], std::string& error) 函数:bool ParseParameters(int argc, const char* const argv[], std::string& error); 用于解析命令行参数。这个函数接受命令行参数的数量和数组,解析并设置相应的配置选项。如果发生错误,会将错误信息写入 error 参数。
  • GetSettingsList(const std::string& arg) 函数:std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const; 获取一组设置值,通常用于处理配置文件中的数组型参数。
  • GetSetting(const std::string& arg) 函数:common::SettingsValue GetSetting(const std::string& arg) const; 获取指定设置的值。结果可能是空(未设置)、true(通过 -setting 参数传递)、false(通过 -nosetting 参数传递)或字符串(通过 -setting=value 参数传递)。
  • UseDefaultSection(const std::string& arg) const 函数:bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args); 用于确定是否应该使用默认配置节的设置值。根据当前的网络和设置是否特定于网络,决定是否使用默认配置。
  • ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys) 函数:bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); 从给定的输入流中读取配置,并将其应用到配置管理器。如果发生错误,将错误信息写入 error 参数。可以选择是否忽略配置文件中的无效键。
  • LockSettings(Fn&& fn) 模板函数:template <typename Fn> void LockSettings(Fn&& fn) 通过锁定互斥锁执行传递的函数对象(通常是 lambda 函数)。确保在设置被锁定的情况下执行。
  • GetChainType() 和 GetChainTypeString() 函数:这两个函数分别用于获取命令行参数中指定的链类型(ChainType 枚举值或字符串表示)。
  • GetArgs, IsArgSet, IsArgNegated, GetArg, GetPathArg, GetIntArg, GetBoolArg 等一系列获取参数值的函数:这些函数用于从命令行参数中获取特定参数的值,提供了方便的接口。
  • ClearPathCache 函数:void ClearPathCache(); 清除缓存的目录路径。
  • GetUnsuitableSectionOnlyArgs 和 GetUnrecognizedSections 函数:std::set<std::string> GetUnsuitableSectionOnlyArgs() const; 返回配置文件中使用了但未在命令行或网络特定部分覆盖的参数的集合。std::list<SectionInfo> GetUnrecognizedSections() const; 返回配置文件中未被识别的部分的信息列表。
  • GetCommand 函数:std::optional<const Command> GetCommand() const; 返回当前命令的信息,包括命令字符串和命令后的参数。
  • GetBlocksDirPath、GetDataDirBase 和 GetDataDirNet 函数:fs::path GetBlocksDirPath() const; 返回区块目录的路径。fs::path GetDataDirBase() const; 返回数据目录的路径。fs::path GetDataDirNet() const; 返回带有网络标识符的数据目录的路径。
  • GetHelpMessage 函数:std::string GetHelpMessage() const; 返回帮助信息,包括已添加参数的说明。
  • GetArgFlags 函数:std::optional<unsigned int> GetArgFlags(const std::string& name) const; 获取指定参数的标志。
  • LogArgs 函数:void LogArgs() const; 记录配置文件和命令行参数,用于调试和排查问题。
  1. ArgsManager 类提供了强大的命令行参数和配置管理功能,支持各种类型的参数(布尔、整数、字符串等)。以下是一些重要的概念和功能:
  • Flags 枚举
    • 定义了一组标志,用于控制配置和命令行参数的验证和解释。其中包括是否允许任何类型的参数、是否禁止否定参数等。
  • Arg 结构
    • 描述了一个参数的帮助文本、标志等信息。
  • 互斥锁 (RecursiveMutex)
    • 使用互斥锁确保在多线程环境下对参数的访问是安全的。
  • Settings 对象
    • 存储了当前的配置设置。
  • Command 结构
    • 包含命令和命令后的参数。
  • 各种获取参数值的函数
    • GetArg、GetIntArg、GetBoolArg 等,提供了获取不同类型参数值的接口。
  • 配置文件操作函数
    • ReadConfigStream、ReadConfigFiles 等,用于读取和解析配置文件。
  • 网络选择和配置
    • SelectConfigNetwork、UseDefaultSection 等,用于选择当前网络和处理网络特定的配置。
  • 参数设置函数
    • SoftSetArg、SoftSetBoolArg 等,用于在参数未设置时设置参数的值。
  • 参数添加和清除函数
    • AddArg、AddCommand、ClearArgs 等,用于动态添加和清除参数。
  • 帮助信息生成函数
    • GetHelpMessage 用于生成参数的帮助信息。
  • 配置文件读写和持久化设置
    • ReadSettingsFile、WriteSettingsFile、GetSettingsPath 等,用于读写配置文件和获取设置的持久化值。

重要总结

这个类设计的目标是提供灵活、易用的接口,方便地处理命令行参数和配置文件,支持多线程环境下的安全访问。通过对各种类型的参数和配置的支持,以及对网络特定设置的处理,使得该类能够适应不同的使用场景和需求。ArgsManager 类提供了丰富的功能,包括参数的添加、获取、设置,命令的处理,配置文件的读写等。通过使用互斥锁保证在多线程环境中的安全操作。该类是比特币程序中参数管理的一个关键组件,为比特币提供了配置的灵活性和可维护性。

文章来源:https://blog.csdn.net/caokun_8341/article/details/135819227
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。