Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make interval waiting to bundle variable #405

Merged
merged 9 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/executor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export class Executor {
): Promise<ReplaceTransactionResult> {
const newRequest = { ...transactionInfo.transactionRequest }

let gasPriceParameters
let gasPriceParameters: GasPriceParameters
try {
gasPriceParameters =
await this.gasPriceManager.tryGetNetworkGasPrice()
Expand Down
81 changes: 56 additions & 25 deletions src/executor/executorManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ function getTransactionsFromUserOperationEntries(
)
}

const MIN_INTERVAL = 100 // 0.1 seconds (100ms)
const MAX_INTERVAL = 1000 // Capped at 1 second (1000ms)
const SCALE_FACTOR = 5 // Interval increases by 5ms per task per minute
const RPM_WINDOW = 60000 // 1 minute window in ms

export class ExecutorManager {
private config: AltoConfig
private executor: Executor
Expand All @@ -61,6 +66,7 @@ export class ExecutorManager {
private timer?: NodeJS.Timer
private gasPriceManager: GasPriceManager
private eventManager: EventManager
private opsCount: number[] = []

constructor({
config,
Expand Down Expand Up @@ -97,23 +103,66 @@ export class ExecutorManager {
this.eventManager = eventManager

if (this.config.bundleMode === "auto") {
this.timer = setInterval(async () => {
await this.bundle()
}, this.config.maxBundleWait) as NodeJS.Timer
this.autoScalingBundling()
}
}

setBundlingMode(bundleMode: BundlingMode): void {
if (bundleMode === "auto" && !this.timer) {
this.timer = setInterval(async () => {
await this.bundle()
}, this.config.maxBundleWait) as NodeJS.Timer
this.autoScalingBundling()
} else if (bundleMode === "manual" && this.timer) {
clearInterval(this.timer)
this.timer = undefined
}
}

async autoScalingBundling() {
const now = Date.now()
this.opsCount = this.opsCount.filter(
(timestamp) => now - timestamp < RPM_WINDOW
)

const opsToBundle = await this.getOpsToBundle()

if (opsToBundle.length > 0) {
const opsCount: number = opsToBundle.length
const timestamp: number = Date.now()
this.opsCount.push(...Array(opsCount).fill(timestamp)) // Add timestamps for each task

await this.bundle(opsToBundle)
}

const rpm: number = this.opsCount.length
// Calculate next interval with linear scaling
const nextInterval: number = Math.min(
MIN_INTERVAL + rpm * SCALE_FACTOR, // Linear scaling
MAX_INTERVAL // Cap at 1000ms
)
setTimeout(this.autoScalingBundling, nextInterval)
}

async getOpsToBundle() {
const opsToBundle: UserOperationInfo[][] = []

while (true) {
const ops = await this.mempool.process(
this.config.maxGasPerBundle,
1
)
if (ops?.length > 0) {
opsToBundle.push(ops)
} else {
break
}
}

if (opsToBundle.length === 0) {
return []
}

return opsToBundle
}

async bundleNow(): Promise<Hash[]> {
const ops = await this.mempool.process(this.config.maxGasPerBundle, 1)
if (ops.length === 0) {
Expand Down Expand Up @@ -285,25 +334,7 @@ export class ExecutorManager {
return txHash
}

async bundle() {
const opsToBundle: UserOperationInfo[][] = []

while (true) {
const ops = await this.mempool.process(
this.config.maxGasPerBundle,
1
)
if (ops?.length > 0) {
opsToBundle.push(ops)
} else {
break
}
}

if (opsToBundle.length === 0) {
return
}

async bundle(opsToBundle: UserOperationInfo[][] = []) {
await Promise.all(
opsToBundle.map(async (ops) => {
const opEntryPointMap = new Map<
Expand Down
5 changes: 4 additions & 1 deletion src/rpc/rpcHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ import {
import { base, baseSepolia, optimism } from "viem/chains"
import type { NonceQueuer } from "./nonceQueuer"
import type { AltoConfig } from "../createConfig"
import { SignedAuthorization, SignedAuthorizationList } from "viem/experimental"
import type {
SignedAuthorization,
SignedAuthorizationList
} from "viem/experimental"

export interface IRpcEndpoint {
handleMethod(
Expand Down
Loading