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

Pim 1040 #219

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
5 changes: 3 additions & 2 deletions src/cli/config/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ export const bundlerArgsSchema = z.object({
"Must contain 3 comma seperated items in format: slow,standard,fast"
)
.transform(([slow, standard, fast]) => ({ slow, standard, fast })),

"mempool-max-parallel-ops": z.number().int().min(0).default(10),
"mempool-max-queued-ops": z.number().int().min(0).default(0),
"enforce-unique-senders-per-bundle": z.boolean().default(true),
"max-gas-per-bundle": z
.string()
.transform((val) => BigInt(val))
.default("5000000")
.default("5000000"),
"send-bundle-delay": z.number().optional()
})

export const compatibilityArgsSchema = z.object({
Expand Down Expand Up @@ -124,6 +124,7 @@ export const serverArgsSchema = z.object({

export const rpcArgsSchema = z.object({
"rpc-url": z.string().url(),
"wss-url": z.string().url().optional(),
"send-transaction-rpc-url": z.string().url().optional(),
"polling-interval": z.number().int().min(0),
"max-block-range": z.number().int().min(0).optional(),
Expand Down
11 changes: 11 additions & 0 deletions src/cli/config/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ export const bundlerOptions: CliCommandOptions<IBundlerArgsInput> = {
type: "string",
require: false,
default: "5000000"
},
"send-bundle-delay": {
description:
"Delay in milliseconds to wait after a block is mined before building and sending a bundle",
type: "number",
require: false
}
}

Expand Down Expand Up @@ -247,6 +253,11 @@ export const rpcOptions: CliCommandOptions<IRpcArgsInput> = {
alias: "r",
require: true
},
"wss-url": {
description: "Websocket RPC url to connect to",
type: "string",
require: false
},
"send-transaction-rpc-url": {
description: "RPC url to send transactions to (e.g. flashbots relay)",
type: "string",
Expand Down
16 changes: 15 additions & 1 deletion src/cli/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
type Chain,
type PublicClient,
type Transport,
webSocket,
http,
formatEther
} from "viem"
Expand All @@ -24,6 +25,7 @@ import {
} from "./config"
import { customTransport } from "./customTransport"
import { setupServer } from "./setupServer"
import { watchBlockNumber } from "viem/actions"
import { PimlicoEntryPointSimulationsDeployBytecode } from "../types/contracts"
import { UtilityWalletMonitor } from "../executor/utilityWalletMonitor"
import { GasPriceManager } from "@alto/handlers"
Expand Down Expand Up @@ -111,7 +113,7 @@ export async function bundlerHandler(args: IOptionsInput): Promise<void> {
}
}

const client = createPublicClient({
let client = createPublicClient({
transport: customTransport(args["rpc-url"], {
logger: logger.child(
{ module: "public_client" },
Expand All @@ -125,6 +127,18 @@ export async function bundlerHandler(args: IOptionsInput): Promise<void> {
chain
})

if (parsedArgs["wss-url"]) {
const wssClient = createPublicClient({
transport: webSocket(parsedArgs["wss-url"]),
chain
})

// User websocket when watching for new blocks
client = client.extend((_client) => ({
watchBlockNumber: (args) => watchBlockNumber(wssClient, args)
}))
}

// if flag is set, use utility wallet to deploy the simulations contract
if (parsedArgs["deploy-simulations-contract"]) {
if (!parsedArgs["utility-private-key"]) {
Expand Down
4 changes: 3 additions & 1 deletion src/cli/setupServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const getMempool = ({
parsedArgs["mempool-max-parallel-ops"],
parsedArgs["mempool-max-queued-ops"],
parsedArgs["enforce-unique-senders-per-bundle"],
parsedArgs["chain-type"],
eventManager
)
}
Expand Down Expand Up @@ -277,7 +278,8 @@ const getExecutorManager = ({
parsedArgs["max-bundle-wait"],
parsedArgs["max-gas-per-bundle"],
gasPriceManager,
eventManager
eventManager,
parsedArgs["send-bundle-delay"]
)
}

Expand Down
17 changes: 14 additions & 3 deletions src/executor/executorManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ export class ExecutorManager {
bundlerFrequency: number,
maxGasLimitPerBundle: bigint,
gasPriceManager: GasPriceManager,
eventManager: EventManager
eventManager: EventManager,
sendBundleDelay?: number
) {
this.entryPoints = entryPoints
this.reputationManager = reputationManager
Expand All @@ -90,7 +91,17 @@ export class ExecutorManager {
this.gasPriceManager = gasPriceManager
this.eventManager = eventManager

if (bundleMode === "auto") {
if (sendBundleDelay) {
publicClient.watchBlockNumber({
onBlockNumber: async (
_blockNumber: bigint,
_prevBlockNumber: bigint | undefined
) => {
await new Promise((r) => setTimeout(r, sendBundleDelay))
await this.bundle()
}
})
} else if (bundleMode === "auto") {
this.timer = setInterval(async () => {
await this.bundle()
}, bundlerFrequency) as NodeJS.Timer
Expand Down Expand Up @@ -269,7 +280,7 @@ export class ExecutorManager {
const opsToBundle: UserOperationInfo[][] = []

while (true) {
const ops = await this.mempool.process(5_000_000n, 1)
const ops = await this.mempool.process(this.maxGasLimitPerBundle, 1)
if (ops?.length > 0) {
opsToBundle.push(ops)
} else {
Expand Down
17 changes: 15 additions & 2 deletions src/mempool/mempool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import {
deriveUserOperation,
EntryPointV07Abi
} from "@alto/types"
import type { HexData32 } from "@alto/types"
import type { ChainType, HexData32 } from "@alto/types"
import type { Logger } from "@alto/utils"
import type { EventManager } from "@alto/handlers"
import {
calcDefaultPreVerificationGas,
getAddressFromInitCodeOrPaymasterAndData,
getNonceKeyAndValue,
getUserOperationHash,
Expand Down Expand Up @@ -55,6 +56,7 @@ export class MemoryMempool {
private parallelUserOpsMaxSize: number
private queuedUserOpsMaxSize: number
private onlyUniqueSendersPerBundle: boolean
private chainType: ChainType
private eventManager: EventManager

constructor(
Expand All @@ -68,6 +70,7 @@ export class MemoryMempool {
parallelUserOpsMaxSize: number,
queuedUserOpsMaxSize: number,
onlyUniqueSendersPerBundle: boolean,
chainType: ChainType,
eventManager: EventManager,
throttledEntityBundleCount?: number
) {
Expand All @@ -82,6 +85,7 @@ export class MemoryMempool {
this.queuedUserOpsMaxSize = queuedUserOpsMaxSize
this.onlyUniqueSendersPerBundle = onlyUniqueSendersPerBundle
this.throttledEntityBundleCount = throttledEntityBundleCount ?? 4
this.chainType = chainType
this.eventManager = eventManager
}

Expand Down Expand Up @@ -658,13 +662,21 @@ export class MemoryMempool {

for (const opInfo of outstandingUserOperations) {
const op = deriveUserOperation(opInfo.mempoolUserOperation)

const preVerificationGas =
this.chainType === "op-stack"
? calcDefaultPreVerificationGas(op)
: op.preVerificationGas

gasUsed +=
op.callGasLimit +
op.verificationGasLimit * 3n +
op.preVerificationGas
preVerificationGas

if (gasUsed > maxGasLimit && opsTaken >= (minOps || 0)) {
break
}

const skipResult = await this.shouldSkip(
opInfo,
paymasterDeposit,
Expand All @@ -673,6 +685,7 @@ export class MemoryMempool {
senders,
storageMap
)

paymasterDeposit = skipResult.paymasterDeposit
stakedEntityCount = skipResult.stakedEntityCount
knownEntities = skipResult.knownEntities
Expand Down
Loading