2019-03-19

小E浅谈丨EOCS中继网络源码剖析


2019-03-19_第1张图片

EOCS中继网络实现了两种模式,分别是eoc模式和icp模式,今天小E先为大家介绍eoc模式。

eoc_relay_plugin 源码剖析

在eoc_relay_plugin.cpp中

----------------------------------------------------------------------------------

static appbase::abstract_plugin& _eoc_relay_plugin = app().register_plugin();

向appbase中注册了eoc_relay_plugin插件。

----------------------------------------------------------------------------------

void eoc_relay_plugin::set_program_options(options_description&, options_description& cfg);

该函数将config中配置的参数设置导入eoc_relay_plugin中,内部调用了plugin_initialize和init_eoc_relay_plugin函数,设置eoc_relay_plugin必备的参数。

----------------------------------------------------------------------------------

接着调用

voideoc_relay_plugin::plugin_startup()

    {

ilog("starting eoc_relay_plugin");

//sendstartaction();

auto&chain = app().get_plugin().chain();

FC_ASSERT(chain.get_read_mode() != chain::db_read_mode::IRREVERSIBLE,"icp is not compatible with \"irreversible\" read_mode");

        relay_->start();

        chain::controller &cc = relay_->chain_plug->chain();

        {

          cc.applied_transaction.connect(boost::bind(&eoc_icp::relay::on_applied_transaction, relay_.get(), _1));

          cc.accepted_block_with_action_digests.connect(boost::bind(&eoc_icp::relay::on_accepted_block, relay_.get(), _1));

          cc.irreversible_block.connect(boost::bind(&eoc_icp::relay::on_irreversible_block, relay_.get(), _1));

        }

        relay_->start_monitors();

for(autoseed_node : relay_->connect_to_peers_)

        {

          connect(seed_node);

        }

if(fc::get_logger_map().find(icp_logger_name) != fc::get_logger_map().end())

          icp_logger = fc::get_logger_map()[icp_logger_name];

// Make the magic happen

    }

该函数主要是实现插件的启动,内部绑定了controller的applied_transaction,accepted_block_with_action_digests,irreversible_block信号,当收到这些信号,就会自动调用relay的三个函数。

上面就是eoc_relay_plugin的核心通信代码,内部的网络消息流程和net_plugin类似,通过icp_relay类完成网络消息的控制,以及回调函数的逻辑处理。

----------------------------------------------------------------------------------

voidrelay::start_monitors( )

{

connector_check.reset(newboost::asio::steady_timer( app().get_io_service()));

start_conn_timer(connector_period,std::weak_ptr());

}

该函数设置了定时器,检测连接是否成功,不成功则定时重连。

----------------------------------------------------------------------------------

voidrelay::start() {

ioc_ =std::make_unique(num_threads_);

timer_ =std::make_shared(app().get_io_service());

autoaddress = boost::asio::ip::make_address(endpoint_address_);

  update_local_head();

if( acceptor ) {

        acceptor->open(listen_endpoint.protocol());

acceptor->set_option(tcp::acceptor::reuse_address(true));

try{

          acceptor->bind(listen_endpoint);

}catch(conststd::exception& e) {

ilog("eoc_relay_plugin::plugin_startup failed to bind to port ${port}",

("port", listen_endpoint.port()));

throwe;

        }

        acceptor->listen();

ilog("starting listener, max clients is ${mc}",("mc",max_client_count));

        start_listen_loop();

      }

}

该函数启动了eoc插件的网络监听事件,start_listen_loop就是控制的网络事件循环监听。

----------------------------------------------------------------------------------

voidrelay::send_icp_net_msg(consticp_net_message& msg)

{

    send_icp_notice_msg(icp_notice_message{local_head_});

for(constauto& c : connections )

    {

      c->send_icp_net_msg(msg);

    }


}

中继间通信是通过网络tcp点对点发送的,该函数就是封装了icp_net_message发送的功能。

----------------------------------------------------------------------------------

voidrelay::on_applied_transaction(consttransaction_trace_ptr& t) {

//ilog("on applied transaction");

//......

for(auto& action: t->action_traces) {

if(action.receipt.receiver != action.act.account)

      {

ilog("action.receipt.receiver != action.act.account");

continue;

      }

if(action.act.account != local_contract_oraction.act.name == ACTION_DUMMY) {// thirdparty contract call or icp contract dummy call

//ilog("on applied transaction action dumy!!!");

for(auto& in: action.inline_traces) {

if(in.receipt.receiver != in.act.account)continue;

if(in.act.account == local_contract_andin.act.name == ACTION_SENDACTION) {

for(auto&inin: in.inline_traces) {

if(inin.receipt.receiver != inin.act.account)continue;

if(inin.act.name == ACTION_ISPACKET) {

autoseq = icp_packet::get_seq(inin.act.data, st.start_packet_seq);

                    st.packet_actions[seq] = send_transaction_internal{ACTION_ONPACKET, inin.act, inin.receipt};

                  }

              }

            }

        }

}elseif(action.act.account == local_contract_) {

if(action.act.name == ACTION_ADDBLOCKSoraction.act.name == ACTION_OPENCHANNEL) {

ilog("on_applied_transaction ,action name is ${p}",("p", action.act.name) );

app().get_io_service().post([this] {

              update_local_head();

            });

}else

        {

//....

        }

  }

if(st.empty())return;

//send_transactions_.insert(st);

    update_send_transaction_index(st);

}

该函数是跨链交易处理的核心逻辑,分别处理了不同类型的action,如ACTION_ADDBLOCKS,ACTION_OPENCHANNEL等。

----------------------------------------------------------------------------------

同样,由于eoc_relay既要发送消息,也要接收消息,所以封装了几个消息处理函数如:

voidrelay::handle_message( icp_connection_ptr c,consticp_notice_message & msg)

{

ilog("received icp_notice_message");

if(notmsg.local_head_.valid())return;

  app().get_io_service().post([=, self=shared_from_this()] {

if(notpeer_head_.valid()) {

        clear_cache_block_state();

      }

      peer_head_ = msg.local_head_;

      });

// TODO: check validity

icp_peer_ilog(c,"received icp_notice_message");

ilog("received icp_notice_message");


}

该函数处理icp_notice_message。详细细节,大家可以下载源码仔细参阅,eoc_relay_plugin核心代码剖析就介绍到这里,欢迎大家关注EOCS官方微信公众号及EOCS小秘书共同探讨交流更多技术。


2019-03-19_第2张图片

你可能感兴趣的:(2019-03-19)