公信宝gxs核心代码阅读笔记1-刚刚开始(霜之小刀)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lihn1987/article/details/79004811

公信宝gxs核心代码阅读笔记1-刚刚开始(霜之小刀)

欢迎转载和引用,若有问题请联系
若有疑问,请联系
Email : [email protected]
QQ:2279557541


1、测试环境简介

这里我使用的是mbp,苹果的开发环境,由于公信宝的工程师都使用的是苹果的环境,所以使用苹果环境编译源码比较容易通过,另外linux的环境应该也是可以的,不过我编译没有成功,如果一定需要在linux环境下编译的,遇到可以在去公信宝的开发社区里面去咨询。公信宝的工程师们还是相当热情的。
我简单看了下,要看懂这部分代码的基本框架并不需要太多的前置知识,主要就是c++,boost,cmake就足够了。
而关于代码阅读这块,出于我个人的习惯,我使用的是qtcreator导入CMakeList.txt

2、代码的下载与编译

其实在公信宝的github上是有说如何编译的,位置在

https://github.com/gxchain/gxb-core

我就把里面的内容转述过来就好了
首先是利用brew安装工具

brew install wget cmake git openssl autoconf automake doxygen libtool

然后是编译代码

git clone https://github.com/gxchain/gxb-core.git
cd gxb-core
git submodule update --init --recursive
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make

上面是官方的原文
不过在这里插一点其他的,
一个是我编译的时候碰到点问题,主要是在cmake这块,官方文档上提到的

-DOPENSSL_INCLUDE_DIR, -DOPENSSL_SSL_LIBRARY, and -DOPENSSL_CRYPTO_LIBRARY -DBOOST_ROOT

等参数我全都用上了才能编译通过,这些参数简单来说就是用来指定2个第三方库的路径的,分别是openssl和boost。


另外,我们看到了开始brew了openssl的库,但是这里的boost库从哪里来呢?
直接执行源码中的script/boost_install.sh就可以了,这个会自动的下载并编译boost库,时间会比较长要有心理准备。


还有,如果直接make,编译速度会很慢,这里建议使用

make -j4

由于我的笔记本是双核4线程的,所以这里使用j4这个参数,比单线程编译确实是快的不是一点点。

3、main.cpp入口程序概览

using namespace graphene;
namespace bpo = boost::program_options;
//==========
#include <QApplication>
#include "MainWidget.h"
/*int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWidget widget;
    widget.show();
    return app.exec();
}*/
void write_default_logging_config_to_stream(std::ostream& out, bool log_file = false);
fc::optional<fc::logging_config> load_logging_config_from_ini_file(const fc::path& config_ini_filename);

int main(int argc, char** argv)
{
   app::application* node = new app::application();
   fc::oexception unhandled_exception;
   try {
      //这里定义了两个选项参数
      bpo::options_description app_options("Graphene Witness Node");
      bpo::options_description cfg_options("Graphene Witness Node");
      app_options.add_options()
            ("help,h", "Print this help message and exit.")
            ("data-dir,d", bpo::value<boost::filesystem::path>()->default_value("witness_node_data_dir"), "Directory containing databases, configuration file, etc.")
            ;

      bpo::variables_map options;
      //这里是在注册各个模块,其实呢,就是把模块同note引擎关联起来,让note起到管理者和连接器的作用
      auto witness_plug = node->register_plugin<witness_plugin::witness_plugin>();
      auto debug_witness_plug = node->register_plugin<debug_witness_plugin::debug_witness_plugin>();
      auto history_plug = node->register_plugin<account_history::account_history_plugin>();
      auto market_history_plug = node->register_plugin<market_history::market_history_plugin>();
      auto delayed_plug = node->register_plugin<delayed_node::delayed_node_plugin>();

      try
      {

         bpo::options_description cli, cfg;
         //在note中填充命令行选项和配置选项,
         //另外上面不是注册了这么多个插件么,
         //这里也会将各个插件需要的命令行选项和配置选项填充进来
         node->set_program_options(cli, cfg);
         //把填充过的cli的参数,添加到app_option里面
         app_options.add(cli);
         //配置选项都加到cfg中
         cfg_options.add(cfg);
         //通过app_option解析命令行,并保存到option中,以备后面使用,这个option呢
         bpo::store(bpo::parse_command_line(argc, argv, app_options), options);
      }
      catch (const boost::program_options::error& e)
      {//补货异常,并打印输出,然后返回
        std::cerr << "Error parsing command line: " << e.what() << "\n";
        return 1;
      }
      //==================================
      //下面都是对参数的处理
      if( options.count("help") )
      {//help参数的处理,直接打印出所有参数及其描述
         std::cout << app_options << "\n";
         return 0;
      }

      if( options.count("version") )
      {//版本信息的处理
         std::cout << "Version: " << graphene::utilities::git_revision_description << "\n";
         std::cout << "SHA: " << graphene::utilities::git_revision_sha << "\n";
         std::cout << "Timestamp: " << fc::get_approximate_relative_time_string(fc::time_point_sec(graphene::utilities::git_revision_unix_timestamp)) << "\n";
         return 0;
      }

      fc::path data_dir;
      if( options.count("data-dir") )
      {//数据存储目录的处理,这里应该是区块链数据
         data_dir = options["data-dir"].as<boost::filesystem::path>();
         if( data_dir.is_relative() )
            data_dir = fc::current_path() / data_dir;
      }

      fc::path config_ini_path = data_dir / "config.ini";
      if( fc::exists(config_ini_path) )
      {//配置文件的处理
         boost::container::flat_set<std::string> seen;
         bpo::options_description unique_options("Graphene Witness Node");
         for( const boost::shared_ptr<bpo::option_description> od : cfg_options.options() )
         {//对cfg_options进行一道过滤,去除重复的参数,然后保存到unique_option
            const std::string name = od->long_name();
            if( seen.find(name) != seen.end() ) continue;
            seen.insert(name);
            unique_options.add( od );
         }

         // 将config.ini文件中的参数也保存到options中
         bpo::store(bpo::parse_config_file<char>(config_ini_path.preferred_string().c_str(), unique_options, true), options);

         // try to get logging options from the config file.
         try
         {//通过配置文件配置日志模块
            fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
            if (logging_config)
               fc::configure_logging(*logging_config);
         }
         catch (const fc::exception&)
         {
            wlog("Error parsing logging config from config file ${config}, using default config", ("config", config_ini_path.preferred_string()));
         }
      }
      else
      {
         ilog("Writing new config file at ${path}", ("path", config_ini_path));
         if( !fc::exists(data_dir) )
            fc::create_directories(data_dir);

         boost::container::flat_set<std::string> seen;
         std::ofstream out_cfg(config_ini_path.preferred_string());
         for( const boost::shared_ptr<bpo::option_description> od : cfg_options.options() )
         {//遍历配置文件
            //首先将不为空的描述进行注释进行注释
            if( !od->description().empty() )
               out_cfg << "# " << od->description() << "\n";
            boost::any store;
            //对没有默认值的参数输出“#xxx=”类似于提示吧
            if( !od->semantic()->apply_default(store) )
               out_cfg << "# " << od->long_name() << " = \n";
            else {
               /*其他的直接按照以下格式输出

                # 描述符
                参数名称 = 参数值

               */
               const std::string name = od->long_name();
               if( seen.find(name) != seen.end() ) continue;
               seen.insert(name);
               auto example = od->format_parameter();
               if( example.empty() )
                  // This is a boolean switch
                  out_cfg << od->long_name() << " = " << "false\n";
               else {
                  // The string is formatted "arg (=<interesting part>)"
                  example.erase(0, 6);
                  example.erase(example.length()-1);
                  out_cfg << od->long_name() << " = " << example << "\n";
               }
            }
            out_cfg << "\n";
         }
      //通过log-file这个参数,把log的一些参数写到配置文件中
      if (options.count("log-file"))
         write_default_logging_config_to_stream(out_cfg, true);
      else
         write_default_logging_config_to_stream(out_cfg, false);

         out_cfg.close();
         // read the default logging config we just wrote out to the file and start using it
         fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
         if (logging_config)
            fc::configure_logging(*logging_config);
      }
      //===============================
      //下面是对各前面加载插件的初始化啊,之类的
      bpo::notify(options);
      node->initialize(data_dir, options);
      node->initialize_plugins( options );

      node->startup();
      node->startup_plugins();

      fc::promise<int>::ptr exit_promise = new fc::promise<int>("UNIX Signal Handler");

      fc::set_signal_handler([&exit_promise](int signal) {
         elog( "Caught SIGINT attempting to exit cleanly" );
         exit_promise->set_value(signal);
      }, SIGINT);

      fc::set_signal_handler([&exit_promise](int signal) {
         elog( "Caught SIGTERM attempting to exit cleanly" );
         exit_promise->set_value(signal);
      }, SIGTERM);

      ilog("Started witness node on a chain with ${h} blocks.", ("h", node->chain_database()->head_block_num()));
      ilog("Chain ID is ${id}", ("id", node->chain_database()->get_chain_id()) );

      int signal = exit_promise->wait();
      ilog("Exiting from signal ${n}", ("n", signal));
      node->shutdown_plugins();
      node->shutdown();
      delete node;
      return 0;
   } catch( const fc::exception& e ) {
      // deleting the node can yield, so do this outside the exception handler
      unhandled_exception = e;
   }

   if (unhandled_exception)
   {
      elog("Exiting with error:\n${e}", ("e", unhandled_exception->to_detail_string()));
      node->shutdown();
      delete node;
      return 1;
   }
}

可以看出整个main函数还是不难理解的
基本就是

  • 配置命令行参数
  • 配置配置文件参数
  • 注册各个模块
  • 配置和启动各个模块

代码中我加了不少的注释,写的都是看这个文件大概看得懂的部分,具体的,会在后面对每一段做一一的解释,今天就写这么多了
另外这一块涉及到了不少boost的相关内容,我也没有详细解释,后面对小块进行说明的时候对于boost的部分我也尽量说说他的意思

猜你喜欢

转载自blog.csdn.net/lihn1987/article/details/79004811
今日推荐