EOS中基于http-json的RPC机制

eos中客户端跟区块链的通信采用基于http-json作为传输的RPC(Remote Procedure Call ),下面简述一下客户端通过RPC调用callA这个过程:
1)client:callA(arg1, arg2...) // client stub 存放server的地址消息,再将client的callA请求参数序列化打包成json数据格式然后通过http发送给server
2)server:callA(arg1, arg2...) // server stub 接收client发送过来的json格式参数,然后将参数反序列化解包成二进制格式,并调用本地的方法callA最终再将结果序列化成json数据格式通过http返回给client

下面以push_transaction为例:
cleos --print-request --print-response -v push action eosio.token transfer '[ "eosio", "hellohello22", "100.0000 SYS", "m" ]' -p eosio@active

客户端发出的http请求: post参数为json数据格式

POST /v1/chain/push_transaction HTTP/1.0
Host: 127.0.0.1:8888
content-length: 380
Accept: */*
Connection: close

{
  "signatures": [
    "SIG_K1_KXikhe2K5KSbuvwc38EahnxwzGA1gFcsy6AoN9tdThxbdxob3kVYQoUZGrsKC7PMraEjEBKKaFfUtoBmoEHvUntF2bDxzh"
  ],
  "compression": "none",
  "packed_context_free_data": "",
  "packed_trx": "5023d05b2c3d5d2c778e000000000100a6823403ea3055000000572d3ccdcd010000000000ea305500000000a8ed3232220000000000ea305520048d51351aa36a40420f00000000000453595300000000016d00"
}

客户端收到的响应:返回的响应为json格式

{
  "transaction_id": "c6dece9a8c2abf83d5b83e8c9c8f74179ab35c7bfeedcc0e41b1bc90681ea331",
  "processed": {
    "id": "c6dece9a8c2abf83d5b83e8c9c8f74179ab35c7bfeedcc0e41b1bc90681ea331",
    "receipt": {
      "status": "executed",
      "cpu_usage_us": 2889,
      "net_usage_words": 16
    },
    "elapsed": 76187,
    "net_usage": 128,
    "scheduled": false,
    "action_traces": [{
        "receipt": {
          "receiver": "eosio.token",
          "act_digest": "ff3f09bbc56a0c9a7a06871c2f66c723c8befa90b837e22985ab65bfc0bf7032",
          "global_sequence": 278021,
          "recv_sequence": 51,
          "auth_sequence": [[
              "eosio",
              277915
            ]
          ],
          "code_sequence": 1,
          "abi_sequence": 1
        },
        "act": {
          "account": "eosio.token",
          "name": "transfer",
          "authorization": [{
              "actor": "eosio",
              "permission": "active"
            }
          ],
          "data": {
            "from": "eosio",
            "to": "hellohello22",
            "quantity": "100.0000 SYS",
            "memo": "m"
          },
...
  }
}
  • url handler的注册
    区块链中所有需要提供http api的插件都依赖于http_plugin,http_plugin实现了一个简单http服务器(websocketpp),要提供一个url接口只需要调用http_plugin中的add_handler函数添加一个处理该url的handler
// 在handler 中需要调用的回调函数
using url_response_callback = std::function<void(int,string)>;
// 相应url的handler,http_plugin会调用
using url_handler = std::function<void(string,string,url_response_callback)>;

void add_handler(const string& url, const url_handler&);

下面以chain_api_plugin.cpp中的push_transaction handler为例

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_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202),
...
   });
}

push_transaction handler对应的uri为/v1/chain/push_transaction,下面push_transaction handler代码为上述CHAIN_RW_CALL_ASYNC宏展开

[this, rw_api](string, string body, url_response_callback cb) mutable { 
if (body.empty()) body = "{}"; 
// 调用本地RPC函数push_transaction
rw_api.push_transaction(fc::json::from_string(body).as<chain_apis::read_write::push_transaction_params>(), 
        [cb, body](const fc::static_variant<fc::exception_ptr, chain_apis::read_write::push_transaction_results>& result){ 
            if (result.contains<fc::exception_ptr>()) { 
                try { 
                    // 如果处理结果中包含异常则直接抛出异常
                    result.get<fc::exception_ptr>()->dynamic_rethrow_exception(); 
                } catch (...) { 
                    http_plugin::handle_exception("chain", "push_transaction", body, cb); 
                } 
            } else { 
                // 没有异常的情况下相应码为202,第二个参数为返回的序列化结果
                cb(202, result.visit(async_result_visitor())); 
            } 
        }
    );
}

上述调用本地RPC函数push_transaction,第一个参数把接收到的json数据格式反序列化为push_transaction_params参数,第二个参数为一个匿名函数,push_transaction处理完之后会调用该匿名函数

  • http请求的处理
    http_plugin处理http请求,找到相应uri对于的handler然后调用,最终handler处理完成之后会调用url_response_callback返回相应码跟body
template<class T>
void handle_http_request(typename websocketpp::server<detail::asio_with_stub_log<T>>::connection_ptr con) {
   try {
...
      auto body = con->get_request_body();
      auto resource = con->get_uri()->get_resource();
     // 是否有该uri的handler
      auto handler_itr = url_handlers.find( resource );
      if( handler_itr != url_handlers.end()) {
         con->defer_http_response();
         // 调用该uri的handler,这个handler就是我们上面通过add_handler添加的handler,第三个参数url_response_callback最终处理完成之后调用(响应码,body)     
         handler_itr->second( resource, body, [con]( auto code, auto&& body ) {
            con->set_body( std::move( body ));
            con->set_status( websocketpp::http::status_code::value( code ));
            con->send_http_response();
         } );

      } 
...
   } catch( ... ) {
      handle_exception<T>( con );
   }
}

关于eos中的参数的序列化与反序列化,eos fc中实现了反射机制,上层应用只需要为某一类型定义一个FC_REFLECT/FC_REFLECT_DERIVED就能实现该类型的序列化跟反序列化

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • 这几日在读林文采老师的心理营养这本书,书中概括了很多父母所没有给予孩子小时候的心理营养,如果幼年没有得到足够的...
    艾葭_阅读 137评论 2 2
  • 这是一首歌,好吧,第一次听的时候,只听了一分钟我就放弃了。因为,没有看的歌词。 第二次听,看着歌词,结尾的时候一句...
    初晴锦瑟阅读 318评论 0 0
  • 男儿当倜傥 凌云壮志满奥场 珞珈山下数英姿 飒爽 龙马精神好儿郎 巾帼何须让 莫笑女子爱红装 柔躯亦含铮铮骨 无双...
    珞珈山下一书生阅读 193评论 0 1
  • 在考研复习初期,很多考生并没有确定考研目标,复习无规划,复习方法不科学,甚至有部分考生依然坚持一周一通宵的生活习惯...
    狼特001血狼阅读 834评论 1 3