From a0bfeb81192db302a69a935855ce048425e9e045 Mon Sep 17 00:00:00 2001 From: sh-cha Date: Tue, 14 May 2024 16:38:59 +0900 Subject: [PATCH 01/19] add splitter between variables when making withdrawal hash --- jest.config.ts | 2 +- src/lib/storage.spec.ts | 6 ------ src/lib/storage.ts | 11 +++++++++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/jest.config.ts b/jest.config.ts index bb5c5c0..d3e7afd 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -2,7 +2,7 @@ import type { Config } from '@jest/types'; // Jest configuration const config: Config.InitialOptions = { - roots: ['/src', '/src/test'], + roots: ['/src'], transform: { '^.+\\.ts?$': 'ts-jest', }, diff --git a/src/lib/storage.spec.ts b/src/lib/storage.spec.ts index 5558cae..3671af2 100644 --- a/src/lib/storage.spec.ts +++ b/src/lib/storage.spec.ts @@ -47,11 +47,5 @@ describe('WithdrawStorage', () => { ]) ).toString('base64') expect(airdrop.verify(merkleProof, target)).toBeTruthy() - - expect(merkleRoot).toEqual('EYgpXs1b+Z3AdGqjjtJHylrGzCjXtBKDD2UTPXelUk4=') - expect(merkleProof).toEqual([ - '5eJNy8mEqvyhysgWCqi7JQ7K602FtSpz+wDRNQitQMc=' - ]) - expect(outputRoot).toEqual('euaoJcFRXfV/6F0AiC0vYwXUY4NPHfCn9LbFMPieNsA=') }) }) diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 03a1c11..6372f54 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -3,6 +3,8 @@ import { sha3_256 } from './util' import { WithdrawalTx } from './types' import { AccAddress } from 'initia-l1' +const SPLITTER = Buffer.from('|') + function convertHexToBase64(hex: string): string { return Buffer.from(hex, 'hex').toString('base64') } @@ -26,8 +28,11 @@ export class WithdrawStorage { bridge_id_buf, sequence_buf, AccAddress.toBuffer(tx.sender), + SPLITTER, AccAddress.toBuffer(tx.receiver), + SPLITTER, Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, amount_buf ]) ) @@ -57,8 +62,11 @@ export class WithdrawStorage { bridge_id_buf, sequence_buf, AccAddress.toBuffer(tx.sender), + SPLITTER, AccAddress.toBuffer(tx.receiver), + SPLITTER, Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, amount_buf ]) ) @@ -91,8 +99,11 @@ export class WithdrawStorage { bridge_id_buf, sequence_buf, AccAddress.toBuffer(tx.sender), + SPLITTER, AccAddress.toBuffer(tx.receiver), + SPLITTER, Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, amount_buf ]) ) From d2011e8a6e7900f75d2959500506f34cae9fdb2d Mon Sep 17 00:00:00 2001 From: sh-cha Date: Tue, 14 May 2024 17:10:29 +0900 Subject: [PATCH 02/19] add test --- src/lib/storage.spec.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/lib/storage.spec.ts b/src/lib/storage.spec.ts index 3671af2..e7e4542 100644 --- a/src/lib/storage.spec.ts +++ b/src/lib/storage.spec.ts @@ -29,6 +29,39 @@ const v1 = [ ] describe('WithdrawStorage', () => { + it('getmerkleproof', async () => { + const tx = { + bridge_id: BigInt(1), + sequence: BigInt(4), + sender: '0000000000000000000000000000000000000004', + receiver: '0000000000000000000000000000000000000001', + l1_denom: 'l1denom', + amount: BigInt(3000000) + } + const bridge_id_buf = Buffer.alloc(8) + bridge_id_buf.writeBigInt64BE(tx.bridge_id) + + const sequence_buf = Buffer.alloc(8) + sequence_buf.writeBigInt64BE(tx.sequence) + + const amount_buf = Buffer.alloc(8) + amount_buf.writeBigInt64BE(tx.amount) + + const result = sha3_256( + Buffer.concat([ + bridge_id_buf, + sequence_buf, + Buffer.from(tx.sender, 'hex'), + Buffer.from('|'), + Buffer.from(tx.receiver, 'hex'), + Buffer.from('|'), + Buffer.from(tx.l1_denom, 'utf8'), + Buffer.from('|'), + amount_buf + ])).toString('base64') + expect(result == "F+mzhRVdcwLS5tk2NDB2MbgMm7A0nk39G+NGEjXpTV0=").toBeTruthy() + }) + it('verify v1', async () => { const airdrop = new WithdrawStorage(v1) const target = v1[0] From 5faa52952992e20b16e5af9c31f32f4152c3a9a6 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 21:13:17 +0900 Subject: [PATCH 03/19] fix output submit --- src/worker/bridgeExecutor/monitor/helper.ts | 7 +++ src/worker/bridgeExecutor/monitor/l2.ts | 10 +++- src/worker/outputSubmitter/outputSubmitter.ts | 57 +++++++++++-------- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/worker/bridgeExecutor/monitor/helper.ts b/src/worker/bridgeExecutor/monitor/helper.ts index b8d49b3..fde7e36 100644 --- a/src/worker/bridgeExecutor/monitor/helper.ts +++ b/src/worker/bridgeExecutor/monitor/helper.ts @@ -91,6 +91,13 @@ class MonitorHelper { }) } + public async getAllOutput( + manager: EntityManager, + entityClass: EntityTarget, + ): Promise { + return await manager.getRepository(entityClass).find() + } + public async saveEntity( manager: EntityManager, entityClass: EntityTarget, diff --git a/src/worker/bridgeExecutor/monitor/l2.ts b/src/worker/bridgeExecutor/monitor/l2.ts index 419b646..1aafe3b 100644 --- a/src/worker/bridgeExecutor/monitor/l2.ts +++ b/src/worker/bridgeExecutor/monitor/l2.ts @@ -114,9 +114,15 @@ export class L2Monitor extends Monitor { return true } - async checkSubmissionInterval(): Promise { + async checkSubmissionInterval(manager: EntityManager): Promise { const lastOutputSubmitted = await getLastOutputInfo(this.bridgeId) + const lastOutputFromDB = await this.helper.getLastOutputFromDB( + manager, + ExecutorOutputEntity + ) + if (!lastOutputFromDB) return true if (lastOutputSubmitted) { + if (lastOutputFromDB.outputIndex !== lastOutputSubmitted.output_index) return false const lastOutputSubmittedTime = lastOutputSubmitted.output_proposal.l1_block_time const bridgeInfo = await getBridgeInfo(this.bridgeId) @@ -133,7 +139,7 @@ export class L2Monitor extends Monitor { } async handleOutput(manager: EntityManager): Promise { - if (!(await this.checkSubmissionInterval())) { + if (!(await this.checkSubmissionInterval(manager))) { if (this.currentHeight % 10 === 0) this.logger.info( `[handleOutput - ${this.name()}] Submission interval not reached` diff --git a/src/worker/outputSubmitter/outputSubmitter.ts b/src/worker/outputSubmitter/outputSubmitter.ts index 522f92c..9a4dbbb 100644 --- a/src/worker/outputSubmitter/outputSubmitter.ts +++ b/src/worker/outputSubmitter/outputSubmitter.ts @@ -1,4 +1,4 @@ -import { MsgProposeOutput } from 'initia-l1' +import { Msg, MsgProposeOutput } from 'initia-l1' import { INTERVAL_OUTPUT } from '../../config' import { ExecutorOutputEntity } from '../../orm' import { delay } from 'bluebird' @@ -17,6 +17,8 @@ import { } from '../../lib/walletL1' import { updateOutputUsageMetrics } from '../../lib/metrics' +const MAX_OUTPUT_PROPOSAL = 50 + export class OutputSubmitter { private db: DataSource private submitter: TxWalletL1 @@ -44,31 +46,28 @@ export class OutputSubmitter { } } - async getOutput( + async getOutputs( manager: EntityManager - ): Promise { + ): Promise { try { const lastOutputInfo = await getLastOutputInfo(this.bridgeId) if (lastOutputInfo) { this.syncedOutputIndex = lastOutputInfo.output_index + 1 } - const output = await this.helper.getOutputByIndex( + const outputs = await this.helper.getAllOutput( manager, ExecutorOutputEntity, - this.syncedOutputIndex ) - if (!output) return null - - return output + return outputs.filter(output => output.outputIndex >= this.syncedOutputIndex) } catch (err) { if (err.response?.data.type === ErrorTypes.NOT_FOUND_ERROR) { logger.warn( `waiting for output index from L1: ${this.syncedOutputIndex}, processed block number: ${this.processedBlockNumber}` ) await delay(INTERVAL_OUTPUT) - return null + return [] } throw err } @@ -76,18 +75,21 @@ export class OutputSubmitter { async processOutput() { await this.db.transaction(async (manager: EntityManager) => { - const output = await this.getOutput(manager) - if (!output) { + const outputs = await this.getOutputs(manager) + if (outputs.length === 0) { logger.info( `waiting for output index from DB: ${this.syncedOutputIndex}, processed block number: ${this.processedBlockNumber}` ) return } - await this.proposeOutput(output) - logger.info( - `successfully submitted! output index: ${this.syncedOutputIndex}, output root: ${output.outputRoot} (${output.startBlockNumber}, ${output.endBlockNumber})` - ) + const chunkedOutputs: ExecutorOutputEntity[] = [] + + for (let i = 0; i < outputs.length; i += MAX_OUTPUT_PROPOSAL) { + chunkedOutputs.push(...outputs.slice(i, i + MAX_OUTPUT_PROPOSAL)) + await this.proposeOutputs(chunkedOutputs) + chunkedOutputs.length = 0 + } }) } @@ -95,16 +97,21 @@ export class OutputSubmitter { this.isRunning = false } - private async proposeOutput(outputEntity: ExecutorOutputEntity) { - const msg = new MsgProposeOutput( - this.submitter.key.accAddress, - this.bridgeId, - outputEntity.endBlockNumber, - outputEntity.outputRoot - ) - - await this.submitter.transaction([msg], undefined, 1000 * 60 * 10) // 10 minutes + private async proposeOutputs(outputEntities: ExecutorOutputEntity[]) { + const msgs: Msg[] = [] + + for (const output of outputEntities) { + msgs.push( + new MsgProposeOutput( + this.submitter.key.accAddress, + this.bridgeId, + output.endBlockNumber, + output.outputRoot + ) + ) + } - this.processedBlockNumber = outputEntity.endBlockNumber + await this.submitter.transaction(msgs, undefined, 1000 * 60 * 10) // 10 minutes + logger.info(`succeed to propose ${outputEntities.length} outputs from ${outputEntities[0].outputIndex} to ${outputEntities[outputEntities.length - 1].outputIndex}`) } } From 6a32de1dab997db2f0073bf0509277c8d88fd451 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 21:15:21 +0900 Subject: [PATCH 04/19] add cond for output --- src/worker/bridgeExecutor/monitor/helper.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/worker/bridgeExecutor/monitor/helper.ts b/src/worker/bridgeExecutor/monitor/helper.ts index fde7e36..ca68696 100644 --- a/src/worker/bridgeExecutor/monitor/helper.ts +++ b/src/worker/bridgeExecutor/monitor/helper.ts @@ -95,7 +95,9 @@ class MonitorHelper { manager: EntityManager, entityClass: EntityTarget, ): Promise { - return await manager.getRepository(entityClass).find() + return await manager.getRepository(entityClass).find({ + order: { outputIndex: 'ASC' } as any + }) } public async saveEntity( From 81c0f09199777948cf89b9a7ad290593932ec907 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 21:58:56 +0900 Subject: [PATCH 05/19] update processedBlockNumber --- src/worker/outputSubmitter/outputSubmitter.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/worker/outputSubmitter/outputSubmitter.ts b/src/worker/outputSubmitter/outputSubmitter.ts index 9a4dbbb..3ec7187 100644 --- a/src/worker/outputSubmitter/outputSubmitter.ts +++ b/src/worker/outputSubmitter/outputSubmitter.ts @@ -112,6 +112,7 @@ export class OutputSubmitter { } await this.submitter.transaction(msgs, undefined, 1000 * 60 * 10) // 10 minutes - logger.info(`succeed to propose ${outputEntities.length} outputs from ${outputEntities[0].outputIndex} to ${outputEntities[outputEntities.length - 1].outputIndex}`) + this.processedBlockNumber = outputEntities[outputEntities.length - 1].endBlockNumber + logger.info(`succeed to propose ${outputEntities.length} outputs from ${outputEntities[0].outputIndex} to ${outputEntities[outputEntities.length - 1].outputIndex}, processed block number ${this.processedBlockNumber}`) } } From fcd752d92a73c44900d1c84c04f6fc2241f00678 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 22:08:33 +0900 Subject: [PATCH 06/19] add validate for controller --- src/controller/executor/ClaimTxController.ts | 14 +++++++++++++- src/controller/executor/DepositTxController.ts | 14 +++++++++++++- src/controller/executor/OutputController.ts | 12 +++++++++++- src/controller/executor/WithdrawalTxController.ts | 14 +++++++++++++- src/lib/constants.ts | 3 +++ src/service/executor/OutputService.ts | 4 ++-- 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/lib/constants.ts diff --git a/src/controller/executor/ClaimTxController.ts b/src/controller/executor/ClaimTxController.ts index 19b6c32..61394ff 100644 --- a/src/controller/executor/ClaimTxController.ts +++ b/src/controller/executor/ClaimTxController.ts @@ -1,11 +1,14 @@ import { Context } from 'koa' -import { KoaController, Get, Controller } from 'koa-joi-controllers' +import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { getClaimTxList } from '../../service' import { responses, routeConfig, z } from 'koa-swagger-decorator' import { GetClaimResponse } from '../../swagger/executor_model' import { wrapControllerFunction } from '../../lib/metricsMiddleware' +import { INIT_ACCOUNT_REGEX } from '../../lib/constants' + +const Joi = Validator.Joi @Controller('') export class ClaimTxController extends KoaController { @@ -33,6 +36,15 @@ export class ClaimTxController extends KoaController { } }) @responses(GetClaimResponse) + @Validate({ + query: { + address: Joi.string().optional().regex(INIT_ACCOUNT_REGEX).description('User address'), + sequence: Joi.number().optional(), + limit: Joi.number().optional().default(20), + offset: Joi.number().optional().default(0), + descending: Joi.boolean().optional().default(true) + } + }) @Get('/tx/claim') async getClaimTxList(ctx: Context): Promise { await wrapControllerFunction('get_claim_tx_list', async (ctx) => { diff --git a/src/controller/executor/DepositTxController.ts b/src/controller/executor/DepositTxController.ts index 30b2364..b4f43ab 100644 --- a/src/controller/executor/DepositTxController.ts +++ b/src/controller/executor/DepositTxController.ts @@ -1,11 +1,14 @@ import { Context } from 'koa' -import { KoaController, Get, Controller } from 'koa-joi-controllers' +import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { getDepositTxList } from '../../service' import { responses, routeConfig, z } from 'koa-swagger-decorator' import { GetDepositResponse } from '../../swagger/executor_model' import { wrapControllerFunction } from '../../lib/metricsMiddleware' +import { INIT_ACCOUNT_REGEX } from '../../lib/constants' + +const Joi = Validator.Joi @Controller('') export class DepositTxController extends KoaController { @@ -33,6 +36,15 @@ export class DepositTxController extends KoaController { } }) @responses(GetDepositResponse) + @Validate({ + query: { + address: Joi.string().optional().regex(INIT_ACCOUNT_REGEX).description('User address'), + sequence: Joi.number().optional(), + limit: Joi.number().optional().default(20), + offset: Joi.number().optional().default(0), + descending: Joi.boolean().optional().default(true) + } + }) @Get('/tx/deposit') async getDepositTxList(ctx: Context): Promise { await wrapControllerFunction('get_deposit_tx_list', async (ctx) => { diff --git a/src/controller/executor/OutputController.ts b/src/controller/executor/OutputController.ts index e671b17..a087d13 100644 --- a/src/controller/executor/OutputController.ts +++ b/src/controller/executor/OutputController.ts @@ -1,5 +1,5 @@ import { Context } from 'koa' -import { KoaController, Get, Controller } from 'koa-joi-controllers' +import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { responses, routeConfig, z } from 'koa-swagger-decorator' @@ -7,6 +7,8 @@ import { getOutputList } from '../../service' import { GetOutputResponse } from '../../swagger/executor_model' import { wrapControllerFunction } from '../../lib/metricsMiddleware' +const Joi = Validator.Joi + @Controller('') export class OutputController extends KoaController { @routeConfig({ @@ -32,6 +34,14 @@ export class OutputController extends KoaController { } }) @responses(GetOutputResponse) + @Validate({ + query: { + output_index: Joi.number().optional(), + limit: Joi.number().optional().default(20), + offset: Joi.number().optional().default(0), + descending: Joi.boolean().optional().default(true) + } + }) @Get('/output') async getgetOutputList(ctx: Context): Promise { await wrapControllerFunction('get_output_list', async (ctx) => { diff --git a/src/controller/executor/WithdrawalTxController.ts b/src/controller/executor/WithdrawalTxController.ts index 5e28bf2..f1534ea 100644 --- a/src/controller/executor/WithdrawalTxController.ts +++ b/src/controller/executor/WithdrawalTxController.ts @@ -1,11 +1,14 @@ import { Context } from 'koa' -import { KoaController, Get, Controller } from 'koa-joi-controllers' +import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { getWithdrawalTxList } from '../../service' import { responses, routeConfig, z } from 'koa-swagger-decorator' import { GetWithdrawalResponse } from '../../swagger/executor_model' import { wrapControllerFunction } from '../../lib/metricsMiddleware' +import { INIT_ACCOUNT_REGEX } from '../../lib/constants' + +const Joi = Validator.Joi @Controller('') export class WithdrawalTxController extends KoaController { @@ -33,6 +36,15 @@ export class WithdrawalTxController extends KoaController { } }) @responses(GetWithdrawalResponse) + @Validate({ + query: { + address: Joi.string().optional().regex(INIT_ACCOUNT_REGEX).description('User address'), + sequence: Joi.number().optional(), + limit: Joi.number().optional().default(20), + offset: Joi.number().optional().default(0), + descending: Joi.boolean().optional().default(true) + } + }) @Get('/tx/withdrawal') async getWithdrawalTxList(ctx: Context): Promise { await wrapControllerFunction('get_withdrawal_tx_list', async (ctx) => { diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 0000000..9f7ee90 --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,3 @@ +export const INIT_BECH32_REGEX = /^init1(?:[a-z0-9]){38}/ +export const INIT_HEX_REGEX = /0x(?:[a-f0-9]*){1,64}/ +export const INIT_ACCOUNT_REGEX = new RegExp(INIT_BECH32_REGEX.source + '|' + INIT_HEX_REGEX.source) \ No newline at end of file diff --git a/src/service/executor/OutputService.ts b/src/service/executor/OutputService.ts index c2d2d0d..d39d8ec 100644 --- a/src/service/executor/OutputService.ts +++ b/src/service/executor/OutputService.ts @@ -6,7 +6,7 @@ export interface GetOutputListParam { height?: number; offset?: number; limit: number; - descending: string; + descending: boolean; } export interface GetOutputListResponse { @@ -23,7 +23,7 @@ export async function getOutputList( const queryRunner = db.createQueryRunner('slave') try { const offset = param.offset ?? 0 - const order = param.descending == 'true' ? 'DESC' : 'ASC' + const order = param.descending ? 'DESC' : 'ASC' const limit = Number(param.limit) ?? 10 const qb = queryRunner.manager.createQueryBuilder( From 76819f011ce07240e99545a8d836b573cdad5719 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 23:30:15 +0900 Subject: [PATCH 07/19] fix withdrawal and getAllOutput --- src/service/executor/ClaimTxService.ts | 2 +- src/worker/bridgeExecutor/monitor/helper.ts | 6 +++++- src/worker/outputSubmitter/outputSubmitter.ts | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/service/executor/ClaimTxService.ts b/src/service/executor/ClaimTxService.ts index 1a66971..0f45449 100644 --- a/src/service/executor/ClaimTxService.ts +++ b/src/service/executor/ClaimTxService.ts @@ -52,7 +52,7 @@ export async function getClaimTxList( ) if (param.address) { - withdrawalQb.andWhere('tx.sender = :sender', { sender: param.address }) + withdrawalQb.andWhere('tx.receiver = :receiver', { receiver: param.address }) } if (param.sequence) { diff --git a/src/worker/bridgeExecutor/monitor/helper.ts b/src/worker/bridgeExecutor/monitor/helper.ts index ca68696..4111df2 100644 --- a/src/worker/bridgeExecutor/monitor/helper.ts +++ b/src/worker/bridgeExecutor/monitor/helper.ts @@ -94,9 +94,13 @@ class MonitorHelper { public async getAllOutput( manager: EntityManager, entityClass: EntityTarget, + startIndex = 0 ): Promise { return await manager.getRepository(entityClass).find({ - order: { outputIndex: 'ASC' } as any + where: { + outputIndex: startIndex as any + }, + order: { outputIndex: 'ASC' } as any, }) } diff --git a/src/worker/outputSubmitter/outputSubmitter.ts b/src/worker/outputSubmitter/outputSubmitter.ts index 3ec7187..f57a9fc 100644 --- a/src/worker/outputSubmitter/outputSubmitter.ts +++ b/src/worker/outputSubmitter/outputSubmitter.ts @@ -58,9 +58,10 @@ export class OutputSubmitter { const outputs = await this.helper.getAllOutput( manager, ExecutorOutputEntity, + this.syncedOutputIndex ) - return outputs.filter(output => output.outputIndex >= this.syncedOutputIndex) + return outputs } catch (err) { if (err.response?.data.type === ErrorTypes.NOT_FOUND_ERROR) { logger.warn( From 3f89fade8897abb06ba85195635221455091933f Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 23:37:52 +0900 Subject: [PATCH 08/19] remove metrics controller --- src/controller/index.ts | 7 +----- src/controller/metrics/MetricsController.ts | 26 --------------------- src/swagger/swagger.ts | 2 +- src/worker/batchSubmitter/index.ts | 4 ++-- src/worker/bridgeExecutor/index.ts | 4 ++-- src/worker/outputSubmitter/index.ts | 3 +-- 6 files changed, 7 insertions(+), 39 deletions(-) delete mode 100644 src/controller/metrics/MetricsController.ts diff --git a/src/controller/index.ts b/src/controller/index.ts index 5c84713..6440c66 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -4,7 +4,6 @@ import { OutputController } from './executor/OutputController' import { WithdrawalTxController } from './executor/WithdrawalTxController' import { DepositTxController } from './executor/DepositTxController' import { ClaimTxController } from './executor/ClaimTxController' -import { MetricsController } from './metrics/MetricsController' export const executorController = [ OutputController, @@ -15,8 +14,4 @@ export const executorController = [ export const batchController = [BatchController].map( (prototype) => new prototype() -) as KoaController[] - -export const metricsController = [MetricsController].map( - (prototype) => new prototype() -) as KoaController[] +) as KoaController[] \ No newline at end of file diff --git a/src/controller/metrics/MetricsController.ts b/src/controller/metrics/MetricsController.ts deleted file mode 100644 index 4323958..0000000 --- a/src/controller/metrics/MetricsController.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Context } from 'koa' -import { KoaController, Get, Controller } from 'koa-joi-controllers' -import { routeConfig } from 'koa-swagger-decorator' -import { Prometheus } from '../../lib/metrics' - -@Controller('') -export class MetricsController extends KoaController { - @routeConfig({ - method: 'get', - path: '/metrics', - tags: ['Metrics'] - }) - @Get('/metrics') - async getMetrics(ctx: Context): Promise { - try { - const metricsData = await Prometheus.get() - ctx.status = 200 - ctx.set('Content-Type', metricsData.contentType) - ctx.body = metricsData.metrics - } catch (e) { - ctx.status = 500 - ctx.body = 'Failed to retrieve metrics' - console.error('Error fetching Prometheus metrics:', e) - } - } -} diff --git a/src/swagger/swagger.ts b/src/swagger/swagger.ts index 1b6d634..1748c46 100644 --- a/src/swagger/swagger.ts +++ b/src/swagger/swagger.ts @@ -7,7 +7,7 @@ import { ClaimTxController } from '../controller/executor/ClaimTxController' const router = new SwaggerRouter({ spec: { info: { - title: 'Initia VIP API', + title: 'Initia OPinit API', version: 'v1.0' } }, diff --git a/src/worker/batchSubmitter/index.ts b/src/worker/batchSubmitter/index.ts index 6d4d6fa..e2a1bf6 100644 --- a/src/worker/batchSubmitter/index.ts +++ b/src/worker/batchSubmitter/index.ts @@ -2,7 +2,7 @@ import { initORM, finalizeORM } from '../../worker/batchSubmitter/db' import { executorLogger as logger } from '../../lib/logger' import { BatchSubmitter } from './batchSubmitter' import { initServer, finalizeServer, initMetricsServer } from '../../loader' -import { batchController, metricsController } from '../../controller' +import { batchController } from '../../controller' import { once } from 'lodash' import { config, isInvokedFromEntrypoint } from '../../config' @@ -44,7 +44,7 @@ export async function startBatch(): Promise { await initORM() await initServer(batchController, config.BATCH_PORT) - await initMetricsServer(metricsController, config.BATCH_METRICS_PORT) + await initMetricsServer([], config.BATCH_METRICS_PORT) if (!config.ENABLE_API_ONLY) { await runBot() diff --git a/src/worker/bridgeExecutor/index.ts b/src/worker/bridgeExecutor/index.ts index 5a082f3..21354b4 100644 --- a/src/worker/bridgeExecutor/index.ts +++ b/src/worker/bridgeExecutor/index.ts @@ -1,7 +1,7 @@ import { RPCClient } from '../../lib/rpc' import { L1Monitor } from './monitor/l1' import { L2Monitor } from './monitor/l2' -import { executorController, metricsController } from '../../controller' +import { executorController } from '../../controller' import { executorLogger as logger } from '../../lib/logger' import { initORM, finalizeORM } from './db' @@ -54,7 +54,7 @@ export async function startExecutor(): Promise { await initORM() await initServer(executorController, config.EXECUTOR_PORT) - await initMetricsServer(metricsController, config.EXECUTOR_METRICS_PORT) + await initMetricsServer([], config.EXECUTOR_METRICS_PORT) if (!config.ENABLE_API_ONLY) { await runBot() diff --git a/src/worker/outputSubmitter/index.ts b/src/worker/outputSubmitter/index.ts index 0a8f0b2..5431d01 100644 --- a/src/worker/outputSubmitter/index.ts +++ b/src/worker/outputSubmitter/index.ts @@ -3,7 +3,6 @@ import { outputLogger as logger } from '../../lib/logger' import { once } from 'lodash' import { initORM } from './db' import { initMetricsServer } from '../../loader' -import { metricsController } from '../../controller' import { config, isInvokedFromEntrypoint } from '../../config' let jobs: OutputSubmitter[] @@ -37,7 +36,7 @@ export async function stopOutput(): Promise { export async function startOutput(): Promise { await initORM() - await initMetricsServer(metricsController, config.OUTPUT_METRICS_PORT) + await initMetricsServer([], config.OUTPUT_METRICS_PORT) await runBot() From 118a3c0f4d79c4ef7eb4d8f63080988561dd8f9c Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Thu, 13 Jun 2024 23:56:28 +0900 Subject: [PATCH 09/19] fix filter cond --- src/worker/bridgeExecutor/monitor/helper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/worker/bridgeExecutor/monitor/helper.ts b/src/worker/bridgeExecutor/monitor/helper.ts index 4111df2..d0302c1 100644 --- a/src/worker/bridgeExecutor/monitor/helper.ts +++ b/src/worker/bridgeExecutor/monitor/helper.ts @@ -12,7 +12,7 @@ import { WithdrawStorage } from '../../../lib/storage' import { WithdrawalTx } from '../../../lib/types' import { sha3_256 } from '../../../lib/util' import OutputEntity from '../../../orm/executor/OutputEntity' -import { EntityManager, EntityTarget, ObjectLiteral } from 'typeorm' +import { EntityManager, EntityTarget, MoreThanOrEqual, ObjectLiteral } from 'typeorm' import { Block, BlockResults, RPCClient } from '../../../lib/rpc' class MonitorHelper { @@ -98,7 +98,7 @@ class MonitorHelper { ): Promise { return await manager.getRepository(entityClass).find({ where: { - outputIndex: startIndex as any + outputIndex: MoreThanOrEqual(startIndex) as any }, order: { outputIndex: 'ASC' } as any, }) From d6a27f0a2ed95a8dfaff5c25335e7b2624710ea2 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 00:30:32 +0900 Subject: [PATCH 10/19] fix controller --- src/service/executor/ClaimTxService.ts | 48 +++++++++------------ src/service/executor/DepositTxService.ts | 35 +++++++-------- src/service/executor/OutputService.ts | 32 ++++++-------- src/service/executor/WithdrawalTxService.ts | 35 +++++++-------- src/worker/bridgeExecutor/monitor/l1.ts | 2 +- 5 files changed, 66 insertions(+), 86 deletions(-) diff --git a/src/service/executor/ClaimTxService.ts b/src/service/executor/ClaimTxService.ts index 0f45449..2df3752 100644 --- a/src/service/executor/ClaimTxService.ts +++ b/src/service/executor/ClaimTxService.ts @@ -37,45 +37,39 @@ export async function getClaimTxList( param: GetClaimTxListParam ): Promise { const [db] = getDB() - const queryRunner = db.createQueryRunner('slave') - try { const offset = param.offset ?? 0 - const order = param.descending == 'true' ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 10 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 const claimTxList: ClaimTx[] = [] - const withdrawalQb = queryRunner.manager.createQueryBuilder( - ExecutorWithdrawalTxEntity, - 'tx' - ) + const withdrawalRepo = db.getRepository(ExecutorWithdrawalTxEntity) + const withdrawalWhereCond = {} if (param.address) { - withdrawalQb.andWhere('tx.receiver = :receiver', { receiver: param.address }) + withdrawalWhereCond['receiver'] = param.address } if (param.sequence) { - withdrawalQb.andWhere('tx.sequence = :sequence', { - sequence: param.sequence - }) + withdrawalWhereCond['sequence'] = param.sequence } - const withdrawalTxs = await withdrawalQb - .orderBy('tx.sequence', order) - .skip(offset * limit) - .take(limit) - .getMany() - + const withdrawalTxs = await withdrawalRepo.find({ + where: withdrawalWhereCond, + order: { + sequence: order + }, + skip: offset * limit, + take: limit + }) + withdrawalTxs.map(async (withdrawalTx) => { - const outputQb = queryRunner.manager - .createQueryBuilder(ExecutorOutputEntity, 'output') - .where('output.output_index = :outputIndex', { - outputIndex: withdrawalTx.outputIndex + const output = await db.getRepository(ExecutorOutputEntity) + .findOne({ + where: { outputIndex: withdrawalTx.outputIndex } }) - const output = await outputQb.getOne() - if (!output) { throw new APIError(ErrorTypes.NOT_FOUND_ERROR) } @@ -96,7 +90,8 @@ export async function getClaimTxList( claimTxList.push(claimData) }) - const count = await withdrawalQb.getCount() + const count = withdrawalTxs.length + let next: number | undefined if (count > (offset + 1) * limit) { @@ -109,7 +104,4 @@ export async function getClaimTxList( limit, claimTxList } - } finally { - await queryRunner.release() - } } diff --git a/src/service/executor/DepositTxService.ts b/src/service/executor/DepositTxService.ts index 9ab3059..7dbc3a9 100644 --- a/src/service/executor/DepositTxService.ts +++ b/src/service/executor/DepositTxService.ts @@ -20,32 +20,32 @@ export async function getDepositTxList( param: GetDepositTxListParam ): Promise { const [db] = getDB() - const queryRunner = db.createQueryRunner('slave') - try { const offset = param.offset ?? 0 - const order = param.descending == 'true' ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 10 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 - const qb = queryRunner.manager.createQueryBuilder( - ExecutorDepositTxEntity, - 'tx' - ) + const depositTxRepo = db.getRepository(ExecutorDepositTxEntity) + const depositTxWhereCond = {} if (param.sequence) { - qb.andWhere('tx.sequence = :sequence', { sequence: param.sequence }) + depositTxWhereCond['sequence'] = param.sequence } if (param.address) { - qb.andWhere('tx.sender = :sender', { sender: param.address }) + depositTxWhereCond['sender'] = param.address } - const depositTxList = await qb - .orderBy('tx.sequence', order) - .skip(offset * limit) - .take(limit) - .getMany() + const depositTxList = await depositTxRepo.find({ + where: depositTxWhereCond, + order: { + sequence: order + }, + skip: offset * limit, + take: limit + }) + + const count = depositTxList.length - const count = await qb.getCount() let next: number | undefined if (count > (offset + 1) * limit) { @@ -58,7 +58,4 @@ export async function getDepositTxList( limit, depositTxList } - } finally { - queryRunner.release() - } } diff --git a/src/service/executor/OutputService.ts b/src/service/executor/OutputService.ts index d39d8ec..2b398ec 100644 --- a/src/service/executor/OutputService.ts +++ b/src/service/executor/OutputService.ts @@ -20,30 +20,27 @@ export async function getOutputList( param: GetOutputListParam ): Promise { const [db] = getDB() - const queryRunner = db.createQueryRunner('slave') - try { const offset = param.offset ?? 0 const order = param.descending ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 10 + const limit = Number(param.limit) ?? 20 - const qb = queryRunner.manager.createQueryBuilder( - ExecutorOutputEntity, - 'output' - ) + const outputRepo = db.getRepository(ExecutorOutputEntity) + const outputWhereCond = {} if (param.output_index) { - qb.andWhere('output.output_index = :output_index', { - output_index: param.output_index - }) + outputWhereCond['outputIndex'] = param.output_index } - const outputList = await qb - .orderBy('output.output_index', order) - .skip(offset * limit) - .take(limit) - .getMany() + const outputList = await outputRepo.find({ + where: outputWhereCond, + order: { + outputIndex: order + }, + skip: offset * limit, + take: limit + }) - const count = await qb.getCount() + const count = outputList.length let next: number | undefined if (count > (offset + 1) * limit) { @@ -56,7 +53,4 @@ export async function getOutputList( limit, outputList } - } finally { - queryRunner.release() - } } diff --git a/src/service/executor/WithdrawalTxService.ts b/src/service/executor/WithdrawalTxService.ts index e1ef235..badd75c 100644 --- a/src/service/executor/WithdrawalTxService.ts +++ b/src/service/executor/WithdrawalTxService.ts @@ -20,32 +20,32 @@ export async function getWithdrawalTxList( param: GetWithdrawalTxListParam ): Promise { const [db] = getDB() - const queryRunner = db.createQueryRunner('slave') - try { const offset = param.offset ?? 0 - const order = param.descending == 'true' ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 10 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 - const qb = queryRunner.manager.createQueryBuilder( - ExecutorWithdrawalTxEntity, - 'tx' - ) + const withdrawalRepo = db.getRepository(ExecutorWithdrawalTxEntity) + const withdrawalWhereCond = {} if (param.sequence) { - qb.andWhere('tx.sequence = :sequence', { sequence: param.sequence }) + withdrawalWhereCond['sequence'] = param.sequence } if (param.address) { - qb.andWhere('tx.sender = :sender', { sender: param.address }) + withdrawalWhereCond['receiver'] = param.address } - const withdrawalTxList = await qb - .orderBy('tx.sequence', order) - .skip(offset * limit) - .take(limit) - .getMany() + const withdrawalTxList = await withdrawalRepo.find({ + where: withdrawalWhereCond, + order: { + sequence: order + }, + skip: offset * limit, + take: limit + }) + + const count = withdrawalTxList.length - const count = await qb.getCount() let next: number | undefined if (count > (offset + 1) * param.limit) { @@ -58,7 +58,4 @@ export async function getWithdrawalTxList( limit: param.limit, withdrawalTxList } - } finally { - queryRunner.release() - } } diff --git a/src/worker/bridgeExecutor/monitor/l1.ts b/src/worker/bridgeExecutor/monitor/l1.ts index 3725713..9719ed7 100644 --- a/src/worker/bridgeExecutor/monitor/l1.ts +++ b/src/worker/bridgeExecutor/monitor/l1.ts @@ -108,7 +108,7 @@ export class L1Monitor extends Monitor { public async handleNewBlock(): Promise { // ressurect every unconfirmed tx before handling new block - await this.resurrector.resurrect() + // await this.resurrector.resurrect() if (!config.ENABLE_ORACLE) return if (!this.latestHeight || this.oracleHeight == this.latestHeight) { From 8b070ee1260a804a40205b784f422385d9df3970 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 11:36:37 +0900 Subject: [PATCH 11/19] revive metrics --- src/controller/index.ts | 5 +++++ src/controller/metrics/MetricsController.ts | 20 +++++++++++++++++++ src/worker/batchSubmitter/index.ts | 4 ++-- src/worker/bridgeExecutor/index.ts | 4 ++-- src/worker/bridgeExecutor/monitor/l1.ts | 2 +- src/worker/outputSubmitter/index.ts | 3 ++- src/worker/outputSubmitter/outputSubmitter.ts | 1 + 7 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 src/controller/metrics/MetricsController.ts diff --git a/src/controller/index.ts b/src/controller/index.ts index 6440c66..277e474 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -4,6 +4,7 @@ import { OutputController } from './executor/OutputController' import { WithdrawalTxController } from './executor/WithdrawalTxController' import { DepositTxController } from './executor/DepositTxController' import { ClaimTxController } from './executor/ClaimTxController' +import { MetricsController } from './metrics/MetricsController' export const executorController = [ OutputController, @@ -14,4 +15,8 @@ export const executorController = [ export const batchController = [BatchController].map( (prototype) => new prototype() +) as KoaController[] + +export const metricsController = [MetricsController].map( + (prototype) => new prototype() ) as KoaController[] \ No newline at end of file diff --git a/src/controller/metrics/MetricsController.ts b/src/controller/metrics/MetricsController.ts new file mode 100644 index 0000000..13e6279 --- /dev/null +++ b/src/controller/metrics/MetricsController.ts @@ -0,0 +1,20 @@ +import { Context } from 'koa' +import { KoaController, Get, Controller } from 'koa-joi-controllers' +import { Prometheus } from '../../lib/metrics' + +@Controller('') +export class MetricsController extends KoaController { + @Get('/metrics') + async getMetrics(ctx: Context): Promise { + try { + const metricsData = await Prometheus.get() + ctx.status = 200 + ctx.set('Content-Type', metricsData.contentType) + ctx.body = metricsData.metrics + } catch (e) { + ctx.status = 500 + ctx.body = 'Failed to retrieve metrics' + console.error('Error fetching Prometheus metrics:', e) + } + } +} \ No newline at end of file diff --git a/src/worker/batchSubmitter/index.ts b/src/worker/batchSubmitter/index.ts index e2a1bf6..6d4d6fa 100644 --- a/src/worker/batchSubmitter/index.ts +++ b/src/worker/batchSubmitter/index.ts @@ -2,7 +2,7 @@ import { initORM, finalizeORM } from '../../worker/batchSubmitter/db' import { executorLogger as logger } from '../../lib/logger' import { BatchSubmitter } from './batchSubmitter' import { initServer, finalizeServer, initMetricsServer } from '../../loader' -import { batchController } from '../../controller' +import { batchController, metricsController } from '../../controller' import { once } from 'lodash' import { config, isInvokedFromEntrypoint } from '../../config' @@ -44,7 +44,7 @@ export async function startBatch(): Promise { await initORM() await initServer(batchController, config.BATCH_PORT) - await initMetricsServer([], config.BATCH_METRICS_PORT) + await initMetricsServer(metricsController, config.BATCH_METRICS_PORT) if (!config.ENABLE_API_ONLY) { await runBot() diff --git a/src/worker/bridgeExecutor/index.ts b/src/worker/bridgeExecutor/index.ts index 21354b4..5a082f3 100644 --- a/src/worker/bridgeExecutor/index.ts +++ b/src/worker/bridgeExecutor/index.ts @@ -1,7 +1,7 @@ import { RPCClient } from '../../lib/rpc' import { L1Monitor } from './monitor/l1' import { L2Monitor } from './monitor/l2' -import { executorController } from '../../controller' +import { executorController, metricsController } from '../../controller' import { executorLogger as logger } from '../../lib/logger' import { initORM, finalizeORM } from './db' @@ -54,7 +54,7 @@ export async function startExecutor(): Promise { await initORM() await initServer(executorController, config.EXECUTOR_PORT) - await initMetricsServer([], config.EXECUTOR_METRICS_PORT) + await initMetricsServer(metricsController, config.EXECUTOR_METRICS_PORT) if (!config.ENABLE_API_ONLY) { await runBot() diff --git a/src/worker/bridgeExecutor/monitor/l1.ts b/src/worker/bridgeExecutor/monitor/l1.ts index 9719ed7..3725713 100644 --- a/src/worker/bridgeExecutor/monitor/l1.ts +++ b/src/worker/bridgeExecutor/monitor/l1.ts @@ -108,7 +108,7 @@ export class L1Monitor extends Monitor { public async handleNewBlock(): Promise { // ressurect every unconfirmed tx before handling new block - // await this.resurrector.resurrect() + await this.resurrector.resurrect() if (!config.ENABLE_ORACLE) return if (!this.latestHeight || this.oracleHeight == this.latestHeight) { diff --git a/src/worker/outputSubmitter/index.ts b/src/worker/outputSubmitter/index.ts index 5431d01..9434084 100644 --- a/src/worker/outputSubmitter/index.ts +++ b/src/worker/outputSubmitter/index.ts @@ -4,6 +4,7 @@ import { once } from 'lodash' import { initORM } from './db' import { initMetricsServer } from '../../loader' import { config, isInvokedFromEntrypoint } from '../../config' +import { metricsController } from '../../controller' let jobs: OutputSubmitter[] @@ -36,7 +37,7 @@ export async function stopOutput(): Promise { export async function startOutput(): Promise { await initORM() - await initMetricsServer([], config.OUTPUT_METRICS_PORT) + await initMetricsServer(metricsController, config.OUTPUT_METRICS_PORT) await runBot() diff --git a/src/worker/outputSubmitter/outputSubmitter.ts b/src/worker/outputSubmitter/outputSubmitter.ts index f57a9fc..71d29f0 100644 --- a/src/worker/outputSubmitter/outputSubmitter.ts +++ b/src/worker/outputSubmitter/outputSubmitter.ts @@ -53,6 +53,7 @@ export class OutputSubmitter { const lastOutputInfo = await getLastOutputInfo(this.bridgeId) if (lastOutputInfo) { this.syncedOutputIndex = lastOutputInfo.output_index + 1 + this.processedBlockNumber = lastOutputInfo.output_proposal.l2_block_number } const outputs = await this.helper.getAllOutput( From 831b925a56236f61a5914446e7a0b79186232d3f Mon Sep 17 00:00:00 2001 From: beer-1 <147697694+beer-1@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:10:35 +0900 Subject: [PATCH 12/19] feat: update merkle logic to apply latest chain update (#39) * update merkle logic to apply latest chain update * remove console.log --------- Co-authored-by: Harvey --- package-lock.json | 4 ++-- src/lib/storage.spec.ts | 31 +++++++++++++++++++++++++++++++ src/lib/storage.ts | 14 +++++++------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5497c39..acd6083 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@initia/rollup", - "version": "0.1.12", + "version": "0.1.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@initia/rollup", - "version": "0.1.12", + "version": "0.1.14", "license": "MIT", "dependencies": { "@koa/cors": "^5.0.0", diff --git a/src/lib/storage.spec.ts b/src/lib/storage.spec.ts index e7e4542..925eb20 100644 --- a/src/lib/storage.spec.ts +++ b/src/lib/storage.spec.ts @@ -25,6 +25,30 @@ const v1 = [ receiver: 'init174knscjg688ddtxj8smyjz073r3w5mmsp3m0m2', l1_denom: 'uinit', amount: BigInt(1000000) + }, + { + bridge_id: BigInt(1), + sequence: BigInt(4), + sender: 'init1wzenw7r2t2ra39k4l9yqq95pw55ap4sm4vsa9g', + receiver: 'init174knscjg688ddtxj8smyjz073r3w5mmsp3m0m2', + l1_denom: 'uinit', + amount: BigInt(1000231200) + }, + { + bridge_id: BigInt(1), + sequence: BigInt(5), + sender: 'init1wzenw7r2t2ra39k4l9yqq95pw55ap4sm4vsa9g', + receiver: 'init174knscjg688ddtxj8smyjz073r3w5mmsp3m0m2', + l1_denom: 'uinit', + amount: BigInt(32340000) + }, + { + bridge_id: BigInt(1), + sequence: BigInt(6), + sender: 'init1wzenw7r2t2ra39k4l9yqq95pw55ap4sm4vsa9g', + receiver: 'init174knscjg688ddtxj8smyjz073r3w5mmsp3m0m2', + l1_denom: 'uinit', + amount: BigInt(101230000) } ] @@ -80,5 +104,12 @@ describe('WithdrawStorage', () => { ]) ).toString('base64') expect(airdrop.verify(merkleProof, target)).toBeTruthy() + expect(merkleRoot).toEqual('VcN+0UZbTtGyyLfQtAHW+bCv5ixadyyT0ZZ26aUT1JY=') + expect(merkleProof).toEqual([ + 'gnUeNU3EnW4iBOk8wounvu98aTER0BP5dOD0lkuwBBE=', + 'yE4zjliK5P9sfdzR2iNh6nYHmD+mjDK6dONuZ3QlVcA=', + 'GQXXUQ5P/egGvbAHkYfWHIAfgyCEmnjz/fUMKrWCEn8=' + ]) + expect(outputRoot).toEqual('0cg24XcpDwTIFXHY4jNyxg2EQS5RUqcMvlMJeuI5rf4=') }) }) diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 6372f54..99e8d26 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -3,7 +3,7 @@ import { sha3_256 } from './util' import { WithdrawalTx } from './types' import { AccAddress } from 'initia-l1' -const SPLITTER = Buffer.from('|') +const SPLITTER = Buffer.from('|', 'utf8') function convertHexToBase64(hex: string): string { return Buffer.from(hex, 'hex').toString('base64') @@ -23,7 +23,7 @@ export class WithdrawStorage { const amount_buf = Buffer.alloc(8) amount_buf.writeBigInt64BE(tx.amount) - return sha3_256( + return sha3_256(sha3_256( Buffer.concat([ bridge_id_buf, sequence_buf, @@ -35,7 +35,7 @@ export class WithdrawStorage { SPLITTER, amount_buf ]) - ) + )) }) this.tree = new MerkleTree(leaves, sha3_256, { sort: true }) @@ -57,7 +57,7 @@ export class WithdrawStorage { return this.tree .getHexProof( - sha3_256( + sha3_256(sha3_256( Buffer.concat([ bridge_id_buf, sequence_buf, @@ -69,7 +69,7 @@ export class WithdrawStorage { SPLITTER, amount_buf ]) - ) + )) ) .map((v) => convertHexToBase64(v.replace('0x', ''))) } @@ -94,7 +94,7 @@ export class WithdrawStorage { const amount_buf = Buffer.alloc(8) amount_buf.writeBigInt64BE(tx.amount) - let hashBuf = sha3_256( + let hashBuf = sha3_256(sha3_256( Buffer.concat([ bridge_id_buf, sequence_buf, @@ -106,7 +106,7 @@ export class WithdrawStorage { SPLITTER, amount_buf ]) - ) + )) proof.forEach((proofElem) => { const proofBuf = Buffer.from(proofElem, 'base64') From f45acb7a39ce062826d81e1c4861b84c3bd80c07 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 15:51:20 +0900 Subject: [PATCH 13/19] output creation logger --- src/worker/bridgeExecutor/monitor/l2.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/worker/bridgeExecutor/monitor/l2.ts b/src/worker/bridgeExecutor/monitor/l2.ts index 838b8aa..1f524fd 100644 --- a/src/worker/bridgeExecutor/monitor/l2.ts +++ b/src/worker/bridgeExecutor/monitor/l2.ts @@ -121,7 +121,10 @@ export class L2Monitor extends Monitor { manager, ExecutorOutputEntity ) - if (!lastOutputFromDB) return true + if (!lastOutputFromDB) { + this.logger.info(`[checkSubmissionInterval - ${this.name()}] No output from DB`) + return true + } if (lastOutputSubmitted) { if (lastOutputFromDB.outputIndex !== lastOutputSubmitted.output_index) return false const lastOutputSubmittedTime = @@ -136,6 +139,7 @@ export class L2Monitor extends Monitor { ) return false } + this.logger.info(`[checkSubmissionInterval - ${this.name()}] Submission interval reached`) return true } @@ -191,7 +195,8 @@ export class L2Monitor extends Monitor { startBlockNumber, endBlockNumber ) - + + this.logger.info(`output entity created: ${startBlockNumber} - ${endBlockNumber}`) await this.helper.saveEntity(manager, ExecutorOutputEntity, outputEntity) } From 5ece548a19c1d09123ad8ed55986f133b6384d03 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 16:13:41 +0900 Subject: [PATCH 14/19] fix output logic --- src/worker/bridgeExecutor/monitor/l2.ts | 38 ++++++++++++++++--------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/worker/bridgeExecutor/monitor/l2.ts b/src/worker/bridgeExecutor/monitor/l2.ts index 1f524fd..2a83434 100644 --- a/src/worker/bridgeExecutor/monitor/l2.ts +++ b/src/worker/bridgeExecutor/monitor/l2.ts @@ -121,24 +121,36 @@ export class L2Monitor extends Monitor { manager, ExecutorOutputEntity ) + + // if no output from DB, create output if (!lastOutputFromDB) { this.logger.info(`[checkSubmissionInterval - ${this.name()}] No output from DB`) return true } - if (lastOutputSubmitted) { - if (lastOutputFromDB.outputIndex !== lastOutputSubmitted.output_index) return false - const lastOutputSubmittedTime = - lastOutputSubmitted.output_proposal.l1_block_time + + // if no output submitted, wait for submission + if (!lastOutputSubmitted) return false + + // if output index not matched, wait for submission + if (lastOutputSubmitted.output_index !== lastOutputFromDB.outputIndex) return false + + const lastOutputSubmittedTime = + lastOutputSubmitted.output_proposal.l1_block_time const bridgeInfo = await getBridgeInfo(this.bridgeId) - const submissionInterval = - bridgeInfo.bridge_config.submission_interval.seconds.toNumber() - if ( - this.getCurTimeSec() < - this.dateToSeconds(lastOutputSubmittedTime) + - Math.floor(submissionInterval * config.SUBMISSION_THRESHOLD) - ) - return false + const submissionInterval = + bridgeInfo.bridge_config.submission_interval.seconds.toNumber() + const targetTimeSec = this.dateToSeconds(lastOutputSubmittedTime) + + Math.floor(submissionInterval * config.SUBMISSION_THRESHOLD) + + // if submission interval not reached, wait for submission + if ( + this.getCurTimeSec() < targetTimeSec + ) { + this.logger.info(`[checkSubmissionInterval - ${this.name()}] need to wait for submission interval ${targetTimeSec - this.getCurTimeSec()}`) + return false } + + // if submission interval reached, create output this.logger.info(`[checkSubmissionInterval - ${this.name()}] Submission interval reached`) return true } @@ -196,7 +208,7 @@ export class L2Monitor extends Monitor { endBlockNumber ) - this.logger.info(`output entity created: ${startBlockNumber} - ${endBlockNumber}`) + this.logger.info(`output entity created: block height (${startBlockNumber} - ${endBlockNumber})`) await this.helper.saveEntity(manager, ExecutorOutputEntity, outputEntity) } From a84876ec533504b96ca762b23b4a88f086a4a9cf Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 16:13:57 +0900 Subject: [PATCH 15/19] lint --- src/controller/executor/ClaimTxController.ts | 13 +- .../executor/DepositTxController.ts | 13 +- src/controller/executor/OutputController.ts | 8 +- .../executor/WithdrawalTxController.ts | 13 +- src/controller/index.ts | 2 +- src/controller/metrics/MetricsController.ts | 2 +- src/lib/constants.ts | 4 +- src/lib/query.ts | 2 +- src/lib/storage.spec.ts | 7 +- src/lib/storage.ts | 84 +++++++------ src/service/executor/ClaimTxService.ts | 115 +++++++++--------- src/service/executor/DepositTxService.ts | 76 ++++++------ src/service/executor/OutputService.ts | 66 +++++----- src/service/executor/WithdrawalTxService.ts | 76 ++++++------ src/worker/bridgeExecutor/monitor/helper.ts | 9 +- src/worker/bridgeExecutor/monitor/l2.ts | 36 +++--- src/worker/bridgeExecutor/monitor/monitor.ts | 2 +- src/worker/challenger/challenger.ts | 3 +- src/worker/common/name.ts | 10 +- src/worker/outputSubmitter/outputSubmitter.ts | 18 +-- 20 files changed, 308 insertions(+), 251 deletions(-) diff --git a/src/controller/executor/ClaimTxController.ts b/src/controller/executor/ClaimTxController.ts index 61394ff..43dc4db 100644 --- a/src/controller/executor/ClaimTxController.ts +++ b/src/controller/executor/ClaimTxController.ts @@ -1,5 +1,11 @@ import { Context } from 'koa' -import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' +import { + KoaController, + Get, + Controller, + Validator, + Validate +} from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { getClaimTxList } from '../../service' @@ -38,7 +44,10 @@ export class ClaimTxController extends KoaController { @responses(GetClaimResponse) @Validate({ query: { - address: Joi.string().optional().regex(INIT_ACCOUNT_REGEX).description('User address'), + address: Joi.string() + .optional() + .regex(INIT_ACCOUNT_REGEX) + .description('User address'), sequence: Joi.number().optional(), limit: Joi.number().optional().default(20), offset: Joi.number().optional().default(0), diff --git a/src/controller/executor/DepositTxController.ts b/src/controller/executor/DepositTxController.ts index b4f43ab..fabbd10 100644 --- a/src/controller/executor/DepositTxController.ts +++ b/src/controller/executor/DepositTxController.ts @@ -1,5 +1,11 @@ import { Context } from 'koa' -import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' +import { + KoaController, + Get, + Controller, + Validator, + Validate +} from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { getDepositTxList } from '../../service' @@ -38,7 +44,10 @@ export class DepositTxController extends KoaController { @responses(GetDepositResponse) @Validate({ query: { - address: Joi.string().optional().regex(INIT_ACCOUNT_REGEX).description('User address'), + address: Joi.string() + .optional() + .regex(INIT_ACCOUNT_REGEX) + .description('User address'), sequence: Joi.number().optional(), limit: Joi.number().optional().default(20), offset: Joi.number().optional().default(0), diff --git a/src/controller/executor/OutputController.ts b/src/controller/executor/OutputController.ts index a087d13..7309c62 100644 --- a/src/controller/executor/OutputController.ts +++ b/src/controller/executor/OutputController.ts @@ -1,5 +1,11 @@ import { Context } from 'koa' -import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' +import { + KoaController, + Get, + Controller, + Validator, + Validate +} from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { responses, routeConfig, z } from 'koa-swagger-decorator' diff --git a/src/controller/executor/WithdrawalTxController.ts b/src/controller/executor/WithdrawalTxController.ts index f1534ea..688530b 100644 --- a/src/controller/executor/WithdrawalTxController.ts +++ b/src/controller/executor/WithdrawalTxController.ts @@ -1,5 +1,11 @@ import { Context } from 'koa' -import { KoaController, Get, Controller, Validator, Validate } from 'koa-joi-controllers' +import { + KoaController, + Get, + Controller, + Validator, + Validate +} from 'koa-joi-controllers' import { ErrorTypes } from '../../lib/error' import { error, success } from '../../lib/response' import { getWithdrawalTxList } from '../../service' @@ -38,7 +44,10 @@ export class WithdrawalTxController extends KoaController { @responses(GetWithdrawalResponse) @Validate({ query: { - address: Joi.string().optional().regex(INIT_ACCOUNT_REGEX).description('User address'), + address: Joi.string() + .optional() + .regex(INIT_ACCOUNT_REGEX) + .description('User address'), sequence: Joi.number().optional(), limit: Joi.number().optional().default(20), offset: Joi.number().optional().default(0), diff --git a/src/controller/index.ts b/src/controller/index.ts index 277e474..5c84713 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -19,4 +19,4 @@ export const batchController = [BatchController].map( export const metricsController = [MetricsController].map( (prototype) => new prototype() -) as KoaController[] \ No newline at end of file +) as KoaController[] diff --git a/src/controller/metrics/MetricsController.ts b/src/controller/metrics/MetricsController.ts index 13e6279..7b24eaf 100644 --- a/src/controller/metrics/MetricsController.ts +++ b/src/controller/metrics/MetricsController.ts @@ -17,4 +17,4 @@ export class MetricsController extends KoaController { console.error('Error fetching Prometheus metrics:', e) } } -} \ No newline at end of file +} diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 9f7ee90..de619e4 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,3 +1,5 @@ export const INIT_BECH32_REGEX = /^init1(?:[a-z0-9]){38}/ export const INIT_HEX_REGEX = /0x(?:[a-f0-9]*){1,64}/ -export const INIT_ACCOUNT_REGEX = new RegExp(INIT_BECH32_REGEX.source + '|' + INIT_HEX_REGEX.source) \ No newline at end of file +export const INIT_ACCOUNT_REGEX = new RegExp( + INIT_BECH32_REGEX.source + '|' + INIT_HEX_REGEX.source +) diff --git a/src/lib/query.ts b/src/lib/query.ts index 9eccb2d..406ed00 100644 --- a/src/lib/query.ts +++ b/src/lib/query.ts @@ -75,4 +75,4 @@ export async function getLatestOutputFromExecutor(): Promise { const axiosInstance = AxiosSingleton.getInstance() const res = await axiosInstance.get(url) return res.data -} \ No newline at end of file +} diff --git a/src/lib/storage.spec.ts b/src/lib/storage.spec.ts index 925eb20..5af4b82 100644 --- a/src/lib/storage.spec.ts +++ b/src/lib/storage.spec.ts @@ -82,8 +82,11 @@ describe('WithdrawStorage', () => { Buffer.from(tx.l1_denom, 'utf8'), Buffer.from('|'), amount_buf - ])).toString('base64') - expect(result == "F+mzhRVdcwLS5tk2NDB2MbgMm7A0nk39G+NGEjXpTV0=").toBeTruthy() + ]) + ).toString('base64') + expect( + result == 'F+mzhRVdcwLS5tk2NDB2MbgMm7A0nk39G+NGEjXpTV0=' + ).toBeTruthy() }) it('verify v1', async () => { diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 99e8d26..6208457 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -23,19 +23,21 @@ export class WithdrawStorage { const amount_buf = Buffer.alloc(8) amount_buf.writeBigInt64BE(tx.amount) - return sha3_256(sha3_256( - Buffer.concat([ - bridge_id_buf, - sequence_buf, - AccAddress.toBuffer(tx.sender), - SPLITTER, - AccAddress.toBuffer(tx.receiver), - SPLITTER, - Buffer.from(tx.l1_denom, 'utf8'), - SPLITTER, - amount_buf - ]) - )) + return sha3_256( + sha3_256( + Buffer.concat([ + bridge_id_buf, + sequence_buf, + AccAddress.toBuffer(tx.sender), + SPLITTER, + AccAddress.toBuffer(tx.receiver), + SPLITTER, + Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, + amount_buf + ]) + ) + ) }) this.tree = new MerkleTree(leaves, sha3_256, { sort: true }) @@ -57,19 +59,21 @@ export class WithdrawStorage { return this.tree .getHexProof( - sha3_256(sha3_256( - Buffer.concat([ - bridge_id_buf, - sequence_buf, - AccAddress.toBuffer(tx.sender), - SPLITTER, - AccAddress.toBuffer(tx.receiver), - SPLITTER, - Buffer.from(tx.l1_denom, 'utf8'), - SPLITTER, - amount_buf - ]) - )) + sha3_256( + sha3_256( + Buffer.concat([ + bridge_id_buf, + sequence_buf, + AccAddress.toBuffer(tx.sender), + SPLITTER, + AccAddress.toBuffer(tx.receiver), + SPLITTER, + Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, + amount_buf + ]) + ) + ) ) .map((v) => convertHexToBase64(v.replace('0x', ''))) } @@ -94,19 +98,21 @@ export class WithdrawStorage { const amount_buf = Buffer.alloc(8) amount_buf.writeBigInt64BE(tx.amount) - let hashBuf = sha3_256(sha3_256( - Buffer.concat([ - bridge_id_buf, - sequence_buf, - AccAddress.toBuffer(tx.sender), - SPLITTER, - AccAddress.toBuffer(tx.receiver), - SPLITTER, - Buffer.from(tx.l1_denom, 'utf8'), - SPLITTER, - amount_buf - ]) - )) + let hashBuf = sha3_256( + sha3_256( + Buffer.concat([ + bridge_id_buf, + sequence_buf, + AccAddress.toBuffer(tx.sender), + SPLITTER, + AccAddress.toBuffer(tx.receiver), + SPLITTER, + Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, + amount_buf + ]) + ) + ) proof.forEach((proofElem) => { const proofBuf = Buffer.from(proofElem, 'base64') diff --git a/src/service/executor/ClaimTxService.ts b/src/service/executor/ClaimTxService.ts index 2df3752..8e67b91 100644 --- a/src/service/executor/ClaimTxService.ts +++ b/src/service/executor/ClaimTxService.ts @@ -38,70 +38,69 @@ export async function getClaimTxList( ): Promise { const [db] = getDB() - const offset = param.offset ?? 0 - const order = param.descending ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 20 - - const claimTxList: ClaimTx[] = [] - - const withdrawalRepo = db.getRepository(ExecutorWithdrawalTxEntity) - const withdrawalWhereCond = {} + const offset = param.offset ?? 0 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 + + const claimTxList: ClaimTx[] = [] + + const withdrawalRepo = db.getRepository(ExecutorWithdrawalTxEntity) + const withdrawalWhereCond = {} + + if (param.address) { + withdrawalWhereCond['receiver'] = param.address + } + + if (param.sequence) { + withdrawalWhereCond['sequence'] = param.sequence + } + + const withdrawalTxs = await withdrawalRepo.find({ + where: withdrawalWhereCond, + order: { + sequence: order + }, + skip: offset * limit, + take: limit + }) + + withdrawalTxs.map(async (withdrawalTx) => { + const output = await db.getRepository(ExecutorOutputEntity).findOne({ + where: { outputIndex: withdrawalTx.outputIndex } + }) - if (param.address) { - withdrawalWhereCond['receiver'] = param.address + if (!output) { + throw new APIError(ErrorTypes.NOT_FOUND_ERROR) } - if (param.sequence) { - withdrawalWhereCond['sequence'] = param.sequence + const claimData: ClaimTx = { + bridgeId: parseInt(withdrawalTx.bridgeId), + outputIndex: withdrawalTx.outputIndex, + merkleProof: withdrawalTx.merkleProof, + sender: withdrawalTx.sender, + receiver: withdrawalTx.receiver, + amount: parseInt(withdrawalTx.amount), + l2Denom: withdrawalTx.l2Denom, + version: sha3_256(withdrawalTx.outputIndex).toString('base64'), + stateRoot: output.stateRoot, + merkleRoot: output.merkleRoot, + lastBlockHash: output.lastBlockHash } + claimTxList.push(claimData) + }) - const withdrawalTxs = await withdrawalRepo.find({ - where: withdrawalWhereCond, - order: { - sequence: order - }, - skip: offset * limit, - take: limit - }) - - withdrawalTxs.map(async (withdrawalTx) => { - const output = await db.getRepository(ExecutorOutputEntity) - .findOne({ - where: { outputIndex: withdrawalTx.outputIndex } - }) - - if (!output) { - throw new APIError(ErrorTypes.NOT_FOUND_ERROR) - } - - const claimData: ClaimTx = { - bridgeId: parseInt(withdrawalTx.bridgeId), - outputIndex: withdrawalTx.outputIndex, - merkleProof: withdrawalTx.merkleProof, - sender: withdrawalTx.sender, - receiver: withdrawalTx.receiver, - amount: parseInt(withdrawalTx.amount), - l2Denom: withdrawalTx.l2Denom, - version: sha3_256(withdrawalTx.outputIndex).toString('base64'), - stateRoot: output.stateRoot, - merkleRoot: output.merkleRoot, - lastBlockHash: output.lastBlockHash - } - claimTxList.push(claimData) - }) - - const count = withdrawalTxs.length + const count = withdrawalTxs.length - let next: number | undefined + let next: number | undefined - if (count > (offset + 1) * limit) { - next = offset + 1 - } + if (count > (offset + 1) * limit) { + next = offset + 1 + } - return { - count, - next, - limit, - claimTxList - } + return { + count, + next, + limit, + claimTxList + } } diff --git a/src/service/executor/DepositTxService.ts b/src/service/executor/DepositTxService.ts index 7dbc3a9..21b7eb0 100644 --- a/src/service/executor/DepositTxService.ts +++ b/src/service/executor/DepositTxService.ts @@ -20,42 +20,42 @@ export async function getDepositTxList( param: GetDepositTxListParam ): Promise { const [db] = getDB() - const offset = param.offset ?? 0 - const order = param.descending ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 20 - - const depositTxRepo = db.getRepository(ExecutorDepositTxEntity) - const depositTxWhereCond = {} - - if (param.sequence) { - depositTxWhereCond['sequence'] = param.sequence - } - - if (param.address) { - depositTxWhereCond['sender'] = param.address - } - - const depositTxList = await depositTxRepo.find({ - where: depositTxWhereCond, - order: { - sequence: order - }, - skip: offset * limit, - take: limit - }) - - const count = depositTxList.length - - let next: number | undefined - - if (count > (offset + 1) * limit) { - next = offset + 1 - } - - return { - count, - next, - limit, - depositTxList - } + const offset = param.offset ?? 0 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 + + const depositTxRepo = db.getRepository(ExecutorDepositTxEntity) + const depositTxWhereCond = {} + + if (param.sequence) { + depositTxWhereCond['sequence'] = param.sequence + } + + if (param.address) { + depositTxWhereCond['sender'] = param.address + } + + const depositTxList = await depositTxRepo.find({ + where: depositTxWhereCond, + order: { + sequence: order + }, + skip: offset * limit, + take: limit + }) + + const count = depositTxList.length + + let next: number | undefined + + if (count > (offset + 1) * limit) { + next = offset + 1 + } + + return { + count, + next, + limit, + depositTxList + } } diff --git a/src/service/executor/OutputService.ts b/src/service/executor/OutputService.ts index 2b398ec..e80293f 100644 --- a/src/service/executor/OutputService.ts +++ b/src/service/executor/OutputService.ts @@ -20,37 +20,37 @@ export async function getOutputList( param: GetOutputListParam ): Promise { const [db] = getDB() - const offset = param.offset ?? 0 - const order = param.descending ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 20 - - const outputRepo = db.getRepository(ExecutorOutputEntity) - const outputWhereCond = {} - - if (param.output_index) { - outputWhereCond['outputIndex'] = param.output_index - } - - const outputList = await outputRepo.find({ - where: outputWhereCond, - order: { - outputIndex: order - }, - skip: offset * limit, - take: limit - }) - - const count = outputList.length - let next: number | undefined - - if (count > (offset + 1) * limit) { - next = offset + 1 - } - - return { - count, - next, - limit, - outputList - } + const offset = param.offset ?? 0 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 + + const outputRepo = db.getRepository(ExecutorOutputEntity) + const outputWhereCond = {} + + if (param.output_index) { + outputWhereCond['outputIndex'] = param.output_index + } + + const outputList = await outputRepo.find({ + where: outputWhereCond, + order: { + outputIndex: order + }, + skip: offset * limit, + take: limit + }) + + const count = outputList.length + let next: number | undefined + + if (count > (offset + 1) * limit) { + next = offset + 1 + } + + return { + count, + next, + limit, + outputList + } } diff --git a/src/service/executor/WithdrawalTxService.ts b/src/service/executor/WithdrawalTxService.ts index badd75c..83f4d28 100644 --- a/src/service/executor/WithdrawalTxService.ts +++ b/src/service/executor/WithdrawalTxService.ts @@ -20,42 +20,42 @@ export async function getWithdrawalTxList( param: GetWithdrawalTxListParam ): Promise { const [db] = getDB() - const offset = param.offset ?? 0 - const order = param.descending ? 'DESC' : 'ASC' - const limit = Number(param.limit) ?? 20 - - const withdrawalRepo = db.getRepository(ExecutorWithdrawalTxEntity) - const withdrawalWhereCond = {} - - if (param.sequence) { - withdrawalWhereCond['sequence'] = param.sequence - } - - if (param.address) { - withdrawalWhereCond['receiver'] = param.address - } - - const withdrawalTxList = await withdrawalRepo.find({ - where: withdrawalWhereCond, - order: { - sequence: order - }, - skip: offset * limit, - take: limit - }) - - const count = withdrawalTxList.length - - let next: number | undefined - - if (count > (offset + 1) * param.limit) { - next = offset + 1 - } - - return { - count, - next, - limit: param.limit, - withdrawalTxList - } + const offset = param.offset ?? 0 + const order = param.descending ? 'DESC' : 'ASC' + const limit = Number(param.limit) ?? 20 + + const withdrawalRepo = db.getRepository(ExecutorWithdrawalTxEntity) + const withdrawalWhereCond = {} + + if (param.sequence) { + withdrawalWhereCond['sequence'] = param.sequence + } + + if (param.address) { + withdrawalWhereCond['receiver'] = param.address + } + + const withdrawalTxList = await withdrawalRepo.find({ + where: withdrawalWhereCond, + order: { + sequence: order + }, + skip: offset * limit, + take: limit + }) + + const count = withdrawalTxList.length + + let next: number | undefined + + if (count > (offset + 1) * param.limit) { + next = offset + 1 + } + + return { + count, + next, + limit: param.limit, + withdrawalTxList + } } diff --git a/src/worker/bridgeExecutor/monitor/helper.ts b/src/worker/bridgeExecutor/monitor/helper.ts index d0302c1..8456369 100644 --- a/src/worker/bridgeExecutor/monitor/helper.ts +++ b/src/worker/bridgeExecutor/monitor/helper.ts @@ -12,7 +12,12 @@ import { WithdrawStorage } from '../../../lib/storage' import { WithdrawalTx } from '../../../lib/types' import { sha3_256 } from '../../../lib/util' import OutputEntity from '../../../orm/executor/OutputEntity' -import { EntityManager, EntityTarget, MoreThanOrEqual, ObjectLiteral } from 'typeorm' +import { + EntityManager, + EntityTarget, + MoreThanOrEqual, + ObjectLiteral +} from 'typeorm' import { Block, BlockResults, RPCClient } from '../../../lib/rpc' class MonitorHelper { @@ -100,7 +105,7 @@ class MonitorHelper { where: { outputIndex: MoreThanOrEqual(startIndex) as any }, - order: { outputIndex: 'ASC' } as any, + order: { outputIndex: 'ASC' } as any }) } diff --git a/src/worker/bridgeExecutor/monitor/l2.ts b/src/worker/bridgeExecutor/monitor/l2.ts index 2a83434..f3c7b38 100644 --- a/src/worker/bridgeExecutor/monitor/l2.ts +++ b/src/worker/bridgeExecutor/monitor/l2.ts @@ -124,7 +124,9 @@ export class L2Monitor extends Monitor { // if no output from DB, create output if (!lastOutputFromDB) { - this.logger.info(`[checkSubmissionInterval - ${this.name()}] No output from DB`) + this.logger.info( + `[checkSubmissionInterval - ${this.name()}] No output from DB` + ) return true } @@ -132,26 +134,30 @@ export class L2Monitor extends Monitor { if (!lastOutputSubmitted) return false // if output index not matched, wait for submission - if (lastOutputSubmitted.output_index !== lastOutputFromDB.outputIndex) return false - + if (lastOutputSubmitted.output_index !== lastOutputFromDB.outputIndex) + return false + const lastOutputSubmittedTime = lastOutputSubmitted.output_proposal.l1_block_time - const bridgeInfo = await getBridgeInfo(this.bridgeId) + const bridgeInfo = await getBridgeInfo(this.bridgeId) const submissionInterval = bridgeInfo.bridge_config.submission_interval.seconds.toNumber() - const targetTimeSec = this.dateToSeconds(lastOutputSubmittedTime) + - Math.floor(submissionInterval * config.SUBMISSION_THRESHOLD) + const targetTimeSec = + this.dateToSeconds(lastOutputSubmittedTime) + + Math.floor(submissionInterval * config.SUBMISSION_THRESHOLD) // if submission interval not reached, wait for submission - if ( - this.getCurTimeSec() < targetTimeSec - ) { - this.logger.info(`[checkSubmissionInterval - ${this.name()}] need to wait for submission interval ${targetTimeSec - this.getCurTimeSec()}`) + if (this.getCurTimeSec() < targetTimeSec) { + this.logger.info( + `[checkSubmissionInterval - ${this.name()}] need to wait for submission interval ${targetTimeSec - this.getCurTimeSec()}` + ) return false } - + // if submission interval reached, create output - this.logger.info(`[checkSubmissionInterval - ${this.name()}] Submission interval reached`) + this.logger.info( + `[checkSubmissionInterval - ${this.name()}] Submission interval reached` + ) return true } @@ -207,8 +213,10 @@ export class L2Monitor extends Monitor { startBlockNumber, endBlockNumber ) - - this.logger.info(`output entity created: block height (${startBlockNumber} - ${endBlockNumber})`) + + this.logger.info( + `output entity created: block height (${startBlockNumber} - ${endBlockNumber})` + ) await this.helper.saveEntity(manager, ExecutorOutputEntity, outputEntity) } diff --git a/src/worker/bridgeExecutor/monitor/monitor.ts b/src/worker/bridgeExecutor/monitor/monitor.ts index 192c272..8a6d96a 100644 --- a/src/worker/bridgeExecutor/monitor/monitor.ts +++ b/src/worker/bridgeExecutor/monitor/monitor.ts @@ -53,7 +53,7 @@ export abstract class Monitor { }) this.syncedHeight = state?.height || 0 - + if (!state) { if (this.name() === BOT_NAME.EXECUTOR_L1_MONITOR) { this.syncedHeight = config.EXECUTOR_L1_MONITOR_HEIGHT diff --git a/src/worker/challenger/challenger.ts b/src/worker/challenger/challenger.ts index da9ec04..269b54d 100644 --- a/src/worker/challenger/challenger.ts +++ b/src/worker/challenger/challenger.ts @@ -200,13 +200,12 @@ export class Challenger { : (await getOutputInfoByIndex(this.bridgeId, outputIndex - 1)) .output_proposal.l2_block_number + 1 const endBlockNumber = output.output_proposal.l2_block_number - + const state = await manager.getRepository(StateEntity).findOne({ where: { name: 'challenger_l2_monitor' } }) if (!state || state.height < endBlockNumber) return null - const blockInfo = await config.l2lcd.tendermint.blockInfo(endBlockNumber) const txEntities = await this.helper.getWithdrawalTxs( diff --git a/src/worker/common/name.ts b/src/worker/common/name.ts index fce7c65..68ec037 100644 --- a/src/worker/common/name.ts +++ b/src/worker/common/name.ts @@ -1,6 +1,6 @@ export const BOT_NAME = { - EXECUTOR_L1_MONITOR: 'executor_l1_monitor', - EXECUTOR_L2_MONITOR: 'executor_l2_monitor', - CHALLENGER_L1_MONITOR: 'challenger_l1_monitor', - CHALLENGER_L2_MONITOR: 'challenger_l2_monitor', -} \ No newline at end of file + EXECUTOR_L1_MONITOR: 'executor_l1_monitor', + EXECUTOR_L2_MONITOR: 'executor_l2_monitor', + CHALLENGER_L1_MONITOR: 'challenger_l1_monitor', + CHALLENGER_L2_MONITOR: 'challenger_l2_monitor' +} diff --git a/src/worker/outputSubmitter/outputSubmitter.ts b/src/worker/outputSubmitter/outputSubmitter.ts index 71d29f0..2291509 100644 --- a/src/worker/outputSubmitter/outputSubmitter.ts +++ b/src/worker/outputSubmitter/outputSubmitter.ts @@ -46,14 +46,13 @@ export class OutputSubmitter { } } - async getOutputs( - manager: EntityManager - ): Promise { + async getOutputs(manager: EntityManager): Promise { try { const lastOutputInfo = await getLastOutputInfo(this.bridgeId) if (lastOutputInfo) { this.syncedOutputIndex = lastOutputInfo.output_index + 1 - this.processedBlockNumber = lastOutputInfo.output_proposal.l2_block_number + this.processedBlockNumber = + lastOutputInfo.output_proposal.l2_block_number } const outputs = await this.helper.getAllOutput( @@ -86,7 +85,7 @@ export class OutputSubmitter { } const chunkedOutputs: ExecutorOutputEntity[] = [] - + for (let i = 0; i < outputs.length; i += MAX_OUTPUT_PROPOSAL) { chunkedOutputs.push(...outputs.slice(i, i + MAX_OUTPUT_PROPOSAL)) await this.proposeOutputs(chunkedOutputs) @@ -101,7 +100,7 @@ export class OutputSubmitter { private async proposeOutputs(outputEntities: ExecutorOutputEntity[]) { const msgs: Msg[] = [] - + for (const output of outputEntities) { msgs.push( new MsgProposeOutput( @@ -114,7 +113,10 @@ export class OutputSubmitter { } await this.submitter.transaction(msgs, undefined, 1000 * 60 * 10) // 10 minutes - this.processedBlockNumber = outputEntities[outputEntities.length - 1].endBlockNumber - logger.info(`succeed to propose ${outputEntities.length} outputs from ${outputEntities[0].outputIndex} to ${outputEntities[outputEntities.length - 1].outputIndex}, processed block number ${this.processedBlockNumber}`) + this.processedBlockNumber = + outputEntities[outputEntities.length - 1].endBlockNumber + logger.info( + `succeed to propose ${outputEntities.length} outputs from ${outputEntities[0].outputIndex} to ${outputEntities[outputEntities.length - 1].outputIndex}, processed block number ${this.processedBlockNumber}` + ) } } From 82fc996352b5551dd7719df6893b703f19833668 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 16:23:47 +0900 Subject: [PATCH 16/19] fix logging --- src/worker/bridgeExecutor/monitor/l2.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/worker/bridgeExecutor/monitor/l2.ts b/src/worker/bridgeExecutor/monitor/l2.ts index f3c7b38..593d7e5 100644 --- a/src/worker/bridgeExecutor/monitor/l2.ts +++ b/src/worker/bridgeExecutor/monitor/l2.ts @@ -148,9 +148,12 @@ export class L2Monitor extends Monitor { // if submission interval not reached, wait for submission if (this.getCurTimeSec() < targetTimeSec) { - this.logger.info( - `[checkSubmissionInterval - ${this.name()}] need to wait for submission interval ${targetTimeSec - this.getCurTimeSec()}` - ) + if (this.currentHeight % 10 === 0){ + this.logger.info( + `[checkSubmissionInterval - ${this.name()}] need to wait for submission interval ${targetTimeSec - this.getCurTimeSec()} seconds` + ) + } + return false } @@ -162,13 +165,8 @@ export class L2Monitor extends Monitor { } async handleOutput(manager: EntityManager): Promise { - if (!(await this.checkSubmissionInterval(manager))) { - if (this.currentHeight % 10 === 0) - this.logger.info( - `[handleOutput - ${this.name()}] Submission interval not reached` - ) - return - } + if (!(await this.checkSubmissionInterval(manager))) return + const lastOutput = await this.helper.getLastOutputFromDB( manager, From d78ca827d158f823a87907b911598051b240c9d4 Mon Sep 17 00:00:00 2001 From: JSHan94 Date: Fri, 14 Jun 2024 16:26:47 +0900 Subject: [PATCH 17/19] remove output_tx --- src/orm/index.ts | 4 ---- src/orm/output/OutputTxEntity.ts | 14 -------------- src/worker/outputSubmitter/db.ts | 4 ++-- 3 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 src/orm/output/OutputTxEntity.ts diff --git a/src/orm/index.ts b/src/orm/index.ts index c494e04..7de4793 100644 --- a/src/orm/index.ts +++ b/src/orm/index.ts @@ -8,8 +8,6 @@ import ExecutorUnconfirmedTxEntity from './executor/UnconfirmedTxEntity' import RecordEntity from './batch/RecordEntity' import BatchTxEntity from './batch/BatchTxEntity' -import OutputTxEntity from './output/OutputTxEntity' - import ChallengerDepositTxEntity from './challenger/DepositTxEntity' import ChallengerWithdrawalTxEntity from './challenger/WithdrawalTxEntity' import ChallengerFinalizeDepositTxEntity from './challenger/FinalizeDepositTxEntity' @@ -18,7 +16,6 @@ import ChallengerOutputEntity from './challenger/OutputEntity' import ChallengedOutputEntity from './challenger/DeletedOutputEntity' import ChallengeEntity from './challenger/ChallengeEntity' -export * from './output/OutputTxEntity' export * from './batch/RecordEntity' export * from './batch/BatchTxEntity' @@ -40,7 +37,6 @@ export * from './challenger/ChallengeEntity' export { RecordEntity, BatchTxEntity, - OutputTxEntity, StateEntity, ExecutorWithdrawalTxEntity, ExecutorDepositTxEntity, diff --git a/src/orm/output/OutputTxEntity.ts b/src/orm/output/OutputTxEntity.ts deleted file mode 100644 index 0ac6712..0000000 --- a/src/orm/output/OutputTxEntity.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Column, Entity, Index, PrimaryColumn } from 'typeorm' - -@Entity('output_tx') -export default class OutputTxEntity { - @PrimaryColumn('text') - txHash: string - - @Column() - @Index('output_tx_output_index_index') - outputIndex: number - - @Column() - processed: boolean -} diff --git a/src/worker/outputSubmitter/db.ts b/src/worker/outputSubmitter/db.ts index 39a4301..8563735 100644 --- a/src/worker/outputSubmitter/db.ts +++ b/src/worker/outputSubmitter/db.ts @@ -11,12 +11,12 @@ import dbg from 'debug' const debug = dbg('orm') -import { ExecutorOutputEntity, OutputTxEntity } from '../../orm' +import { ExecutorOutputEntity } from '../../orm' const staticOptions = { supportBigNumbers: true, bigNumberStrings: true, - entities: [ExecutorOutputEntity, OutputTxEntity] + entities: [ExecutorOutputEntity] } let DB: DataSource[] = [] From ce5d04b94788e6d595e469ac57bf8036cecea3a6 Mon Sep 17 00:00:00 2001 From: ALPAC-4 Date: Mon, 15 Jul 2024 16:54:22 +0900 Subject: [PATCH 18/19] remove double hashing --- src/lib/storage.ts | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 6208457..36cc5b3 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -24,19 +24,17 @@ export class WithdrawStorage { amount_buf.writeBigInt64BE(tx.amount) return sha3_256( - sha3_256( - Buffer.concat([ - bridge_id_buf, - sequence_buf, - AccAddress.toBuffer(tx.sender), - SPLITTER, - AccAddress.toBuffer(tx.receiver), - SPLITTER, - Buffer.from(tx.l1_denom, 'utf8'), - SPLITTER, - amount_buf - ]) - ) + Buffer.concat([ + bridge_id_buf, + sequence_buf, + AccAddress.toBuffer(tx.sender), + SPLITTER, + AccAddress.toBuffer(tx.receiver), + SPLITTER, + Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, + amount_buf + ]) ) }) From 973b11a985f8dcac033301238a3cc3b4dfeefab3 Mon Sep 17 00:00:00 2001 From: ALPAC-4 Date: Tue, 16 Jul 2024 11:32:14 +0900 Subject: [PATCH 19/19] fix: adjust double hashing --- src/lib/storage.ts | 48 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 36cc5b3..cc13524 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -58,19 +58,17 @@ export class WithdrawStorage { return this.tree .getHexProof( sha3_256( - sha3_256( - Buffer.concat([ - bridge_id_buf, - sequence_buf, - AccAddress.toBuffer(tx.sender), - SPLITTER, - AccAddress.toBuffer(tx.receiver), - SPLITTER, - Buffer.from(tx.l1_denom, 'utf8'), - SPLITTER, - amount_buf - ]) - ) + Buffer.concat([ + bridge_id_buf, + sequence_buf, + AccAddress.toBuffer(tx.sender), + SPLITTER, + AccAddress.toBuffer(tx.receiver), + SPLITTER, + Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, + amount_buf + ]) ) ) .map((v) => convertHexToBase64(v.replace('0x', ''))) @@ -97,19 +95,17 @@ export class WithdrawStorage { amount_buf.writeBigInt64BE(tx.amount) let hashBuf = sha3_256( - sha3_256( - Buffer.concat([ - bridge_id_buf, - sequence_buf, - AccAddress.toBuffer(tx.sender), - SPLITTER, - AccAddress.toBuffer(tx.receiver), - SPLITTER, - Buffer.from(tx.l1_denom, 'utf8'), - SPLITTER, - amount_buf - ]) - ) + Buffer.concat([ + bridge_id_buf, + sequence_buf, + AccAddress.toBuffer(tx.sender), + SPLITTER, + AccAddress.toBuffer(tx.receiver), + SPLITTER, + Buffer.from(tx.l1_denom, 'utf8'), + SPLITTER, + amount_buf + ]) ) proof.forEach((proofElem) => {