fibos-tracker 是一个 FIBOS 区块链数据 API 服务框架,基于 fib-app 框架实现.
- 提供对 FIBOS 区块数据的 emitter 监听事件
- 提供 http 服务,支持 GraphQL 调用
- 支持使用 ORM模型 定制自己的数据模型 model,自定义数据表以及自定义 hook 监听数据
使用之前您可能需要去了解一下这些内容:
注意 如果您使用的是 ubuntu, 请确保使用 16.04(xenial) 及其以上的版本.
- FIBOS 版本支持
- 数据存储支持
- 安装 fibos-tracker
- Mysql
- SQLite
- 过滤某个合约,如:
eosio.token
- 过滤某个合约的 action,如:
eosio.token/transfer
- 满足过滤规则的所有 action 合并成数组传递
- 数组内每一个满足过滤规则的 action 包含 本层 action 以下所有 inline_action,并且如果存在上层 action,将携带 parent 属性,标识上层 parent 的 action 数据。
- 快速安装 FIBOS
- 查看 FIBOS 版本
- 准备示例目录
- FIBOS GraphQL 客户端
- Web GraphQL 客户端
1.3.x -> 1.4.x
fibos-tracker 从 1.4.x 版本起,修改了默认数据表结构&表名。
执行以下 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 可以大大节省链下数据存储的时间。
支持: v1.7.1.9+
快速安装: curl -s https://fibos.io/download/installer.sh | sh
fibos --install fibos-tracker
框架默认存储了 fibos_blocks 、fibos_transactions、fibos_actions 的基础数据,如下图显示:
字段 | 类型 | 备注 |
---|---|---|
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 | 记录更新时间 |
字段 | 类型 | 备注 |
---|---|---|
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 | 记录更新时间 |
| 字段 | 类型 | 备注 | | 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 | 记录更新时间 |
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 |
fib-app 的实例 app 对象,具体请阅读 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();
FIBOS emitter 插件,配合 FIBOS 的 action 插件使用。
示例:
const fibos = require("fibos");
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
tracker.emitter();
生成数据表的关联图,如果自定义了数据表,需要先调用 tracker.use 再执行。
示例:
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
//If exist other db modles,please exec tracker.use.
tracker.diagram();
使 tracker 安全停止
示例:
const Tracker = require("fibos-tracker");
const tracker = new Tracker();
tracker.stop();
自定义 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 的过滤规则说明:
hooks 的 messages 数据说明:
为了方便 hooks 业务研发,传递 messages 时做了优化:
注:每层 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
}
]
}
]
}
]
学习了解 fibos-trakcer 之后,让我们开始动手编写,使用框架写一个区块链数据存储展现的应用。
与 FIBOS 的 emiiter结合,写一个应用。 它可以同步 FIBOS TestNet 网络区块数据,并且使用 GraphQL 获取应用数据。
curl -s https://fibos.io/download/installer.sh | sh
$ fibos //Enter
输出:
(不同 FIBOS 版本输出信息不一致)
Welcome to FIBOS v1.7.1.8 Based on fibjs 0.29.0-dev.
Type ".help" for more information.
:$ mkdir example;cd example
:$ fibos --init
:$ fibos --install fibos-tracker
genesis.json 是 FIBOS TestNet 网络的配置。
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
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
});
}
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(`
{
find_fibos_blocks(
skip: 0,
limit: 10,
order: "-id"
){
id,
block_time,
block_num,
producer_block_id,
producer,
status,
createdAt,
updatedAt
}
}`)
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
}
}
}`)
学习了基础篇的应用,让我们使用 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 监听的 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
}
tracker.use(require("./addons/eosio_token_transfers.js"));
启动服务:
fibos index.js
查询 eosio_token_transfers 列表:
graphql(`
{
find_eosio_token_transfers(
skip: 0,
limit: 10,
order: "-id"
){
id,
from,
to,
quantity,
memo,
createdAt,
updatedAt
}
}`)