修改blockdata抓取, 配置从json读取

This commit is contained in:
CounterFire2023 2024-01-15 12:46:03 +08:00
parent ba4d63b185
commit acfee0ee69
8 changed files with 177 additions and 41 deletions

View File

@ -0,0 +1,19 @@
[
{
"chain": 421614,
"rpc": "https://arb-sepolia.g.alchemy.com/v2/mHoYM0SyjeizxvdjShcdOHiCrXOM_mlg",
"fromBlock": 5624211,
"filters": [{
"key": "input",
"op": "eq",
"type": "utf8_data",
"value": "data:,{\"p\":\"cf-20\",\"op\":\"check\"}"
},{
"key": "to",
"op": "eq",
"type": "address",
"value": "0x50a8e60041a206acaa5f844a1104896224be6f39"
}],
"dataModel": "CheckIn"
}
]

View File

@ -1,30 +0,0 @@
import { CheckIn } from "models/CheckIn"
import { utf8ToHex } from "utils/string.util"
export interface IScriptionCfg {
chain: number,
rpc?: string,
fromBlock: number,
filter: (event: any) => boolean,
process: (event: any) => Promise<void>,
}
const CHECKIN_DATA_STR = 'data:,{"p":"cf-20","op":"check"}'
const CHECKIN_DATA_HEX = '0x'+utf8ToHex(CHECKIN_DATA_STR)
const CHECKIN_ADDRESS = '0x50a8e60041a206acaa5f844a1104896224be6f39'
export const SCRIPTIONS_CFG: IScriptionCfg[] = [
{
chain: 421614,
// rpc: 'https://arbitrum-sepolia.infura.io/v3/25559ac58e714177b31ff48d507e7ac9',
rpc: 'https://arb-sepolia.g.alchemy.com/v2/EKR1je8ZGia332kkemNc4mtXQuFskIq3',
fromBlock: 5624211,
filter: (event: any) => {
return ( event.input === CHECKIN_DATA_HEX
&& event.to.toLowerCase() === CHECKIN_ADDRESS)
},
process: async (tx: any) => {
return CheckIn.saveEvent(tx)
}
}
]

View File

@ -0,0 +1,38 @@
export enum FilterEnum {
eq = 'eq',
ne = 'ne',
gt = 'gt',
gte = 'gte',
lt = 'lt',
lte = 'lte',
in = 'in',
nin = 'nin',
like = 'like',
nlike = 'nlike',
isNull = 'isNull',
isNotNull = 'isNotNull'
}
export enum FilterValueTypeEnum {
string = 'string',
number = 'number',
boolean = 'boolean',
utf8_data = 'utf8_data',
hex_data = 'hex_data',
address = 'address'
}
export interface IFilter {
key: string,
type: string,
value: string,
op: FilterEnum
}
export interface IScriptionCfg {
chain: number,
rpc?: string,
fromBlock: number,
filters?: IFilter[],
filter: (event: any) => boolean,
process: (event: any) => Promise<void>,
}

View File

@ -42,9 +42,9 @@ export class CheckInClass extends BaseModule {
event.count = preDayEvent.count + 1
}
try {
await CheckIn.insertOrUpdate({ from: event.from, dataTag: event.dataTag }, event)
await CheckIn.insertOrUpdate({ from: event.from, dateTag: event.dateTag }, event)
} catch (err) {
logger.info('save check record error: ', event.dataTag, event.from, err.message || err)
logger.info('save check record error: ', event.dateTag, event.from, err.message || err)
}
}

View File

@ -3,20 +3,36 @@ import logger from 'logger/logger'
import { RedisClient } from 'redis/RedisClient'
const envFile = process.env.NODE_ENV && process.env.NODE_ENV === 'production' ? `.env.production` : '.env.development'
dotenv.config({ path: envFile })
import {IScriptionCfg, SCRIPTIONS_CFG} from 'config/scriptions_cfg'
const scriptions = require('../config/scription_list.json')
import 'common/Extend'
import { AllChains, IChain } from 'chain/allchain'
import { BlockSyncSvr } from 'service/block.sync.service'
import { IScriptionCfg } from 'interface/IScriptionCfg'
import { buildScriptionFilters } from 'utils/block.util'
import { CheckIn } from 'models/CheckIn'
let svrs: any[] = []
let lock = false
let eventProcessers = {
CheckIn: CheckIn,
}
async function initEventSvrs() {
const cfgMap: Map<IChain, IScriptionCfg[]> = new Map();
for (let cfg of SCRIPTIONS_CFG) {
for (let cfg of scriptions) {
if (!cfg.filter && cfg.filters) {
cfg.filter = buildScriptionFilters(cfg)
}
cfg.process = async (event: any) => {
let processer = eventProcessers[cfg.dataModel]
if (!processer) {
logger.error('processer not found: ' + cfg.dataModel)
return
}
await processer.saveEvent(event)
}
const chainCfg = AllChains.find((chain) => chain.id === cfg.chain)
if (!chainCfg) {
logger.error('chainCfg not found: ' + cfg.chain)

View File

@ -1,10 +1,13 @@
import { IChain } from "chain/allchain";
import { ethBlockNumber, retryEthBlockNumber } from "chain/chain.api";
import { IScriptionCfg } from "config/scriptions_cfg";
import { retryEthBlockNumber } from "chain/chain.api";
import { IScriptionCfg } from "interface/IScriptionCfg";
import logger from "logger/logger";
import { CheckIn } from "models/CheckIn";
import { RedisClient } from "redis/RedisClient";
import { getPastBlocksIter } from "utils/block.util";
import { formatDate } from "utils/date.util";
export class BlockSyncSvr {
chainCfg: IChain
scriptionCfgs: IScriptionCfg[] = []
@ -66,8 +69,13 @@ export class BlockSyncSvr {
}
for (let j = 0; j < this.scriptionCfgs.length; j++) {
const cfg = this.scriptionCfgs[j];
if (cfg.filter(tx)) {
if (cfg.filter && cfg.filter(tx) ) {
try {
await cfg.process(tx)
} catch (err) {
logger.error('process tx error: ', err.message || err)
}
}
}
}

View File

@ -1,6 +1,8 @@
import { batchEthBlocks } from "chain/chain.api";
import { IScriptionCfg } from "interface/IScriptionCfg";
import logger from "logger/logger";
import { RedisClient } from "redis/RedisClient";
import { utf8ToHex } from "./string.util";
const MAX_BATCH_AMOUNT = 500
const REQUEST_INTERVAL = 0.5 * 1000
@ -84,3 +86,86 @@ export function* getPastBlocksIter({chainId, rpc, fromBlock, amount}
remain -= MAX_BATCH_AMOUNT
}
}
export const buildScriptionFilters = (cfg: IScriptionCfg) => {
if (cfg.filter) {
return cfg.filter
}
if (cfg.filters) {
let body = ''
for (let i = 0; i < cfg.filters.length; i++) {
if (i > 0) {
body += ' && '
}
let filter = cfg.filters[i]
let value: any = filter.value
let op = ''
switch (filter.op) {
case 'eq':
op = '==='
break
case 'ne':
op = '!=='
break
case 'gt':
op = '>'
break
case 'gte':
op = '>='
break
case 'lt':
op = '<'
break
case 'lte':
op = '<='
break
case 'in':
op = 'in'
break
case 'nin':
op = 'nin'
break
case 'like':
op = 'like'
break
case 'nlike':
op = 'nlike'
break
case 'isNull':
body += `!event.${filter.key}`
break
case 'isNotNull':
body += `!!event.${filter.key}`
break
}
if (filter.type === 'address') {
value = `'${value.toLowerCase()}'`
} else if (filter.type === 'utf8_data') {
value = `'0x${utf8ToHex(value)}'`
} else if (filter.type === 'hex_data') {
value = `'${value.indexOf('0x') === 0 ? value : '0x'+value}'`
} else if (filter.type === 'number') {
value = parseInt(value)
} else if (filter.type === 'boolean') {
value = !!value
} else {
value = `'${value}'`
}
if (op) {
if (op === 'in') {
body += `event.${filter.key}.indexOf(${value}) >= 0`
} else if (op === 'nin') {
body += `!(event.${filter.key}.indexOf(${value}) >= 0)`
} else if (op === 'nlike') {
body += `!new RegExp(${value}).test(event.${filter.key})`
} else if (op === 'like') {
body += new RegExp(value).test(`event.${filter.key}`)
} else {
body += `event.${filter.key}${op}${value}`
}
}
}
return new Function('event', `return ${body}`)
}
}