From fecc04df44a575d70cb01ae8bf67ea29af93927c Mon Sep 17 00:00:00 2001 From: Souradeep Das Date: Thu, 1 Jun 2023 16:48:36 +0530 Subject: [PATCH] fix: bundler relies on eth_getLogs with indefinite range (#855) * fix: workaround for bundler eth_getLogs range * remove unused deps * fix: rename to l2Offset * add configurable logsChunckSize --------- Co-authored-by: Riedl Kevin, Bsc (cherry picked from commit 13a1222e6ae0700183fd33ac013e262620129538) --- .../boba/account-abstraction/package.json | 1 - packages/boba/bundler/package.json | 1 - packages/boba/bundler/src/BundlerConfig.ts | 6 ++++ packages/boba/bundler/src/BundlerServer.ts | 4 +-- .../boba/bundler/src/UserOpMethodHandler.ts | 17 ++++++---- .../boba/bundler/src/modules/EventsManager.ts | 32 +++++++++++++++++-- .../boba/bundler/src/modules/initServer.ts | 2 +- packages/boba/bundler/src/runBundler.ts | 2 ++ 8 files changed, 51 insertions(+), 14 deletions(-) diff --git a/packages/boba/account-abstraction/package.json b/packages/boba/account-abstraction/package.json index 22b88bf19b..e1326f6b08 100644 --- a/packages/boba/account-abstraction/package.json +++ b/packages/boba/account-abstraction/package.json @@ -67,7 +67,6 @@ "@gnosis.pm/safe-contracts": "^1.3.0", "@nomiclabs/hardhat-etherscan": "^3.1.0", "@openzeppelin/contracts": "^4.2.0", - "@openzeppelin/contracts-upgradeable": "4.3.2", "@thehubbleproject/bls": "^0.5.1", "@typechain/hardhat": "^6.1.2", "@types/mocha": "^9.0.0", diff --git a/packages/boba/bundler/package.json b/packages/boba/bundler/package.json index 0b7d604f04..b3e425f212 100644 --- a/packages/boba/bundler/package.json +++ b/packages/boba/bundler/package.json @@ -20,7 +20,6 @@ }, "dependencies": { "@openzeppelin/contracts": "^4.2.0", - "@openzeppelin/contracts-upgradeable": "4.3.2", "@boba/accountabstraction": "^1.0.0", "@boba/bundler_utils": "^0.2.3", "@bobanetwork/bundler_sdk": "*", diff --git a/packages/boba/bundler/src/BundlerConfig.ts b/packages/boba/bundler/src/BundlerConfig.ts index 7702a54723..e89cf2ec85 100644 --- a/packages/boba/bundler/src/BundlerConfig.ts +++ b/packages/boba/bundler/src/BundlerConfig.ts @@ -22,6 +22,8 @@ export interface BundlerConfig { addressManager: string l1NodeWeb3Url: string enableDebugMethods: boolean + l2Offset?: number + logsChunkSize?: number } // TODO: implement merging config (args -> config.js -> default) and runtime shape validation @@ -46,6 +48,8 @@ export const BundlerConfigShape = { addressManager: ow.string, l1NodeWeb3Url: ow.string, enableDebugMethods: ow.boolean, + l2Offset: ow.optional.number, + logsChunkSize: ow.optional.number, } // TODO: consider if we want any default fields at all @@ -60,4 +64,6 @@ export const bundlerConfigDefault: Partial = { autoBundleInterval: 1, autoBundleMempoolSize: 1, enableDebugMethods: false, + l2Offset: 0, + logsChunkSize: 5000, } diff --git a/packages/boba/bundler/src/BundlerServer.ts b/packages/boba/bundler/src/BundlerServer.ts index d9e916e891..6997909bf2 100644 --- a/packages/boba/bundler/src/BundlerServer.ts +++ b/packages/boba/bundler/src/BundlerServer.ts @@ -186,10 +186,10 @@ export class BundlerServer { ) break case 'eth_getUserOperationReceipt': - result = await this.methodHandler.getUserOperationReceipt(params[0]) + result = await this.methodHandler.getUserOperationReceipt(params[0], params[1]) break case 'eth_getUserOperationByHash': - result = await this.methodHandler.getUserOperationByHash(params[0]) + result = await this.methodHandler.getUserOperationByHash(params[0], params[1]) break case 'web3_clientVersion': result = this.methodHandler.clientVersion() diff --git a/packages/boba/bundler/src/UserOpMethodHandler.ts b/packages/boba/bundler/src/UserOpMethodHandler.ts index 075dc12f0e..02dc6ed66f 100644 --- a/packages/boba/bundler/src/UserOpMethodHandler.ts +++ b/packages/boba/bundler/src/UserOpMethodHandler.ts @@ -227,11 +227,14 @@ export class UserOpMethodHandler { } async _getUserOperationEvent( - userOpHash: string + userOpHash: string, + opts?: any ): Promise { // TODO: eth_getLogs is throttled. must be acceptable for finding a UserOperation by hash const event = await this.entryPoint.queryFilter( - this.entryPoint.filters.UserOperationEvent(userOpHash) + this.entryPoint.filters.UserOperationEvent(userOpHash), + opts?.fromBlock, + opts?.toBlock ) return event[0] } @@ -269,14 +272,15 @@ export class UserOpMethodHandler { } async getUserOperationByHash( - userOpHash: string + userOpHash: string, + opts?: any ): Promise { requireCond( userOpHash?.toString()?.match(HEX_REGEX) != null, 'Missing/invalid userOpHash', -32601 ) - const event = await this._getUserOperationEvent(userOpHash) + const event = await this._getUserOperationEvent(userOpHash, opts) if (event == null) { return null } @@ -334,14 +338,15 @@ export class UserOpMethodHandler { } async getUserOperationReceipt( - userOpHash: string + userOpHash: string, + opts?: any ): Promise { requireCond( userOpHash?.toString()?.match(HEX_REGEX) != null, 'Missing/invalid userOpHash', -32601 ) - const event = await this._getUserOperationEvent(userOpHash) + const event = await this._getUserOperationEvent(userOpHash, opts) if (event == null) { return null } diff --git a/packages/boba/bundler/src/modules/EventsManager.ts b/packages/boba/bundler/src/modules/EventsManager.ts index e19462bfca..64b0c5a25a 100644 --- a/packages/boba/bundler/src/modules/EventsManager.ts +++ b/packages/boba/bundler/src/modules/EventsManager.ts @@ -7,6 +7,7 @@ import { ReputationManager } from './ReputationManager' import { EntryPoint } from '@boba/accountabstraction' import Debug from 'debug' import { TypedEvent } from '@boba/accountabstraction/dist/types/common' +import { JsonRpcProvider } from '@ethersproject/providers' import { MempoolManager } from './MempoolManager' const debug = Debug('aa.events') @@ -15,13 +16,21 @@ const debug = Debug('aa.events') * listen to events. trigger ReputationManager's Included */ export class EventsManager { + provider: JsonRpcProvider lastBlock = 0 + chunkSize = 5000 constructor( readonly entryPoint: EntryPoint, readonly mempoolManager: MempoolManager, - readonly reputationManager: ReputationManager - ) {} + readonly reputationManager: ReputationManager, + readonly l2Offset: number, + readonly logsChunkSize: number + ) { + this.provider = entryPoint.provider as JsonRpcProvider + this.lastBlock = l2Offset + this.chunkSize = logsChunkSize > 0 ? logsChunkSize : 1 + } /** * automatically listen to all UserOperationEvent events @@ -40,9 +49,26 @@ export class EventsManager { * process all new events since last run */ async handlePastEvents(): Promise { + let startBlock = this.lastBlock + const currentBlock = await this.provider.getBlockNumber() + if (currentBlock > startBlock + this.chunkSize) { + while (startBlock + this.chunkSize < currentBlock) { + const events = await this.entryPoint.queryFilter( + { address: this.entryPoint.address }, + startBlock, + startBlock + (this.chunkSize - 1) + ) + for (const ev of events) { + this.handleEvent(ev) + } + startBlock = startBlock + this.chunkSize + } + this.lastBlock = startBlock + } const events = await this.entryPoint.queryFilter( { address: this.entryPoint.address }, - this.lastBlock + this.lastBlock, + currentBlock ) for (const ev of events) { this.handleEvent(ev) diff --git a/packages/boba/bundler/src/modules/initServer.ts b/packages/boba/bundler/src/modules/initServer.ts index 12cf99f512..8b9b78cd98 100644 --- a/packages/boba/bundler/src/modules/initServer.ts +++ b/packages/boba/bundler/src/modules/initServer.ts @@ -23,7 +23,7 @@ export function initServer (config: BundlerConfig, signer: Signer): [ExecutionMa const reputationManager = new ReputationManager(BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay) const mempoolManager = new MempoolManager(reputationManager) const validationManager = new ValidationManager(entryPoint, reputationManager, config.unsafe, entryPointWrapper) - const eventsManager = new EventsManager(entryPoint, mempoolManager, reputationManager) + const eventsManager = new EventsManager(entryPoint, mempoolManager, reputationManager, config.l2Offset, config.logsChunkSize) const bundleManager = new BundleManager(entryPoint, eventsManager, mempoolManager, validationManager, reputationManager, config.beneficiary, parseEther(config.minBalance), config.maxBundleGas, config.conditionalRpc, false, entryPointWrapper) const executionManager = new ExecutionManager(reputationManager, mempoolManager, bundleManager, validationManager) diff --git a/packages/boba/bundler/src/runBundler.ts b/packages/boba/bundler/src/runBundler.ts index 0ab13236a9..13ee3b94fd 100644 --- a/packages/boba/bundler/src/runBundler.ts +++ b/packages/boba/bundler/src/runBundler.ts @@ -120,6 +120,8 @@ export async function runBundler( .option('--l1NodeWeb3Url ', 'L1 network url for Address Manager', '') .option('--maxBundleGas ', 'Max Bundle Gas available to use', '5000000') .option('--enableDebugMethods', 'debug_* methods available', false) + .option('--l2Offset ', 'l2 Offset to start from') + .option('--logsChunkSize ', 'eth_getLogs range supported by network') const programOpts = program.parse(argv).opts() showStackTraces = programOpts.showStackTraces