Skip to content

fibos-tracker 进阶篇 - emitter 插件介绍 #7

@WxSimon

Description

@WxSimon

fibos-tracker 进阶篇 - emitter 插件介绍

上节回顾

fibos-tracker 使用指南 文章中,我们学习了如何使用 fibos-tracker 同步 测试网 区块数据以达到定制数据存储的目的。而在本章中,我们将以 fibos-tracker 为起点,一起领略其内部的魅力。

fibos-tracker 中用到的技术

使用过 fibos-tracker 框架的同学知道,fibos-tracker 内部用到的技术主要有:

这篇文章我们就从最核心的 emitter 讲起,看完这篇文章,相信大家也能够使用 emitter 插件,编写链上数据过滤框架。

emitter 插件

什么是 emitter 插件

emitter 是 FIBOS 客户端独有的事件监听插件。依赖于该插件,我们可以收到 emitter 插件推送过来的 transaction(交易数据)、block(区块数据)、irreversible_block(不可逆区块数据) 三个事件,通过链下监听这三个事件,我们就能够完整地将链上数据进行存储。

emitter 插件是如何实现数据推送

由于 FIBOS 的代码目前还未完全开源,所以暂时无法提供 emitter 插件的相关 C++ 源码。待代码完全开源后,大家可以根据 FIBOS 的源码更加细节地了解到 emitter 插件的内部机制,这里先简单介绍一下 emitter 插件的技术原理。

  • fibos 插件介绍
    在 FIBOS 中存在各种各样的系统级别插件,例如主要提供 HTTP 节点服务的 http 插件,用来进行 p2p 网络设置的 net 插件,用来负责加载区块节点的 producer 插件,还有一个负责节点区块数据聚合的插件: chain 插件。你也可以访问 dev.fo 获取更多关于这些插件的使用方法。
  • chain 插件 && emitter 插件
    emitter 插件是基于 chain 插件来实现的。在 chain 插件中,有一个区块数据的信号槽,当有区块数据更新时,信号槽便会发出对应的事件信号,而 emitter 插件处理的事情便是监听 chain 插件的信号槽,当 emitter 插件监听到信号槽中存在信号后,会启动一个 fiber 将监听到的数据推送到客户端。这个时候我们使用 fibos.on 的三个事件便会收到由 emitter 插件推送出来的数据。具体可参考下图:
     emitter 参考图

如何使用 emitter 插件进行二次开发

前面已经介绍了 emitter 插件的基本原理,下面我们就动手使用 emitter 插件同步 测试网 进行二次开发,实现自己的数据定制存储吧。

环境支持

emitter 需要 fibos v1.3.1.7 及以上版本

  • 快速安装: curl -s https://fibos.io/download/installer.sh | sh

使用 emitter 插件

使用 emitter 插件同步测试网的代码如下:

const fibos = require('fibos');

fibos.config_dir = 'fibos_config_dir/';
fibos.data_dir = 'fibos_data_dir/';

fibos.load("http", {
    "http-server-address": "0.0.0.0:8871",
    "access-control-allow-origin": "*",
    "http-validate-host": false,
    "verbose-http-errors": true
});

fibos.load("net", {
    'p2p-listen-endpoint': "0.0.0.0:9876",
    "p2p-peer-address": ["p2p.testnet.fo:80"]
});

fibos.load("chain", {
    "delete-all-blocks": true,
    "genesis-json": "./genesis.json" 
});

fibos.load('chain_api');
fibos.load('emitter');

fibos.on('transaction',at => {
    console.log("====== transaction ======",at);
})

fibos.on('block',at => {
    console.log("====== block ======",at);
})

fibos.on('irreversible_block',at => {
    console.log("====== irreversible_block ======",at);
})

fibos.load('producer', {
    'producer-name': 'eosio',
    'enable-stale-production': true
});

fibos.start();

从上述代码中,可以看到使用 fibos 加载了 emitter 插件,同时监听了 emitter 插件的 transaction、block、irreversible_block 三个事件,当这三个事件存在数据改变时,便可以在客户端中接收到推送过来的数据然后进行相应业务逻辑处理。

进行二次开发

和 fibos-tracker 指南中的需求一致,我们需要存储所有和 fiboscouncil 账号相关的转账记录,同时将数据存储到 Mysql 中(事先需要创建数据库: fibos_chain)。实例代码如下:

  • 建表语句
CREATE TABLE `eosio_token_transfers` (
  `from` varchar(12) NOT NULL,
  `to` varchar(12) NOT NULL,
  `quantity` varchar(256) NOT NULL,
  `memo` varchar(256) DEFAULT NULL,
  `createdAt` datetime DEFAULT NULL,
  `updatedAt` datetime DEFAULT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

由于不依赖任何的 orm,所以数据表结构需要自己定义。

  • 自定义存储
    完整代码如下:

      const fibos = require('fibos');
      const db = require('db');
      
      let conn = db.open(`mysql://root:123456@127.0.0.1/fibos_chain`)
      
      fibos.config_dir = 'fibos_config_dir/';
      fibos.data_dir = 'fibos_data_dir/';
      
      fibos.load("http", {
          "http-server-address": "0.0.0.0:8871",
          "access-control-allow-origin": "*",
          "http-validate-host": false,
          "verbose-http-errors": true
      });
      
      fibos.load("net", {
          'p2p-listen-endpoint': "0.0.0.0:9876",
          "p2p-peer-address": ["p2p.testnet.fo:80"]
      });
      
      fibos.load("chain", {
          "delete-all-blocks": true,
          "genesis-json": "genesis.json"
      });
      
      fibos.load('chain_api');
      fibos.load('emitter');
      
      fibos.on('transaction', at => {
          let action_traces = at.action_traces[0];
      
          let account = "fiboscouncil";
      
          let act = action_traces.act;
          if (act.account === "eosio.token" && act.name === "transfer") {
              let data = act.data;
          
              if (data.from === account || data.to === account) {
                  conn.execute(`instert into eosio_token_transfers (\`from\`,\`to\`,\`quantity\`,\`memo\`,\`createdAt\`,\`updatedAt\`) values (?,?,?,?,now(),now())`, data.from, data.to, data.quantity, data.memo);
              }
          }
      })
      
      fibos.load('producer', {
          'producer-name': 'eosio',
          'enable-stale-production': true
      });
      
      fibos.start();

    上述代码,我们依赖于 emitter 插件完成了如下操作:

    1. 使用了 fibos 的 db 模块 配合 Mysql 来进行数据存储。
    2. 监听 transaction 事件,当存在数据推送时,首先判断 transaction 执行的合约是否为 eosio.token 的 transfer 操作(这一项判断和在 fibos-tracker 一章中我们 hook 的条件为 eosio.token/transfer是一致的)。
    3. 判断这笔转账的双方是否存在目标账户(fiboscouncil),如果存在,使用 Mysql 的 db 连接对象将数据存储到 Mysql 中。如果不存在,则不做任何处理。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions