EOS源码框架剖析第八篇 | chain_plugin插件的实现细节中篇

 LQ EOS开发者 8月27日
上篇文章我们已经对EOS节点运行时默认开启的四大插件中第一个关键插件——chain_plugin进行了框架上的详细梳理。本篇主要选择几个关键函数重点介绍代码逻辑。

1、read_only类关键函数
1.1 get_currency_balance函数该函数的功能为获取某账户token余额,具体执行逻辑如下

<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)代码逻辑中篇

其他系列最新文章:

命令行玩转EOS系列第七篇 | wallet本地钱包管理

火箭入门EOS开发系列第七篇 | multi_index的定义及操作

EOS科普系列第五篇 | EOS共识机制设计思想

Course Information

Course Instructor

Isaac Isaac Author

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Close Menu
×

Cart