7. 使用事件订阅功能

在使用超级链的过程中,可能会遇到一些异步的情况:比如执行合约的时候,构造的交易是否合法我们可以实时获知,但具体什么时候真正的被节点打包上链就不一样了。当然还有其他类似的场景,针对这种问题,我们引入了事件订阅机制。

7.1. 事件订阅的接口

订阅的接口十分简单,只有subscribe和unsubscribe两个,订阅和取消订阅

  1. service PubsubService {
  2. rpc Subscribe (EventRequest) returns (stream Event);
  3. rpc Unsubscribe (UnsubscribeRequest) returns (UnsubscribeResponse) {}
  4. }

其中订阅接口的EventRequest格式如下:

  1. message EventRequest {
  2. EventType type = 1;
  3. bytes payload = 2;
  4. }
  5. // EventType 主要有区块、交易、账户 3种
  6. enum EventType {
  7. UNDEFINED = 0;
  8. BLOCK = 1;
  9. TRANSACTION = 2;
  10. ACCOUNT = 3;
  11. SUBSCRIBE_RESPONSE = 4;
  12. }

请求里的payload是一段序列化的proto对象,因为订阅不同内容需要的参数不尽相同

  1. // BlockEventRequest 订阅区块请求
  2. message BlockEventRequest {
  3. string bcname = 1;
  4. string proposer = 2;
  5. int64 start_height = 3;
  6. int64 end_height = 4;
  7. bool need_content = 5;
  8. }
  9. // TransactionEventRequest 订阅交易请求
  10. message TransactionEventRequest {
  11. string bcname = 1;
  12. string initiator = 2;
  13. string auth_require = 3;
  14. bool need_content = 4;
  15. }
  16. // AccountEventRequest 订阅账户请求
  17. message AccountEventRequest {
  18. string bcname = 1;
  19. string from_addr = 2;
  20. string to_addr = 3;
  21. bool need_content = 4;
  22. }

订阅返回的内容格式均为Event,对应不同的订阅类型填充不同的StatusInfo字段,详细内容会放在payload里

  1. message Event {
  2. string id = 1;
  3. EventType type = 2;
  4. bytes payload = 3;
  5. BlockStatusInfo block_status = 4;
  6. TransactionStatusInfo tx_status = 5;
  7. AccountStatusInfo account_status = 6;
  8. }

订阅区块时,填充BlockEventRequest的链名、矿工地址、起止高度、以及是否需要详细内容字段。在订阅高度内,每当此矿工打包出块,便会接收到区块的内容

  1. message BlockStatusInfo {
  2. string bcname = 1;
  3. string proposer = 2;
  4. int64 height = 3;
  5. BlockStatus status = 4;
  6. }

订阅交易时,可填充TransactionEventRequest的链名、发起方、签名方、以及是否需要详细内容字段,订阅开始后,由指定的账号发起或者有指定账号签名(注意两个条件是逻辑或的关系),便会收到交易内容

  1. message TransactionStatusInfo {
  2. string bcname = 1;
  3. string initiator = 2;
  4. repeated string auth_require = 3;
  5. TransactionStatus status = 4;
  6. }

订阅账号时,可填充AccountEventRequest的链名、来源方、接收方、以及是否需要详细内容字段,订阅开始后,来源指定账号或者由指定账号接收的(注意两个条件是逻辑或的关系)交易内容均可以收到

  1. message AccountStatusInfo {
  2. string bcname = 1;
  3. repeated string from_addr = 2;
  4. repeated string to_addr = 3;
  5. TransactionStatus status = 4;
  6. }

三种模式成功订阅后,都可以收到一个全局唯一的订阅id,使用这个id可以构造请求取消此订阅

  1. // UnsubscribeRequest 取消事件订阅请求
  2. message UnsubscribeRequest {
  3. string id = 1;
  4. }

当然,进行订阅的进程退出或被杀死,订阅行为也会停止

7.2. 使用事件订阅

我们在xchain的代码中实现了一个简单的例子,参考 xuperchain/xuperchain/core/test/pubsub 目录,里面有一个示例程序和不同类别订阅需要的参数json文件

正常编译xchain即可获得此demo的可执行文件 event_client,按如下命令执行即可

  1. ./event_client -c subscribe -f accountEventSubscribe.json -h localhost:37101
  2. ./event_client -c unsubscribe -id xxxxxxxxxxxxxxxxxxx

示例程序中调用的便是上一小节介绍的订阅rpc接口