开始研读比特币2

上次读到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();初始化网络参数函数后的其他函数,下篇继续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容