操作系统:MAC OS 10.13.x,EOSIO版本:1.1.3
在EOS侧链的开发过程中,必然需要侧链与主链之间的通讯。请先看我们的系列文章:EOS跨链转账 - 。
1.过程
在“EOS跨链转账”中,主链的同步节点(同步链)在确认账户A到合约账号M的转账不可撤销后,通过http向测链节点发送一个action。
void send_transaction(const block_state_ptr& irb) {
auto& chain = chain_plug->chain();
auto& db = chain.db();
const auto& trmi = db.get_index();
auto itr = trmi.begin();
while( itr != trmi.end()) {
if (itr->block_num <= irb->block_num) {
auto data = fc::raw::unpack(itr->data);
// need to validate ?
// send propose or approve
string datastr = DATA_FORMAT(_peer_chain_account, string(itr->trx_id), string(data.to), data.quantity.to_string());
vector permissions = {_peer_chain_account};
try {
app().find_plugin()->get_client_apis().push_action(_peer_chain_address, _peer_chain_constract,"msigtrans", datastr, permissions);
} catch (...) {
wlog("send transaction failed");
}
// remove or move to other table ?
db.remove(*itr);
}
++ itr;
}
}
上述send_transaction
中,app().find_plugin()->get_client_apis().push_action(_peer_chain_address, _peer_chain_constract, "msigtrans", datastr, permissions);
即为client_plugin提供的push_action方法。入参与EOSIO的命令行cleos push action account action data
类似,增加了一个url,此url为侧链上的一个节点地址如:http://192.168.31.91:8888。
2.实现
为了实现主链同步节点在同步过程中向侧链查询或者发送交易的功能,我们写了一个client_plugin,专门负责处理发送http请求。
client_plugin中push_action与EOSIO中的program/cleos/main 的push_action类似,这为后续扩展其他查询/http请求提供方便。具体代码如下
void client_cactus::push_action(const std::string& url, string contract_account, string action, string data, const vector& tx_permission ){
fc::variant action_args_var;
if( !data.empty() ) {
try {
action_args_var = json_from_file_or_string(data, fc::json::relaxed_parser);
} EOS_RETHROW_EXCEPTIONS(action_type_exception, "Fail to parse action JSON data='${data}'", ("data", data))
}
auto arg= fc::mutable_variant_object
("code", contract_account)
("action", action)
("args", action_args_var);
auto result = call(url, json_to_bin_func, arg);
auto accountPermissions = get_account_permissions(tx_permission);
send_actions(url, {eosio::chain::action{accountPermissions, contract_account, action, result.get_object()["binargs"].as()}});
}
void client_cactus::send_actions(const std::string& url, std::vector&& actions, int32_t extra_kcpu, packed_transaction::compression_type compression) {
auto result = push_actions( url, move(actions), extra_kcpu, compression);
std::cout << fc::json::to_pretty_string( result ) << std::endl;
}
fc::variant client_cactus::push_actions(const std::string& url, std::vector&& actions, int32_t extra_kcpu, packed_transaction::compression_type compression) {
signed_transaction trx;
trx.actions = std::forward(actions);
return push_transaction(url, trx, extra_kcpu, compression);
}
fc::variant client_cactus::push_transaction( const std::string& url, signed_transaction& trx, int32_t extra_kcpu, packed_transaction::compression_type compression) {
auto info = get_info(url);
trx.expiration = info.head_block_time + tx_expiration;
// Set tapos, default to last irreversible block
trx.set_reference_block(info.last_irreversible_block_id);
trx.max_cpu_usage_ms = tx_max_net_usage;
trx.max_net_usage_words = (tx_max_net_usage + 7)/8;
sign_transaction_local(trx, client_prikey, info.chain_id);//本地对交易签名,没有使用钱包!后续可以使用钱包来对交易签名
return call(url, push_txn_func, packed_transaction(trx, compression));
}
不使用钱包,本地签名实现:
chain_id_type& chain_id) {
optional sig = private_key.sign(trx.sig_digest(chain_id, trx.context_free_data));
if (sig) {
trx.signatures.push_back(*sig);
}
}
使用EOSIO的call实现do_http_call( )请求
template
fc::variant client_cactus::call( const std::string& url,
const std::string& path,
const T& v ) {
static http_context context = create_http_context();
auto urlpath = parse_url(url) + path;
connection_param *cp = new connection_param(context, urlpath, false);
return do_http_call( *cp, fc::variant(v), false, false );
}
3. 启动client_plugin
需要配置如下参数:
client-private-key
见证人的私钥
--client-private-key 5K8MzDTmBKfGWE5wDpTcpmMimHH2SzFADjmSkvJe47RWHv3nbke
具体演示结果见EOS跨链转账 -