用cleos get info 为例子,看看从cleos 客户端发送请求到 nodeos 全流程,共三步骤:
1.cleos使用接口
2.nodeos接口定义
3.nodeos接口实现
cleos使用接口:
eos/programs/cleos/main.cpp
定义url,返回结果 eosio::chain_apis::read_only::get_info_results定义在plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp
string url = "http://localhost:8888/";
eosio::chain_apis::read_only::get_info_results get_info() {
return call(url, get_info_func).as<eosio::chain_apis::read_only::get_info_results>();
}
get_info_func的定义
eos/programs/cleos/httpc.hpp
const string chain_func_base = "/v1/chain";
const string get_info_func = chain_func_base + "/get_info";
nodeos接口定义:
plugins/chain_api_plugin/chain_api_plugin.cpp
void chain_api_plugin::plugin_startup() {
ilog( "starting chain_api_plugin" );
my.reset(new chain_api_plugin_impl(app().get_plugin<chain_plugin>().chain()));
auto ro_api = app().get_plugin<chain_plugin>().get_read_only_api();
auto rw_api = app().get_plugin<chain_plugin>().get_read_write_api();
app().get_plugin<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_abi, 200),
CHAIN_RO_CALL(get_table_rows, 200),
CHAIN_RO_CALL(get_currency_balance, 200),
CHAIN_RO_CALL(get_currency_stats, 200),
CHAIN_RO_CALL(get_producers, 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_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)
});
}
plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp
定义 get_info 方法
class read_only {
const controller& db;
public:
static const string KEYi64;
read_only(const controller& db)
: db(db) {}
using get_info_params = empty;
struct get_info_results {
string server_version;
chain::chain_id_type chain_id;
uint32_t head_block_num = 0;
uint32_t last_irreversible_block_num = 0;
chain::block_id_type last_irreversible_block_id;
chain::block_id_type head_block_id;
fc::time_point head_block_time;
account_name head_block_producer;
uint64_t virtual_block_cpu_limit = 0;
uint64_t virtual_block_net_limit = 0;
uint64_t block_cpu_limit = 0;
uint64_t block_net_limit = 0;
//string recent_slots;
//double participation_rate = 0;
};
get_info_results get_info(const get_info_params&) const;
nodeos接口实现:
plugins/chain_plugin/chain_plugin.hpp 实现get_info
namespace chain_apis {
const string read_only::KEYi64 = "i64";
read_only::get_info_results read_only::get_info(const read_only::get_info_params&) const {
const auto& rm = db.get_resource_limits_manager();
return {
eosio::utilities::common::itoh(static_cast<uint32_t>(app().version())),
db.get_chain_id(),
db.head_block_num(),
db.last_irreversible_block_num(),
db.last_irreversible_block_id(),
db.head_block_id(),
db.head_block_time(),
db.head_block_producer(),
rm.get_virtual_block_cpu_limit(),
rm.get_virtual_block_net_limit(),
rm.get_block_cpu_limit(),
rm.get_block_net_limit()
//std::bitset<64>(db.get_dynamic_global_properties().recent_slots_filled).to_string(),
//__builtin_popcountll(db.get_dynamic_global_properties().recent_slots_filled) / 64.0
};
}
再看看wallet方面的接口流程
cleos使用接口:
httpc.hpp
const string wallet_func_base = "/v1/wallet";
const string wallet_sign_trx = wallet_func_base + "/sign_transaction";
main.cpp
void sign_transaction(signed_transaction& trx, fc::variant& required_keys, const chain_id_type& chain_id) {
fc::variants sign_args = {fc::variant(trx), required_keys, fc::variant(chain_id)};
const auto& signed_trx = call(wallet_url, wallet_sign_trx, sign_args);
trx = signed_trx.as<signed_transaction>();
}
nodeos接口定义:wallet_api_plugin.cpp
app().get_plugin<http_plugin>().add_api({
CALL(wallet, wallet_mgr, sign_transaction,
INVOKE_R_R_R_R(wallet_mgr, sign_transaction, chain::signed_transaction, flat_set<public_key_type>, chain::chain_id_type), 201),
nodeos接口实现:
wallet_plugin.cpp实现插件功能,具体功能在 wallet_manager.hpp实现
/// Sign transaction with the private keys specified via their public keys. 通过其公钥指定的私钥签署事务
/// Use chain_controller::get_required_keys to determine which keys are needed for txn.
/// @param txn the transaction to sign.要签署的事务
/// @param keys the public keys of the corresponding private keys to sign the transaction with
/// @param id the chain_id to sign transaction with.
/// @return txn signed 返回签名
/// @throws fc::exception if corresponding private keys not found in unlocked wallets 如果未解锁的钱包中没有找到相应的私钥,则将出现异常
chain::signed_transaction sign_transaction(const chain::signed_transaction& txn, const flat_set<public_key_type>& keys,
const chain::chain_id_type& id);
wallet_manager.cpp
chain::signed_transaction
wallet_manager::sign_transaction(const chain::signed_transaction& txn, const flat_set<public_key_type>& keys, const chain::chain_id_type& id) {
check_timeout();
chain::signed_transaction stxn(txn);
for (const auto& pk : keys) {
bool found = false;
for (const auto& i : wallets) {
if (!i.second->is_locked()) {
optional<signature_type> sig = i.second->try_sign_digest(stxn.sig_digest(id, stxn.context_free_data), pk);
if (sig) {
stxn.signatures.push_back(*sig);
found = true;
break; // inner for
}
}
}
if (!found) {
EOS_THROW(chain::wallet_missing_pub_key_exception, "Public key not found in unlocked wallets ${k}", ("k", pk));
}
}
return stxn;
}