Skip to content

Commit

Permalink
feat: reindex cw20 service ( main ) (#277)
Browse files Browse the repository at this point in the history
* feat: reindex cw20 service

* test: test cw20 reindexing

* fix: idiot

* refactor: code

* feat: api admin
  • Loading branch information
phamphong9981 authored Aug 16, 2023
1 parent 32d103a commit 685bb4b
Show file tree
Hide file tree
Showing 14 changed files with 807 additions and 71 deletions.
5 changes: 4 additions & 1 deletion ci/config.json.ci
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@
"cw20": {
"blocksPerCall": 100,
"millisecondRepeatJob": 2000,
"key": "cw20"
"key": "cw20",
"reindexHistory": {
"limitRecordGet": 500
}
},
"dashboardStatistics": {
"millisecondCrawl": 10000,
Expand Down
5 changes: 4 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@
"cw20": {
"blocksPerCall": 100,
"millisecondRepeatJob": 2000,
"key": "cw20"
"key": "cw20",
"reindexHistory": {
"limitRecordGet": 500
}
},
"crawlContractEvent": {
"key": "crawlContractEvent",
Expand Down
10 changes: 10 additions & 0 deletions src/common/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export const BULL_JOB_NAME = {
REINDEX_CW721_HISTORY: 'reindex:cw721-history',
HANDLE_MIGRATE_CONTRACT: 'handle:migrate-contract',
JOB_REDECODE_TX: 'job:redecode-tx',
REINDEX_CW20_CONTRACT: 'reindex:cw20-contract',
REINDEX_CW20_HISTORY: 'reindex:cw20-history',
};

export const SERVICE = {
Expand Down Expand Up @@ -223,6 +225,14 @@ export const SERVICE = {
path: 'v1.ReDecodeTx',
},
},
Cw20ReindexingService: {
key: 'Cw20ReindexingService',
name: 'v1.Cw20ReindexingService',
Reindexing: {
key: 'reindexing',
path: 'v1.Cw20ReindexingService.reindexing',
},
},
},
};

Expand Down
2 changes: 2 additions & 0 deletions src/models/cw20_activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Cw20Contract } from './cw20_contract';
import { SmartContract } from './smart_contract';

export class Cw20Event extends BaseModel {
static softDelete = false;

[relation: string]: any;

id!: number;
Expand Down
2 changes: 2 additions & 0 deletions src/models/cw20_contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface IContractInfo {
name?: string;
}
export class Cw20Contract extends BaseModel {
static softDelete = false;

[relation: string]: any;

id!: number;
Expand Down
2 changes: 2 additions & 0 deletions src/models/cw20_holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Cw20Contract } from './cw20_contract';
import { SmartContract } from './smart_contract';

export class CW20Holder extends BaseModel {
static softDelete = false;

[relation: string]: any;

id?: number;
Expand Down
2 changes: 2 additions & 0 deletions src/models/cw20_total_holder_stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import BaseModel from './base';
import { Cw20Contract } from './cw20_contract';

export class CW20TotalHolderStats extends BaseModel {
static softDelete = false;

[relation: string]: any;

date!: Date;
Expand Down
6 changes: 6 additions & 0 deletions src/services/api-gateways/api_gateway.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ import { bullBoardMixin } from '../../mixins/bullBoard/bullBoard.mixin';
mappingPolicy: 'restrict', // allow action called with exact method
whitelist: ['v2.dashboard-statistics.*', 'v2.graphql.*'],
},
{
path: '/admin',
autoAliases: true, // allow generate rest info (GET/PUT/POST...) in the services
mappingPolicy: 'restrict', // allow action called with exact method
whitelist: ['v1.cw20-admin.*'],
},
],
// empty cors object will have moleculer to generate handler for preflight request and CORS header which allow all origin
cors: {},
Expand Down
45 changes: 45 additions & 0 deletions src/services/api-gateways/cw20_admin.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Post, Service } from '@ourparentcenter/moleculer-decorators-extended';
import { Context, ServiceBroker } from 'moleculer';
import networks from '../../../network.json' assert { type: 'json' };
import BaseService from '../../base/base.service';

@Service({
name: 'cw20-admin',
version: 1,
})
export default class Cw20AdminService extends BaseService {
public constructor(public broker: ServiceBroker) {
super(broker);
}

@Post('/cw20-reindexing', {
name: 'cw20Reindexing',
params: {
chainid: {
type: 'string',
optional: false,
enum: networks.map((network) => network.chainId),
},
contractAddress: {
type: 'string',
optional: false,
},
},
})
async cw20ReindexingByChainId(
ctx: Context<
{ chainid: string; contractAddress: string },
Record<string, unknown>
>
) {
const selectedChain = networks.find(
(network) => network.chainId === ctx.params.chainid
);
return this.broker.call(
`v1.Cw20ReindexingService.reindexing@${selectedChain?.moleculerNamespace}`,
{
contractAddress: ctx.params.contractAddress,
}
);
}
}
98 changes: 72 additions & 26 deletions src/services/cw20/cw20.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Service } from '@ourparentcenter/moleculer-decorators-extended';
import { Queue } from 'bullmq';
import { Knex } from 'knex';
import _ from 'lodash';
import { ServiceBroker } from 'moleculer';
Expand Down Expand Up @@ -34,6 +35,13 @@ export const CW20_ACTION = {
BURN_FROM: 'burn_from',
SEND_FROM: 'send_from',
};
export interface ICw20ReindexingHistoryParams {
smartContractId: number;
startBlock: number;
endBlock: number;
prevId: number;
contractAddress: string;
}
@Service({
name: SERVICE.V1.Cw20.key,
version: 1,
Expand Down Expand Up @@ -205,41 +213,38 @@ export default class Cw20Service extends BullableService {
}
}

async getCw20ContractEvents(startBlock: number, endBlock: number) {
async getCw20ContractEvents(
startBlock: number,
endBlock: number,
smartContractId?: number,
page?: { prevId: number; limit: number }
) {
return SmartContractEvent.query()
.alias('smart_contract_event')
.withGraphJoined(
'[message(selectMessage), tx(selectTransaction), attributes(selectAttribute), smart_contract(selectSmartContract).code(selectCode)]'
)
.modifiers({
selectCode(builder) {
builder.select('type');
},
selectTransaction(builder) {
builder.select('hash', 'height');
},
selectMessage(builder) {
builder.select('sender', 'content');
},
selectAttribute(builder) {
builder.select('key', 'value');
},
selectSmartContract(builder) {
builder.select('address', 'id');
},
})
.withGraphFetched('attributes(selectAttribute)')
.joinRelated('[message, tx, smart_contract.code]')
.where('smart_contract:code.type', 'CW20')
.where('tx.height', '>', startBlock)
.andWhere('tx.height', '<=', endBlock)
.modify((builder) => {
if (smartContractId) {
builder.andWhere('smart_contract.id', smartContractId);
}
if (page) {
builder
.andWhere('smart_contract_event.id', '>', page.prevId)
.orderBy('smart_contract_event.id', 'asc')
.limit(page.limit);
}
})
.select(
'message.sender as sender',
'smart_contract.address as contract_address',
'smart_contract_event.action',
'smart_contract_event.event_id as event_id',
'smart_contract_event.index',
'smart_contract_event.event_id',
'smart_contract.id as smart_contract_id',
'tx.height as height',
'smart_contract_event.id as smart_contract_event_id'
'smart_contract_event.id as smart_contract_event_id',
'tx.hash',
'tx.height'
)
.orderBy('smart_contract_event.id', 'asc');
}
Expand Down Expand Up @@ -304,4 +309,45 @@ export default class Cw20Service extends BullableService {
}
return super._start();
}

@QueueHandler({
queueName: BULL_JOB_NAME.REINDEX_CW20_HISTORY,
jobName: BULL_JOB_NAME.REINDEX_CW20_HISTORY,
})
public async reindexHistory(_payload: ICw20ReindexingHistoryParams) {
const { smartContractId, startBlock, endBlock, prevId, contractAddress } =
_payload;
// insert data from event_attribute_backup to event_attribute
const { limitRecordGet } = config.cw20.reindexHistory;
const events = await this.getCw20ContractEvents(
startBlock,
endBlock,
smartContractId,
{ limit: limitRecordGet, prevId }
);
if (events.length > 0) {
await knex.transaction(async (trx) => {
await this.handleCw20Histories(events, trx);
});
await this.createJob(
BULL_JOB_NAME.REINDEX_CW20_HISTORY,
BULL_JOB_NAME.REINDEX_CW20_HISTORY,
{
smartContractId,
startBlock,
endBlock,
prevId: events[events.length - 1].smart_contract_event_id,
contractAddress,
} satisfies ICw20ReindexingHistoryParams,
{
removeOnComplete: true,
}
);
} else {
const queue: Queue = this.getQueueManager().getQueue(
BULL_JOB_NAME.REINDEX_CW20_CONTRACT
);
(await queue.getJob(contractAddress))?.remove();
}
}
}
Loading

0 comments on commit 685bb4b

Please sign in to comment.