fibos-tracker
Version:
a tracking data and api service based on FIBOS/EOS blockchain nodes.
688 lines (531 loc) • 14.5 kB
Markdown
# fibos-tracker
[](https://www.npmjs.org/package/fibos-tracker)
[](https://travis-ci.org/fibosio/fibos-tracker)
fibos-tracker 是一个 FIBOS 区块链数据 API 服务框架,基于 [fib-app](https://github.com/fibjs/fib-app) 框架实现.
- 提供对 FIBOS 区块数据的 emitter 监听事件
- 提供 http 服务,支持 GraphQL 调用
- 支持使用 ORM模型 定制自己的数据模型 model,自定义数据表以及自定义 hook 监听数据
使用之前您可能需要去了解一下这些内容:
- [FIBOS](https://fibos.io)
- [GraphQL](http://graphql.cn/)
- [fib-app](https://github.com/fibjs/fib-app)
**注意** 如果您使用的是 ubuntu, 请确保使用 16.04(xenial) 及其以上的版本.
## 目录
<dl>
<dt><a href="#fibos-版本支持">FIBOS 版本支持</a></dt>
<dd></dd>
<dl>
<dt><a href="#数据存储支持">数据存储支持</a></dt>
<dd></dd>
<dl>
<dt><a href="#安装-fibos-tracker">安装 fibos-tracker</a></dt>
<dd></dd>
<dl>
<dt><a href="#框架说明及-API-使用">框架说明及 API 使用</a></dt>
<dd></dd>
<dt><a href="#example-快速应用">Example-快速应用</a></dt>
<dd></dd>
<dt><a href="#高级篇-使用-orm-自定义数据">高级篇-使用 ORM 自定义数据</a></dt>
<dd></dd>
</dl>
## 升级指南
> 1.3.x -> 1.4.x
fibos-tracker 从 1.4.x 版本起,修改了默认数据表结构&表名。
执行以下 sql 语句进行表结构升级:
```sql
ALTER TABLE `transactions` RENAME TO `fibos_transactions`;
ALTER TABLE `blocks` RENAME TO `fibos_blocks`;
ALTER TABLE `fibos_transactions` ADD `contract_action` varchar(64);
ALTER TABLE `fibos_transactions` ADD INDEX contract_action_index (contract_action);
ALTER TABLE `fibos_transactions` ADD `block_id` bigint(20) DEFAULT NULL;
```
## 测试对比
> 使用 FIBOS 主网数据进行 replay 测试,区块数据高度:70166754 机器性能:4核 8G
测试结果如下:
| 测试方式 | 耗时 |
| --- | --- |
| 使用区块数据 replay | 12H |
| 使用区块数据 + emitter 插件 replay | 12H |
| 使用 fibos-tracker的 db replay | 1H |
由上结果可以得知,使用 fibos-tracker 的 db replay 可以大大节省链下数据存储的时间。
## FIBOS 版本支持
支持: `v1.7.1.9+`
快速安装: `curl -s https://fibos.io/download/installer.sh | sh`
## 数据存储支持
- Mysql
- SQLite
## 安装 fibos-tracker
```
fibos --install fibos-tracker
```
## 框架说明及 API 使用
### fibos-tracker DB 说明
框架默认存储了 fibos_blocks 、fibos_transactions、fibos_actions 的基础数据,如下图显示:

#### fibos_blocks 表数据
| 字段 | 类型 | 备注|
|---------------------|--------|------------|
| id | Number | 自增长 id |
| block_num | Number | 区块高度 |
| block_time | Date | 区块时间 |
| producer_block_id | String | 区块 hash |
| producer | String | 区块 producer |
| previous | String | 上一块 hash |
| status | String | 可逆状态 |
| createdAt | Date | 记录创建时间 |
| updatedAt | Date | 记录更新时间 |
#### fibos_transactions 表数据
| 字段 | 类型 | 备注|
|---------------------|--------|------------|
| id | bigint | 自增长 id |
| trx_id | String | 交易 hash |
| rawData | JSON | 原始数据 |
| producer_block_id | String | 区块 hash |
| contract_action | String | 合约/动作 |
| block_id | bigint | 事务关联区块id |
| createdAt | Date | 记录创建时间 |
| updatedAt | Date | 记录更新时间 |
#### fibos_actions 表数据
| 字段 | 类型 | 备注 |
| id | bigint | 自增长 id |
| trx_id | String | 交易id |
| rawData | JSON | action 对应的数据 |
| contract_action | String | 合约/动作 |
| transaction_id | String | 关联 transaction id |
| parent_id | String | inline 上级id |
| createdAt | Date | 记录创建时间 |
| updatedAt | Date | 记录更新时间 |
### fibos-tracker API 介绍
#### Tracker.Config
Config 是 Tracker 全局属性,可以使用该属性快速修改配置,如:修改存储引擎配置。
示例:
```
const Tracker = require("fibos-tracker");
Tracker.Config.DBconnString = "mysql://root:123456@127.0.0.1/fibos_chain";
Tracker.Config.replay = true;
Tracker.Config.replayStatrBn = 1000;
```
| name | desc | default|
|---------------------|--------|------------|
| DBconnString | 数据存储引擎 | 默认使用 SQLite 存储引擎 |
| replay | 是否开启 DB replay | false |
| replayStatrBn | DB replay 指定高度(需要配合replay) | 0 |
#### tracker.app
fib-app 的实例 app 对象,具体请阅读 [fib-app](https://github.com/fibjs/fib-app) 相关文档。
tracker.app 对象可支持路由访问。
示例:
```
const http = require("http");
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
let httpServer = new http.Server("", 8080, {
'/1.0/app': tracker.app
});
httpServer.run();
```
#### tracker.emitter
FIBOS emitter 插件,配合 FIBOS 的 action 插件使用。
示例:
```
const fibos = require("fibos");
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
tracker.emitter();
```
#### tracker.diagram
生成数据表的关联图,如果自定义了数据表,需要先调用 tracker.use 再执行。
示例:
```
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
//If exist other db modles,please exec tracker.use.
tracker.diagram();
```
#### tracker.stop
使 tracker 安全停止
示例:
```
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
tracker.stop();
```
#### tracker.use
自定义 hook 监听数据,使用 ORM 模型自定义 DB 存储以及处理。
示例:
```
const fibos = require("fibos");
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
tracker.use({
defines: [(db) => {
// ORM DB Define
}, (db) => {
// ORM DB Define
}],
hooks: {
"eosio.token/transfer": (db, messages) => {
// hook Tracker messages
},
"eosio/newaccount": (db, messages) => {
// hook Tracker messages
}
}
});
```
defines 支持数组形式,满足某个 model 需要多个数据表的操作场景。
tracker.use 参数定义:
| params | type | desc |
|---------------------|--------|--------|
| model | Object | 自定义数据对象,包含 defines 和 hooks |
`model` 内部参数定义:
| key | type | desc | params|
|---------------------|--------|--------|--------|
| defines | Function |使用 ORM 模型定义数据表,提供 API 访问 | `(db) => {}`参数 db 是 ORM 对象,可用于操作数据层 |
| hooks | Function | 支持过滤 action 数据的 hook function | `(db, messages) => {}` 参数 db 是 ORM 对象,参数 messages 是 action 原始数据集合 |
hooks 的过滤规则说明:
- 过滤某个合约,如:`eosio.token`
- 过滤某个合约的 action,如:`eosio.token/transfer`
hooks 的 messages 数据说明:
为了方便 hooks 业务研发,传递 messages 时做了优化:
- 满足过滤规则的所有 action 合并成数组传递
- 数组内每一个满足过滤规则的 action 包含 本层 action 以下所有 inline_action,并且如果存在上层 action,将携带 parent 属性,标识上层 parent 的 action 数据。
注:每层 `parent_id` 是该层 `action` 上级的 DB 自增长 id。
举一个返回示例结构:
```
[
{
"inline_traces": [
{
"parent": ... parent_id => 1
"inline_traces": [
{
"parent": ... parent_id => 2
"parent": ... parent_id => 1
},
{
"parent": ... parent_id => 2
"parent": ... parent_id => 1
}
]
}
]
}
]
```
## Example 快速应用
[Example 源码](./examples)
学习了解 fibos-trakcer 之后,让我们开始动手编写,使用框架写一个区块链数据存储展现的应用。
与 FIBOS 的 emiiter结合,写一个应用。 它可以同步 FIBOS TestNet 网络区块数据,并且使用 GraphQL 获取应用数据。
[FIBOS TestNet WebSite](https://testnet.fibos.fo/#/):
### 环境准备
1. 快速安装 FIBOS
```
curl -s https://fibos.io/download/installer.sh | sh
```
2. 查看 FIBOS 版本
```
$ fibos //Enter
```
输出:
(不同 FIBOS 版本输出信息不一致)
```
Welcome to FIBOS v1.7.1.8 Based on fibjs 0.29.0-dev.
Type ".help" for more information.
```
3. 准备示例目录
```
:$ mkdir example;cd example
:$ fibos --init
:$ fibos --install fibos-tracker
```
### 编写例子
[genesis.json](./examples/genesis.json) 是 FIBOS TestNet 网络的配置。
[index.js](./examples/index.js):
```
const http = require("http");
const fibos = require("fibos");
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
fibos.config_dir = "./data";
fibos.data_dir = "./data";
fibos.load("http", {
"http-server-address": "0.0.0.0:8870",
"access-control-allow-origin": "*",
"http-validate-host": false,
"verbose-http-errors": true
});
fibos.load("net", {
"p2p-peer-address": ["p2p-testnet.fibos.fo:9870"],
"p2p-listen-endpoint": "0.0.0.0:9870"
});
fibos.load("producer");
fibos.load("chain", {
"contracts-console": true,
"delete-all-blocks": true,
"genesis-json": "genesis.json"
});
fibos.load("chain_api");
tracker.emitter();
fibos.start();
let httpServer = new http.Server("", 8080, [
(req) => {
req.session = {};
}, {
'^/ping': (req) => {
req.response.write("pong");
},
'/1.0/app': tracker.app,
"*": [function(req) {}]
},
function(req) {}
]);
httpServer.crossDomain = true;
httpServer.asyncRun();
```
### 启动服务
```
fibos index.js
```
### 使用 GraphQL 方式获取应用数据
1. FIBOS GraphQL 客户端
```
const http = require("http");
let graphql = function(body) {
return http.post(`http://127.0.0.1:8080/1.0/app/`, {
headers: {
'Content-Type': 'application/graphql'
},
body: body
});
}
```
2. Web GraphQL 客户端
Jquery Ajax 示例:
```
let graphql = function(body) {
$.ajax({
type: "POST",
url: "http://127.0.0.1:8080/1.0/app",
data: body,
headers: {
"Content-Type": "application/graphql"
},
success: (res) => {
console.log("success");
},
error: (res) => {
console.log("error");
}
});
}
```
#### GraphQL 获取应用-列表数据
```
graphql(`
{
find_fibos_blocks(
skip: 0,
limit: 10,
order: "-id"
){
id,
block_time,
block_num,
producer_block_id,
producer,
status,
createdAt,
updatedAt
}
}`)
```
#### GraphQL 获取应用-详情数据
```
graphql(`
{
find_fibos_blocks(
where:{
id: 23
}
) {
id,
block_time,
block_num,
producer_block_id,
producer,
status,
createdAt,
updatedAt,
transactions{
id,
trx_id,
rawData,
createdAt,
updatedAt
}
}
}`)
```
## 高级篇-使用 ORM 自定义数据
[Example 源码](./examples)
学习了基础篇的应用,让我们使用 fibos-tracker 的 `use` 完成一个仅监控 eosio.token 合约 transfer 的应用。
### 环境准备
基于上面的环境应用,让我们创建一个目录:
```
:$ mkdir addons;cd addons;
```
### 设计&&定义一个数据模型
设计数据表 eosio_token_transfers:
| 字段 | 类型 | 备注|
|---------------------|--------|------------|
| id | Number | 自增长 id |
| from | String | 转出方 |
| to | String | 转入方 |
| quantity | String | 交易数量 |
| memo | String | memo |
| createdAt | Date | 记录创建时间 |
| updatedAt | Date | 记录更新时间 |
使用 ORM Define 数据表逻辑:
```
let defines = [db => {
return db.define('eosio_token_transfers', {
from: {
required: true,
type: "text",
size: 12
},
to: {
required: true,
type: "text",
size: 12
},
quantity: {
required: true,
type: "text",
size: 256
},
memo: {
type: "text",
size: 256
}
}, {
hooks: {},
methods: {},
validations: {},
functions: {},
ACL: function(session) {
return {
'*': {
find: true,
read: true
}
};
}
});
}];
```
### 定义 hook 数据监听
hook 监听的 messages 是一组系统排序过滤后的原始区块数据。
tracker.use 需要对 hook 的接受数据进行过滤。
```
let hooks = {
"eosio.token/transfer": (db, messages) => {
let eosio_token_transfers = db.models.eosio_token_transfers;
try {
db.trans(() => {
messages.forEach((m) => {
eosio_token_transfers.createSync(m.act.data);
});
});
} catch (e) {
console.error("eosio.token/transfer Error:", e);
}
}
}
```
### 保存自定义数据模型代码
保存下面代码到 eosio_token_transfers.js:
```
let defines = [db => {
return db.define('eosio_token_transfers', {
from: {
required: true,
type: "text",
size: 12
},
to: {
required: true,
type: "text",
size: 12
},
quantity: {
required: true,
type: "text",
size: 256
},
memo: {
type: "text",
size: 256
}
}, {
hooks: {},
methods: {},
validations: {},
functions: {},
ACL: function(session) {
return {
'*': {
find: true,
read: true
}
};
}
});
}];
let hooks = {
"eosio.token/transfer": (db, messages) => {
let eosio_token_transfers = db.models.eosio_token_transfers;
try {
db.trans(() => {
messages.forEach((m) => {
eosio_token_transfers.createSync(m.data);
});
});
} catch (e) {
console.error("eosio.token/transfer Error:", e);
}
}
}
module.exports = {
defines: defines,
hooks: hooks
}
```
### 使用 fibos-tracker 加载新的数据模型
```
tracker.use(require("./addons/eosio_token_transfers.js"));
```
#### 启动服务&&使用 GraphQL 获取数据
启动服务:
```
fibos index.js
```
查询 eosio_token_transfers 列表:
```
graphql(`
{
find_eosio_token_transfers(
skip: 0,
limit: 10,
order: "-id"
){
id,
from,
to,
quantity,
memo,
createdAt,
updatedAt
}
}`)
```