美文网首页
开始研读比特币2

开始研读比特币2

作者: NanoLeak | 来源:发表于2018-02-28 23:29 被阅读0次

    上次读到src/bitcoind.cpp 中AppInit,大概的流程是

    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,启动失败中断操作和清理工作
    

    AppInit函数代码如下:
    代码如下:

        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  
    
    

    大概浏览了以下AppInit函数的实现,发现大部分都是在解析bitcoind的命令行参数,首先解析-?,-h,-help帮助信息和-version版本信息,91行执行GetDataDir函数,检查数据目录是否合法,通过-datadir参数进行设置,该目录下主要保存同步的区块信息,钱包信息,配置信息等等几乎所有的区块链运行信息都保存在这里,这个函数在src/util.cpp中实现,代码如下:

    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函数105行: SelectParams(ChainNameFromCommandLine());设置的当前程序运行的网络,有三种:Main,Testnet,Regtest
    ChainNameFromCommandLine函数,在src/chainparamsbase.cpp中实现,代码如下

        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函数122行:InitLogging函数,初始化日志记录以及打印方式,在src/init.cpp中实现,代码如下

    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函数123行: InitParameterInteraction();初始化网络参数函数后的其他函数,下篇继续

    相关文章

      网友评论

          本文标题:开始研读比特币2

          本文链接:https://www.haomeiwen.com/subject/zoxvxftx.html