chain_plugin参数处理完毕后,设置方法提供者(并没有找到该provider的应用)。接着转播信号到频道,为chain_plugin_impl的唯一指针my的connection属性赋值,创建信号槽。
pre_accepted_block_connection,连接信号pre_accepted_block,更新loaded_checkpoints区块检查点位置。
accepted_block_header_connection,连接信号accepted_block_header,承认区块头信号。
accepted_block_connection,连接信号accepted_block,承认区块信号。
irreversible_block_connection,连接信号irreversible_block,区块不可逆。
accepted_transaction_connection,连接信号accepted_transaction,承认事务。
applied_transaction_connection,连接信号applied_transaction,应用事务。
accepted_confirmation_connection,连接信号accepted_confirmation,承认确认。
chain_plugin的插件初始化工作完毕,主要是对chain_plugin的配置参数的处理,以及信号槽的实现。
chain_plugin::plugin_startupchain_plugin插件的启动,首先是快照的处理,这部分在快照的内容中有介绍,是根据nodeos过来的快照参数,判断是否要加入快照参数调用controller的startup。这期间如有捕捉到异常,则执行controller的reset重置操作。然后根据controller的属性输出链日志信息。
chain_plugin::plugin_shutdown重置所有的信号槽,重置controller。
四、RPC接口实现外部rpc调用通过chain_api_plugin插件包裹的接口服务,内部接口的实现是在chain_plugin中,对应关系是在chain_api_plugin的接口列表,通过函数名字匹配。
1. 获取基本信息 get_info // 返回值为read_only的实体成员get_info_results结构的实例。 read_only::get_info_results read_only::get_info(const read_only::get_info_params&) const { const auto& rm = db.get_resource_limits_manager(); return { // 以下字段都与get_info_results结构匹配,最终构造出get_info_results实例返回。 eosio::utilities::common::itoh(static_cast<uint32_t>(app().version())), // server_version db.get_chain_id(), // chain_id db.fork_db_head_block_num(), // head_block_num db.last_irreversible_block_num(), // last_irreversible_block_num db.last_irreversible_block_id(), // last_irreversible_block_id db.fork_db_head_block_id(), // head_block_id db.fork_db_head_block_time(), // head_block_time db.fork_db_head_block_producer(), // head_block_producer rm.get_virtual_block_cpu_limit(), // virtual_block_cpu_limit rm.get_virtual_block_net_limit(), // virtual_block_net_limit rm.get_block_cpu_limit(), // block_cpu_limit rm.get_block_net_limit(), // block_net_limit //std::bitset<64>(db.get_dynamic_global_properties().recent_slots_filled).to_string(), // recent_slots //__builtin_popcountll(db.get_dynamic_global_properties().recent_slots_filled) / 64.0, // participation_rate app().version_string(), // server_version_string }; }可以看到get_info_results的部分字段是通过read_only::db对象获取,还有一部分资源相关的内容是通过db的资源限制管理器获得,而关于版本方面的数据是从application实例获得。
2. 获取区块信息 get_block // 特殊的是,此处并没有创建一个get_block_result的结构体作为返回值的容器,是利用了variant语法将signed_block_ptr转换成可输出的状态。 fc::variant read_only::get_block(const read_only::get_block_params& params) const { signed_block_ptr block; // 如果参数block_num_or_id为空或者block_num_or_id的长度大于64,属于非法参数不处理,会报错。 EOS_ASSERT(!params.block_num_or_id.empty() && params.block_num_or_id.size() <= 64, chain::block_id_type_exception, "Invalid Block number or ID, must be greater than 0 and less than 64 characters" ); try { // 通过variant语法将参数block_num_or_id类型擦除然后通过as语法转化为block_id_type类型, block = db.fetch_block_by_id(fc::variant(params.block_num_or_id).as<block_id_type>()); if (!block) {// 如果通过id的方法获得的block为空,则尝试使用区块号的方式获取。 block = db.fetch_block_by_number(fc::to_uint64(params.block_num_or_id));// 利用to_uint64将参数转型。 }// 如果获取失败,抛出异常,无效的参数block_num_or_id } EOS_RETHROW_EXCEPTIONS(chain::block_id_type_exception, "Invalid block ID: ${block_num_or_id}", ("block_num_or_id", params.block_num_or_id)) EOS_ASSERT( block, unknown_block_exception, "Could not find block: ${block}", ("block", params.block_num_or_id)); // 通过校验,开始返回对象。 fc::variant pretty_output; // i将结果block的数据通过resolver解析到pretty_output abi_serializer::to_variant(*block, pretty_output, make_resolver(this, abi_serializer_max_time), abi_serializer_max_time); // 引用区块的前缀设置 uint32_t ref_block_prefix = block->id()._hash[1]; return fc::mutable_variant_object(pretty_output.get_object()) ("id", block->id()) ("block_num",block->block_num()) ("ref_block_prefix", ref_block_prefix); }