Skip to content

Commit

Permalink
Feat/add resubmit timeout flag (#415)
Browse files Browse the repository at this point in the history
* add resubmit timeout flag

* rename env var

* fix build

* change to 10s

---------

Co-authored-by: mouseless <[email protected]>
  • Loading branch information
mouseless0x and mouseless0x authored Jan 24, 2025
1 parent b95ae9c commit 60c14c3
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 125 deletions.
3 changes: 3 additions & 0 deletions src/cli/alto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
bundlerOptions,
compatibilityOptions,
debugOptions,
executorOptions,
gasEstimationOptions,
logOptions,
rpcOptions,
Expand Down Expand Up @@ -71,6 +72,8 @@ export function getAltoCli(): yargs.Argv {
.group(Object.keys(compatibilityOptions), "Compatibility Options:")
.options(serverOptions)
.group(Object.keys(serverOptions), "Server Options:")
.options(executorOptions)
.group(Object.keys(executorOptions), "Executor Options:")
.options(rpcOptions)
.group(Object.keys(rpcOptions), "RPC Options:")
.options(logOptions)
Expand Down
88 changes: 48 additions & 40 deletions src/cli/config/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,43 +27,7 @@ export const bundlerArgsSchema = z.object({
return validatedAddresses
}),
"deterministic-deployer-address": addressSchema,
"entrypoint-simulation-contract": z.preprocess(
(v) => (v === "" ? undefined : v),
addressSchema.optional()
),
"refill-helper-contract": addressSchema.optional(),
"no-profit-bundling": z.boolean(),
"safe-mode": z.boolean(),
"utility-private-key": hexData32Schema
.transform((val) => privateKeyToAccount(val) satisfies Account)
.optional(),
"utility-wallet-monitor": z.boolean(),
"utility-wallet-monitor-interval": z.number(),
"executor-private-keys": z.union([
z
.array(hexData32Schema)
.transform((vals) =>
vals.map((val) => privateKeyToAccount(val) satisfies Account)
),
z
.string()
.regex(/^0x(?:[0-9a-f]{2}){32}(?:,0x(?:[0-9a-f]{2}){32})*$/)
.transform((val) =>
val
.split(",")
.map(
(val) =>
privateKeyToAccount(val as Hex) satisfies Account
)
)
]),
"max-executors": z.number().int().min(0).optional(),
"min-executor-balance": z
.string()
.transform((val) => BigInt(val))
.optional(),
"executor-refill-interval": z.number().int().min(0),
"executor-gas-multiplier": z.string().transform((val) => BigInt(val)),

"min-entity-stake": z.number().int().min(0),
"min-entity-unstake-delay": z.number().int().min(0),
Expand Down Expand Up @@ -119,13 +83,49 @@ export const bundlerArgsSchema = z.object({
","
)}`
),
"refilling-wallets": z.boolean().default(true),
"aa95-gas-multiplier": z.string().transform((val) => BigInt(val)),
"enable-fastlane": z.boolean(),
"enable-instant-bundling-endpoint": z.boolean(),
"enable-experimental-7702-endpoints": z.boolean()
})

export const executorArgsSchema = z.object({
"enable-fastlane": z.boolean(),
"resubmit-stuck-timeout": z.number().int().min(0).default(15_000),
"refilling-wallets": z.boolean().default(true),
"aa95-gas-multiplier": z.string().transform((val) => BigInt(val)),
"refill-helper-contract": addressSchema.optional(),
"no-profit-bundling": z.boolean(),
"utility-private-key": hexData32Schema
.transform((val) => privateKeyToAccount(val) satisfies Account)
.optional(),
"utility-wallet-monitor": z.boolean(),
"utility-wallet-monitor-interval": z.number(),
"executor-private-keys": z.union([
z
.array(hexData32Schema)
.transform((vals) =>
vals.map((val) => privateKeyToAccount(val) satisfies Account)
),
z
.string()
.regex(/^0x(?:[0-9a-f]{2}){32}(?:,0x(?:[0-9a-f]{2}){32})*$/)
.transform((val) =>
val
.split(",")
.map(
(val) =>
privateKeyToAccount(val as Hex) satisfies Account
)
)
]),
"max-executors": z.number().int().min(0).optional(),
"min-executor-balance": z
.string()
.transform((val) => BigInt(val))
.optional(),
"executor-refill-interval": z.number().int().min(0),
"executor-gas-multiplier": z.string().transform((val) => BigInt(val))
})

export const compatibilityArgsSchema = z.object({
"chain-type": z.enum([
"default",
Expand Down Expand Up @@ -200,6 +200,10 @@ export const debugArgsSchema = z.object({
})

export const gasEstimationArgsSchema = z.object({
"entrypoint-simulation-contract": z.preprocess(
(v) => (v === "" ? undefined : v),
addressSchema.optional()
),
"binary-search-tolerance-delta": z
.string()
.transform((val) => BigInt(val))
Expand Down Expand Up @@ -235,6 +239,9 @@ export type IBundlerArgsInput = z.input<typeof bundlerArgsSchema>
export type ICompatibilityArgs = z.infer<typeof compatibilityArgsSchema>
export type ICompatibilityArgsInput = z.input<typeof compatibilityArgsSchema>

export type IExecutorArgs = z.infer<typeof executorArgsSchema>
export type IExecutorArgsInput = z.input<typeof executorArgsSchema>

export type IServerArgs = z.infer<typeof serverArgsSchema>
export type IServerArgsInput = z.input<typeof serverArgsSchema>

Expand All @@ -257,7 +264,8 @@ export const optionArgsSchema = z.object({
...serverArgsSchema.shape,
...rpcArgsSchema.shape,
...debugArgsSchema.shape,
...gasEstimationArgsSchema.shape
...gasEstimationArgsSchema.shape,
...executorArgsSchema.shape
})

export type IOptions = z.infer<typeof optionArgsSchema>
Expand Down
171 changes: 91 additions & 80 deletions src/cli/config/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
IBundlerArgsInput,
ICompatibilityArgsInput,
IDebugArgsInput,
IExecutorArgsInput,
IGasEstimationArgsInput,
ILogArgsInput,
IOptionsInput,
Expand All @@ -25,56 +26,6 @@ export const bundlerOptions: CliCommandOptions<IBundlerArgsInput> = {
require: false,
default: "0x4e59b44847b379578588920ca78fbf26c0b4956c"
},
"entrypoint-simulation-contract": {
description: "Address of the EntryPoint simulations contract",
type: "string",
alias: "c",
require: false
},
"refill-helper-contract": {
description: "Address of the Executor refill helper contract",
type: "string",
require: false
},
"executor-private-keys": {
description: "Private keys of the executor accounts split by commas",
type: "string",
alias: "x",
require: true
},
"utility-private-key": {
description: "Private key of the utility account",
type: "string",
alias: "u",
require: false
},
"utility-wallet-monitor": {
description: "Either to enable utility wallet monitor or not",
type: "boolean",
default: true
},
"utility-wallet-monitor-interval": {
description: "Interval for checking utility wallet balance",
type: "number",
default: 15 * 1000 // 15 seconds
},
"max-executors": {
description:
"Maximum number of executor accounts to use from the list of executor private keys",
type: "number",
require: false
},
"min-executor-balance": {
description:
"Minimum balance required for each executor account (below which the utility account will refill)",
type: "string"
},
"executor-refill-interval": {
description: "Interval to refill the signer balance (seconds)",
type: "number",
require: true,
default: 60 * 20
},
"min-entity-stake": {
description: "Minimum stake required for a relay (in 10e18)",
type: "number",
Expand Down Expand Up @@ -112,12 +63,6 @@ export const bundlerOptions: CliCommandOptions<IBundlerArgsInput> = {
require: false,
default: "100"
},
"no-profit-bundling": {
description:
"Bundle tx such that all beneficiary fees are spent on gas fees",
type: "boolean",
default: false
},
"gas-price-floor-percent": {
description:
"The minimum percentage of incoming user operation gas prices compared to the gas price used by the bundler to submit bundles",
Expand Down Expand Up @@ -179,19 +124,6 @@ export const bundlerOptions: CliCommandOptions<IBundlerArgsInput> = {
require: false,
default: null
},
"refilling-wallets": {
description: "Enable refilling wallets",
type: "boolean",
require: false,
default: true
},
"aa95-gas-multiplier": {
description:
"Amount to multiply the current gas limit by if the bundling tx fails due to AA95",
type: "string",
require: false,
default: "125"
},
"enable-instant-bundling-endpoint": {
description:
"Should the bundler enable the pimlico_sendUserOperationNow endpoint",
Expand All @@ -203,22 +135,17 @@ export const bundlerOptions: CliCommandOptions<IBundlerArgsInput> = {
"Should the bundler enable the pimlico_experimental_sendUserOperation7702 and pimlico_experimental_estimateUserOperationGas7702 endpoint",
type: "boolean",
default: false
},
"executor-gas-multiplier": {
description: "Amount to scale the gas estimations used for bundling",
type: "string",
default: "100"
},
"enable-fastlane": {
description:
"Enable bundling v0.6 userOperations using the pfl_sendRawTransactionConditional endpoint",
type: "boolean",
default: false
}
}

export const gasEstimationOptions: CliCommandOptions<IGasEstimationArgsInput> =
{
"entrypoint-simulation-contract": {
description: "Address of the EntryPoint simulations contract",
type: "string",
alias: "c",
require: false
},
"binary-search-tolerance-delta": {
description:
"Defines the threshold for when to stop the gas estimation binary search",
Expand Down Expand Up @@ -298,6 +225,90 @@ export const gasEstimationOptions: CliCommandOptions<IGasEstimationArgsInput> =
}
}

export const executorOptions: CliCommandOptions<IExecutorArgsInput> = {
"enable-fastlane": {
description:
"Enable bundling v0.6 userOperations using the pfl_sendRawTransactionConditional endpoint",
type: "boolean",
default: false
},
"resubmit-stuck-timeout": {
description:
"Amount of time before retrying a failed userOperation (in ms)",
type: "number",
require: true,
default: 10_000
},
"aa95-gas-multiplier": {
description:
"Amount to multiply the current gas limit by if the bundling tx fails due to AA95",
type: "string",
require: false,
default: "125"
},
"refilling-wallets": {
description: "Enable refilling wallets",
type: "boolean",
require: false,
default: true
},
"executor-gas-multiplier": {
description: "Amount to scale the gas estimations used for bundling",
type: "string",
default: "100"
},
"no-profit-bundling": {
description:
"Bundle tx such that all beneficiary fees are spent on gas fees",
type: "boolean",
default: false
},
"refill-helper-contract": {
description: "Address of the Executor refill helper contract",
type: "string",
require: false
},
"executor-private-keys": {
description: "Private keys of the executor accounts split by commas",
type: "string",
alias: "x",
require: true
},
"utility-private-key": {
description: "Private key of the utility account",
type: "string",
alias: "u",
require: false
},
"utility-wallet-monitor": {
description: "Either to enable utility wallet monitor or not",
type: "boolean",
default: true
},
"utility-wallet-monitor-interval": {
description: "Interval for checking utility wallet balance",
type: "number",
default: 15 * 1000 // 15 seconds
},
"max-executors": {
description:
"Maximum number of executor accounts to use from the list of executor private keys",
type: "number",
require: false
},
"min-executor-balance": {
description:
"Minimum balance required for each executor account (below which the utility account will refill)",
type: "string"
},
"executor-refill-interval": {
description: "Interval to refill the signer balance (seconds)",
type: "number",
require: true,
default: 60 * 20
}
}

export const compatibilityOptions: CliCommandOptions<ICompatibilityArgsInput> =
{
"chain-type": {
Expand Down
8 changes: 4 additions & 4 deletions src/executor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,14 @@ export class Executor {
return { status: "failed" }
}

newRequest.maxFeePerGas = maxBigInt(
newRequest.maxFeePerGas = scaleBigIntByPercent(
gasPriceParameters.maxFeePerGas,
(newRequest.maxFeePerGas * 11n + 9n) / 10n
115n
)

newRequest.maxPriorityFeePerGas = maxBigInt(
newRequest.maxPriorityFeePerGas = scaleBigIntByPercent(
gasPriceParameters.maxPriorityFeePerGas,
(newRequest.maxPriorityFeePerGas * 11n + 9n) / 10n
115n
)
newRequest.account = transactionInfo.executor

Expand Down
5 changes: 4 additions & 1 deletion src/executor/executorManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,10 @@ export class ExecutorManager {
)
await Promise.all(
transactionInfos2.map(async (txInfo) => {
if (Date.now() - txInfo.lastReplaced < 5 * 60 * 1000) {
if (
Date.now() - txInfo.lastReplaced <
this.config.resubmitStuckTimeout
) {
return
}

Expand Down

0 comments on commit 60c14c3

Please sign in to comment.