EOS源码解析--programs(应用层)

一、代码整体架构
主要包括应用层、插件层、库函数层和智能合约层。代码整体架构:
1.1 programs(应用层):
cloes:
nodeos:服务器端,也就是区块生产节点,用于接受客户端的远端请求,并打包区块,主要包含四个插件,chain_plugin、http_plugin、net_plugin、producer_plugin。
keosd:钱包管理模块,主要包括三个插件,wallet_plugin、wallet_api_plugin、http_plugin。
1.2 plugins(插件层)
支持动态加载相关组件,实现了应用层的业务逻辑和区块链底层实现的解耦,同时为应用开发者提供友好的API接口,比较重要的有以下几个插件:chain_plugin、http_plugin
1.3 libraries(库函数层)
为应用层和插件层提供基础能力,实现了区块链的底层关键技术,例如,交易处理,生产区块,加密功能,文件IO操作,网络通信能力等
1.4 constracts(智能合约层)
主要包含一些智能合约的示例代码。
二、programs(应用层)
2.1 nodeos:
位置:programs/nodeos/main.cpp
从main函数开始,程序大致分为三部分:选项配置、加载插件、启动程序。加载chain_plugin, http_plugin, net_plugin, producer_plugin插件

int main(int argc, char** argv)
{
   try {
      //选项配制
      app().set_version(eosio::nodeos::config::version);
      app().register_plugin<history_plugin>();

      auto root = fc::app_path();
      app().set_default_data_dir(root / "eosio/nodeos/data" );
      app().set_default_config_dir(root / "eosio/nodeos/config" );
      //加载插件
      if(!app().initialize<chain_plugin, http_plugin, net_plugin, producer_plugin>(argc, argv))
         return INITIALIZE_FAIL;
      initialize_logging();
      ilog("nodeos version ${ver}", ("ver", eosio::utilities::common::itoh(static_cast<uint32_t>(app().version()))));
      ilog("eosio root is ${root}", ("root", root.string()));
      //启动程序
      app().startup();
      app().exec();
   } catch( const extract_genesis_state_exception& e ) {
      return EXTRACTED_GENESIS;

2.2 cleos
(1)位置:programs/cleos/main.cpp
cleos是一个命令行工具,用于和区块链数据交互以及管理钱包,从main函数开始,
程序大致分为三部分:创建主命令和选项、创建子命令和选项、解析用户参数后调用对应命令的回调函数。

   //创建主命令,并添加主选项
   CLI::App app{"Command Line Interface to EOSIO Client"};
   app.require_subcommand();
   app.add_option( "-H,--host", obsoleted_option_host_port, localized("the host where nodeos is running") )->group("hidden");
   app.add_option( "-p,--port", obsoleted_option_host_po
   ....
   ....
   //创建子命令
      auto version = app.add_subcommand("version", localized("Retrieve version information"), false);
   version->require_subcommand();

   version->add_subcommand("client", localized("Retrieve version information of the client"))->set_callback([] {
     std::cout << localized("Build version: ${ver}", ("ver", eosio::client::config::version_str)) << std::endl;
   });

   // 为主命令创建create子命令
     auto create_key = create->add_subcommand("key", localized("Create a new keypair and print the public and private keys"))->set_callback( [&r1](){
      if( r1 ) {
         auto pk    = private_key_type::generate_r1();
         auto privs = string(pk);
         auto pubs  = string(pk.get_public_key());
         std::cout << localized("Private key: ${key}", ("key",  privs) ) << std::endl;
         std::cout << localized("Public key: ${key}", ("key", pubs ) ) << std::endl;
      } else {
         auto pk    = private_key_type::generate();
         auto privs = string(pk);
         auto pubs  = string(pk.get_public_key());
         std::cout << localized("Private key: ${key}", ("key",  privs) ) << std::endl;
         std::cout << localized("Public key: ${key}", ("key", pubs ) ) << std::endl;
      }
   });
   create_key->add_flag( "--r1", r1, "Generate a key using the R1 curve (iPhone), instead of the K1 curve (Bitcoin)"  );
   // 为create子命令创建子命令account
   auto createAccount = create_account_subcommand( create, true /*simple*/ );
   ...
   ...
   //解析用户命令参数,调用对应的回调函数
   try {
       app.parse(argc, argv);
   } catch (const CLI::ParseError &e) {
       return app.exit(e);
   } catch (const explained_exception& e) {
      return 1;
   } catch (connection_exception& e) {
      if (verbose_errors) {
         elog("connect error: ${e}", ("e", e.to_detail_string()));
      }
   } catch (const fc::exception& e) {
      // attempt to extract the error code if one is present
      if (!print_recognized_errors(e, verbose_errors)) {
         // Error is not recognized
         if (!print_help_text(e) || verbose_errors) {
            elog("Failed with error: ${e}", ("e", verbose_errors ? e.to_detail_string() : e.to_string()));
         }
      }
      return 1;
   }

(2) 创建命令
位置:eos/programs/cleos/CLI11.hpp

//创建主命令
  Option  *add_option(std::string name, callback_t callback, std::string description = "", bool defaulted = false) {
        Option myopt{name, description, callback, defaulted, this};
            if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) {
               return *v == myopt;
           }) == std::end(options_)) {
            options_.emplace_back();
            Option_p &option = options_.back();
            option.reset(new Option(name, description, callback, defaulted, this));
            return option.get();
        } else
            throw OptionAlreadyAdded(myopt.get_name());
    }
  //创建子命令
       /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false
    App *add_subcommand(std::string name, std::string description = "", bool help = true) {
        subcommands_.emplace_back(new App(description, help, detail::dummy));
        subcommands_.back()->name_ = name;
        subcommands_.back()->allow_extras();
        subcommands_.back()->parent_ = this;
        subcommands_.back()->ignore_case_ = ignore_case_;
        subcommands_.back()->fallthrough_ = fallthrough_;
        for(const auto &subc : subcommands_)
            if(subc.get() != subcommands_.back().get())
                if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
                    throw OptionAlreadyAdded(subc->name_);
        return subcommands_.back().get();
    }

(3)解析用户参数
设置完所有的命令、选项和回调函数后,开始解析用户输入的参数,并匹配到对应的命令,执行相应功能。

   try {
       app.parse(argc, argv);
   } catch (const CLI::ParseError &e) {
       return app.exit(e);
   } catch 

将用户参数解析后保存在std::vector args中,通过parse(args)做进一步解析:
eos/programs/cleos/CLI11.hpp

   /// Parses the command line - throws errors
    /// This must be called after the options are in but before the rest of the program.
    std::vector<std::string> parse(int argc, char **argv) {
        name_ = argv[0];
        std::vector<std::string> args;
        for(int i = argc - 1; i > 0; i--)
            args.emplace_back(argv[i]);
        return parse(args);
    }

2.3 keosd
keosd钱包管理模块的处理流程,从main 函数开始,程序大致分为三部分:选项配置、加载插件、启动程序,主要的功能由wallet_plugin、wallet_api_plugin、http_plugin这三个插件完成。
位置:programs/keosd/main.cpp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值