函数的处理逻辑:
vector<asset> read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const { const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); // get_abi与前面RPC接口实现函数为同一个。先通过账户code获取eosio.token合约对象abi数据。 auto table_type = get_table_type( abi, "accounts" ); // 在abi中找到accounts表,返回该表的索引类型。 vector<asset> results; // 结果容器 walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){ // 表数据的value值超过了assert数据类型的大小,说明是无效数据。 EOS_ASSERT( obj.value.size() >= sizeof(asset), chain::asset_type_exception, "Invalid data on table"); asset cursor; // obj.value.data()是原始数据。 fc::datastream<const char *> ds(obj.value.data(), obj.value.size()); fc::raw::unpack(ds, cursor); // 将datastream数据解包到cursor EOS_ASSERT( cursor.get_symbol().valid(), chain::asset_type_exception, "Invalid asset"); if( !p.symbol || boost::iequals(cursor.symbol_name(), *p.symbol) ) { // 对比token符号,一致的添加至结果集。 results.emplace_back(cursor); } return !(p.symbol && boost::iequals(cursor.symbol_name(), *p.symbol)); }); return results; }get_table_type函数:
string get_table_type( const abi_def& abi, const name& table_name ) { for( const auto& t : abi.tables ) { //遍历abi下的所有table if( t.name == table_name ){ // 找到符合条件的table return t.index_type; // 返回该table的索引类型。 } } // 如果没查到,报错提示当前ABI中并未找到目标table。 EOS_ASSERT( false, chain::contract_table_query_exception, "Table ${table} is not specified in the ABI", ("table",table_name) ); } 13. 获取货币状态 get_currency_stats传入eosio.token合约owner账户以及token符号即可请求到该token的状态信息。
fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_params& p )const { fc::mutable_variant_object results; // 结果容器 const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); auto table_type = get_table_type( abi, "stat" ); // 在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; // 数组下标为token符号,内容是token信息。 return true; }); return results; } 14. 获取生产者信息 get_producers入参的结构有是否以json格式输出的布尔类型对象、数据集下限、数据集条目限制,三个都是可选参数。该接口获得的是当前链的生产者信息。该接口的返回值是一个显示所有生产者信息的列表,以及生产者投票总权重信息,最后也有一个more字段用于说明是否有更多未展示的符合条件的数据。
生产者信息是在system合约的producers表中存储。
具体接口的实现函数较长且与前面获取其他状态库表数据的逻辑相似,不在这里重复分析源码。源码中复杂的部分在于对各种二级索引的处理。
15. 获取生产者出块安排 get_producer_schedule无请求参数,返回参数的结构有三个字段:
active,活跃的。直接取自controller的active_producers函数获得,实际上返回的就是controller_impl的属性my->head->active_schedule或者是如果存在pending块时my->pending->_pending_block_state->active_schedule。
pending,等待中的。与上面一项相似来自pending_producers()函数,my->head->pending_schedule或者是如果存在pending块时my->pending->_pending_block_state->pending_schedule。
proposed,计划中的。来自proposed_producers()函数,返回my->db.get<global_property_object>()获取的全局属性中的proposed_schedule字段。
16. 获取日程安排上链的事务信息 get_scheduled_transactions请求参数的结构:
struct get_scheduled_transactions_params { bool json = false; string lower_bound; // 传入时间戳或者交易id。 uint32_t limit = 50; };返回值结构:
struct get_scheduled_transactions_result { fc::variants transactions; // 事务数组 string more; };transactions的一个元素的结构为:
auto row = fc::mutable_variant_object() ("trx_id", itr->trx_id) ("sender", itr->sender) ("sender_id", itr->sender_id) ("payer", itr->payer) ("delay_until", itr->delay_until) ("expiration", itr->expiration) ("published", itr->published) ;