EOS行为核心:解析插件chain_plugin (6)

abi数据,通过abi_serializer将账户的abi数据解析出来。

read_only::get_code_results read_only::get_code( const get_code_params& params )const { get_code_results result; result.account_name = params.account_name; const auto& d = db.db(); const auto& accnt = d.get<account_object,by_name>( params.account_name );// 从controller状态库中获取账户信息 // 当前默认不支持返回wast数据 EOS_ASSERT( params.code_as_wasm, unsupported_feature, "Returning WAST from get_code is no longer supported" ); if( accnt.code.size() ) { if (params.code_as_wasm) { // 完整的原始账户的code的数据 result.wasm = string(accnt.code.begin(), accnt.code.end()); } // 获得code的哈希值:将账户信息下的code的data和size值做sha256哈希得到的值 result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); } // 获取账户的abi数据:通过abi_serializer将账户的abi数据解析出来。 abi_def abi; if( abi_serializer::to_abi(accnt.abi, abi) ) { result.abi = std::move(abi); } return result; } 6. 获得账户的code哈希值 get_code_hash

实现方法参照get_code,返回数据只包括code的hash值。

7. 获得账户的abi数据 get_abi

实现方法参照get_code,返回数据只包括账户的abi数据。

8. 获得账户的原始code和abi数据 get_raw_code_and_abi read_only::get_raw_code_and_abi_results read_only::get_raw_code_and_abi( const get_raw_code_and_abi_params& params)const { get_raw_code_and_abi_results result; result.account_name = params.account_name; const auto& d = db.db(); const auto& accnt = d.get<account_object,by_name>(params.account_name); result.wasm = blob{{accnt.code.begin(), accnt.code.end()}}; // 原始wasm值,完整取出即可。 result.abi = blob{{accnt.abi.begin(), accnt.abi.end()}}; // 原始abi值,完整取出即可。 return result; } 9. 获得账户的原始abi数据 get_raw_abi

实现方法参照get_raw_code_and_abi,返回数据只包括账户的原始abi数据。

10. 获得一条状态库表的值 get_table_rows

首先查看该接口的传入参数的数据结构:

struct get_table_rows_params { bool json = false; // 是否是json的格式 name code; // 传入code值,即拥有该table的账户名 string scope; // 传入scope值,即查询条件 name table; // 传入table的名字 string table_key; // table主键 string lower_bound; // 设置检索数据的下限,默认是first string upper_bound; // 设置检索数据的上限,默认是last uint32_t limit = 10; // 数据结果的最大条目限制 string key_type; // 通过指定键的数据类型,定位查询依赖的键 string index_position; // 通过传入键的位置,,定位查询依赖的键。1 - 主键(first), 2 - 二级索引 (multi_index定义), 3 - 三级索引,等等 string encode_type{"dec"}; //加密类型,有十进制还是十六进制,默认是十进制dec。 };

除了code、scope、table以外都是可选的参数,这三个参数是定位检索数据的关键,所以不可省略。下面来看该接口的返回值类型:

struct get_table_rows_result { vector<fc::variant> rows; // 数据集合。一行是一条,无论是十六进制加密串还是解析成json对象,都代表一行。 bool more = false; // 如果最后显示的元素(受制于limit)并不是数据库中最后一个,则该字段会置为true };

进入接口实现的函数体,内容较多。首先通过传入参数对象中的index_position字段来确定查询依赖的键,这是通过函数get_table_index_name完成的工作,同时会修改primary原对象的值,返回table名字的同时告知是否是主键(table的键的名字是与table名字相关的)。
接着,如果是主键:

// 对比入参对象的table名字是否与通过index反查的table名字保持一致。 EOS_ASSERT( p.table == table_with_index, chain::contract_table_query_exception, "Invalid table name ${t}", ( "t", p.table )); auto table_type = get_table_type( abi, p.table );// 获得table类型 if( table_type == KEYi64 || p.key_type == "i64" || p.key_type == "name" ) {//支持这三种table类型 return get_table_rows_ex<key_value_index>(p,abi);// 具体检索table的函数。 } // 如果是已支持的三种table类型之外的,则会报错。 EOS_ASSERT( false, chain::contract_table_query_exception, "Invalid table type ${type}", ("type",table_type)("abi",abi));

具体检索table的函数get_table_rows_ex,这是非常重要的一个函数,需要源码分析:

/** * 检索table的核心函数 * @tparam IndexType 模板类,支持不同的索引类型 * @param p get_table_rows接口入参对象 * @param abi 通过controller查询入参code对应的程序abi * @return 查询结果 */ template <typename IndexType> read_only::get_table_rows_result get_table_rows_ex( const read_only::get_table_rows_params& p, const abi_def& abi )const { read_only::get_table_rows_result result; // 首先定义结果容器 const auto& d = db.db(); // 状态主库对象 uint64_t scope = convert_to_type<uint64_t>(p.scope, "scope"); // 获得查询条件。 abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time);// 将abi_def类型的abi通过序列化转到abi_serializer类型的对象abis。 // 查询状态库表的标准范式,返回的是通过code、scope、table检索到的结果集的数据迭代器, const auto* t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(p.code, scope, p.table)); if (t_id != nullptr) { // 迭代器不为空 const auto& idx = d.get_index<IndexType, chain::by_scope_primary>(); // 传入查询依赖的键,指定迭代器的索引。 decltype(t_id->id) next_tid(t_id->id._id + 1); auto lower = idx.lower_bound(boost::make_tuple(t_id->id)); // 获取结果集上限 auto upper = idx.lower_bound(boost::make_tuple(next_tid)); // 获取结果集下限 if (p.lower_bound.size()) {// 如果入参对象设置了结果集下限 if (p.key_type == "name") { // 主键类型是账户名字,设置下限对象 name s(p.lower_bound); lower = idx.lower_bound( boost::make_tuple( t_id->id, s.value )); } else {// 主键类型是其他类型,设置下限对象 auto lv = convert_to_type<typename IndexType::value_type::key_type>( p.lower_bound, "lower_bound" ); lower = idx.lower_bound( boost::make_tuple( t_id->id, lv )); } } if (p.upper_bound.size()) {// 如果入参对象设置了结果集上限 if (p.key_type == "name") {// 主键类型是账户名字,设置上限对象 name s(p.upper_bound); upper = idx.lower_bound( boost::make_tuple( t_id->id, s.value )); } else {// 主键类型是其他类型,设置上限对象 auto uv = convert_to_type<typename IndexType::value_type::key_type>( p.upper_bound, "upper_bound" ); upper = idx.lower_bound( boost::make_tuple( t_id->id, uv )); } } // 迭代器启动迭代,开始检索 vector<char> data; auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms 是最长时间 unsigned int count = 0; auto itr = lower; for (; itr != upper; ++itr) { copy_inline_row(*itr, data); // 将迭代器当前指针指向的对象复制到data容器中去。 if (p.json) { // 处理data为json格式,通过方法binary_to_variant,向result的结果集rows中插入解析后的明文json格式的data result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) ); } else { // 未要求json格式,则直接返回data,data不是可读的。 result.rows.emplace_back(fc::variant(data)); } if (++count == p.limit || fc::time_point::now() > end) { // 两个限制:一是结果集行数limit限制,二是执行时间是否超时 ++itr; break; } } if (itr != upper) { // 如果实际返回的结果集并没有完全输出所有符合要求的数据,则将more字段置为true,提醒用户还有符合要求的数据没显示。 result.more = true; } } return result; }

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

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