EOS行为核心:解析插件chain_plugin

EOS提供了大量的rpc接口,其中功能性最强,使用最频繁的一部分接口是EOS的行为核心,由chain_api_plugin提供,具体实现是在chain_plugin。

关键字:EOS,区块链,chain_plugin,chain_api_plugin,rpc,FC_REFLECT,反射,method模板,channel模板

一、接口列表chain_api_plugin

rpc调用逻辑,chainbase数据库底层原理,nodeos启动流程,plugin生命周期在前文都有介绍。本节直接研究chain_plugin的内容,研究入口会从chain_api_plugin中暴漏的rpc接口切入,这些接口是非常熟悉的,因为之前演练cleos相关命令时调用的也是rpc。首先展示一下所有的接口内容:

_http_plugin.add_api({ CHAIN_RO_CALL(get_info, 200l), CHAIN_RO_CALL(get_block, 200), CHAIN_RO_CALL(get_block_header_state, 200), CHAIN_RO_CALL(get_account, 200), CHAIN_RO_CALL(get_code, 200), CHAIN_RO_CALL(get_code_hash, 200), CHAIN_RO_CALL(get_abi, 200), CHAIN_RO_CALL(get_raw_code_and_abi, 200), CHAIN_RO_CALL(get_raw_abi, 200), CHAIN_RO_CALL(get_table_rows, 200), CHAIN_RO_CALL(get_table_by_scope, 200), CHAIN_RO_CALL(get_currency_balance, 200), CHAIN_RO_CALL(get_currency_stats, 200), CHAIN_RO_CALL(get_producers, 200), CHAIN_RO_CALL(get_producer_schedule, 200), CHAIN_RO_CALL(get_scheduled_transactions, 200), CHAIN_RO_CALL(abi_json_to_bin, 200), CHAIN_RO_CALL(abi_bin_to_json, 200), CHAIN_RO_CALL(get_required_keys, 200), CHAIN_RO_CALL(get_transaction_id, 200), CHAIN_RW_CALL_ASYNC(push_block, chain_apis::read_write::push_block_results, 202), CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202), CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202) });

这些接口可以分为两类,一类是通过宏CHAIN_RO_CALL调用的,另一类是通过宏CHAIN_RW_CALL_ASYNC调用。

(1) CHAIN_RO_CALL #define CHAIN_RO_CALL(call_name, http_response_code) CALL(chain, ro_api, chain_apis::read_only, call_name, http_response_code)

采用同步只读的方式调用宏CALL。call_name是调用的函数名,http_response_code是响应码。下面进入宏CALL。

/** * @attention 目前调用CALL函数的只有read_only应用。 * @param api_name "chain' * @param api_handle app().get_plugin<chain_plugin>().get_read_only_api(); * @param api_namespace chain_apis::read_only * @param call_name -INHERIT * @param http_response_code -INHERIT */ #define CALL(api_name, api_handle, api_namespace, call_name, http_response_code) \ {std::string("/v1/" #api_name "http://www.likecs.com/" #call_name), \ /*拼接接口url::port/v1/chain/{call_name}*/ \ /* * @param body:http请求体 * @param cb:回调函数,用于返回处理结果 */ \ [api_handle](string, string body, url_response_callback cb) mutable { \ api_handle.validate(); \ try { \ if (body.empty()) body = "{}"; \ /* * api_handle为chain_plugin中read_only类的实例 * call_name为函数名,实现体找chain_plugin.cpp文件 * 函数参数1个:此处规定了一个命名规则,接口名加入后缀_param即为请求参数结构 */ \ auto result = api_handle.call_name(fc::json::from_string(body).as<api_namespace::call_name ## _params>()); \ /*回调函数返回处理结果,此处也规定了一个命名规则,接口名加入后缀_result即为返回结构,转化为json的格式返回。*/ \ cb(http_response_code, fc::json::to_string(result)); \ } catch (...) { \ /*捕捉到异常,调用http_plugin的异常处理函数handle_exception*/ \ http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ } \ } api_handle参数

同步只读的请求传入的api_handle参数值为ro_api变量,该变量是在chain_api_plugin插件启动chain_api_plugin::plugin_startup时(插件的生命周期前文已有介绍)初始化的,

auto ro_api = app().get_plugin<chain_plugin>().get_read_only_api();

app()函数以及与application类相关的内容前文已经介绍过,通过get_plugin<chain_plugin>获取chain_plugin的实例,然后调用其成员函数get_read_only_api(),

chain_apis::read_only get_read_only_api() const { return chain_apis::read_only(chain(), get_abi_serializer_max_time()); } //注意const修饰符,函数体内返回值是不可修改的。

返回的是chain_apis::read_only构造函数返回的read_only实例。类read_only中包含了所有基于只读机制的接口实现,与上面接口列表中声明的保持一致。

read_only(const controller& db, const fc::microseconds& abi_serializer_max_time) : db(db), abi_serializer_max_time(abi_serializer_max_time) {}

因此,最后传入CALL宏的api_handle参数值实际就是这个类read_only的实例。之后使用该实例去调用call_name,就是简单的实例调用自身成员函数(一般这个成员函数是声明和实现都有的)的逻辑了。

(2) CHAIN_RW_CALL_ASYNC #define CHAIN_RW_CALL_ASYNC(call_name, call_result, http_response_code) CALL_ASYNC(chain, rw_api, chain_apis::read_write, call_name, call_result, http_response_code)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssfzz.html