EOS源码框架剖析第八篇 | chain_plugin插件的实现细节中篇
<pre><code class=”hljs sql”>
vector<asset> read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const {
//调用指定数据表操作接口,表拥有者为p.code
const abi_def abi = eosio::chain_apis::get_abi( db, p.code );
//按账户名返回表信息
auto table_type = get_table_type( abi, “accounts” );
//声明一个vector用以保存返回结果
vector<asset> results;
//调用walk_key_value_table模板,用以检索数据
walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){
//判断表中数据合规性
EOS_ASSERT( obj.value.size() >= sizeof(asset), chain::asset_type_exception, “Invalid data on table”);
//声明cursor资产,用作迭代结果返回值
asset cursor;
//初始化待检索数据
fc::datastream<const char *> ds(obj.value.data(), obj.value.size());
fc::raw::unpack(ds, cursor);
</code></pre>
EOS_ASSERT( cursor.get_symbol().valid(), chain::asset_type_exception, “Invalid asset”);
//判断返回结果是否为指定类型代币,若是则压入results中
if( !p.symbol || boost::iequals(cursor.symbol_name(), *p.symbol) ) {
results.emplace_back(cursor);
}
return !(p.symbol && boost::iequals(cursor.symbol_name(), *p.symbol));
});
return results;
}
1.2 get_currency_stats函数
该函数的功能用于返回某种代币的发行状态信息,具体执行逻辑如下:
fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_params& p )const {
fc::mutable_variant_object results;
//调用指定数据表操作接口,表拥有者为p.code
const abi_def abi = eosio::chain_apis::get_abi( db, p.code );
auto table_type = get_table_type( abi, “stat” );
//设置检索范围为表全局
uint64_t scope = ( eosio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 );
//重复上述流程
walk_key_value_table(p.code, scope, N(stat), [&](const key_value_object& obj){
EOS_ASSERT( obj.value.size() >= sizeof(read_only::get_currency_stats_result), chain::asset_type_exception, “Invalid data on table”);
fc::datastream<const char *> ds(obj.value.data(), obj.value.size());
read_only::get_currency_stats_result result;
fc::raw::unpack(ds, result.supply);
fc::raw::unpack(ds, result.max_supply);
fc::raw::unpack(ds, result.issuer);
results[result.supply.symbol_name()] = result;
return true;
});
return results;
}
1.3 get_producers函数
该函数用于返回当前出块节点信息,具体执行逻辑如下:
read_only::get_producers_result read_only::get_producers( const read_only::get_producers_params& p ) const {
//获取EOSIO账户下的智能合约中拥有的数据表接口
const abi_def abi = eosio::chain_apis::get_abi(db, N(eosio));
const auto table_type = get_table_type(abi, N(producers));
const abi_serializer abis{ abi, abi_serializer_max_time };
//判断返回结果数据类型是否合规
EOS_ASSERT(table_type == KEYi64, chain::contract_table_query_exception, “Invalid table type ${type} for table producers”, (“type”,table_type));
//设置数据表指针
const auto& d = db.db();
const auto lower = name{p.lower_bound};
static const uint8_t secondary_index_num = 0;
//查找并返回保存producers数据的数据表指针
const auto* const table_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(N(eosio), N(eosio), N(producers)));
const auto* const secondary_table_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(N(eosio), N(eosio), N(producers) | secondary_index_num));
EOS_ASSERT(table_id && secondary_table_id, chain::contract_table_query_exception, “Missing producers table”);
//初始化查找指针
const auto& kv_index = d.get_index<key_value_index, by_scope_primary>();
const auto& secondary_index = d.get_index<index_double_index>().indices();
const auto& secondary_index_by_primary = secondary_index.get<by_primary>();
const auto& secondary_index_by_secondary = secondary_index.get<by_secondary>();
//声明get_producers_result类对象,用于存储返回值
read_only::get_producers_result result;
const auto stopTime = fc::time_point::now() + fc::microseconds(1000 * 10); // 10ms
vector<char> data;
//声明一个匿名函数,调用lower_bound检索方法
auto it = [&]{
if(lower.value == 0)
return secondary_index_by_secondary.lower_bound(
boost::make_tuple(secondary_table_id->id, to_softfloat64(std::numeric_limits<double>::lowest()), 0));
else
return secondary_index.project<by_secondary>(
secondary_index_by_primary.lower_bound(
boost::make_tuple(secondary_table_id->id, lower.value)));
}();
//逐个压入检索结果
for( ; it != secondary_index_by_secondary.end() && it->t_id == secondary_table_id->id; ++it ) {
if (result.rows.size() >= p.limit || fc::time_point::now() > stopTime) {
result.more = name{it->primary_key}.to_string();
break;
}
copy_inline_row(*kv_index.find(boost::make_tuple(table_id->id, it->primary_key)), data);
if (p.json)
result.rows.emplace_back(abis.binary_to_variant(abis.get_table_type(N(producers)), data, abi_serializer_max_time));
else
result.rows.emplace_back(fc::variant(data));
}
//最后压入总投票权重值
result.total_producer_vote_weight = get_global_row(d, abi, abis, abi_serializer_max_time)[“total_producer_vote_weight”].as_double();
return result;
}
EOS源码框架剖析系列于每周一定期推出,本篇我们详解了几个chain_plugin插件中read_only类函数,下一篇,我们将选择chain_plugin插件中的read_write函数进行详细剖析,帮助大家理解该插件代码的实现逻辑,关注获得更多价值文章!
本系列前置文章:
EOS源码框架剖析第七篇 | chain_plugin插件的实现细节上篇
EOS源码框架剖析第六篇 | EOS共识算法(DPOS+BFT)代码逻辑下篇
EOS源码框架剖析第五篇 | EOS共识算法(DPOS+BFT)代码逻辑中篇
其他系列最新文章: