Skip to content

Commit

Permalink
AA-522: Support alt-mempool configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
forshtat committed Jan 26, 2025
1 parent 715ff28 commit 54170ff
Show file tree
Hide file tree
Showing 18 changed files with 132 additions and 34 deletions.
15 changes: 15 additions & 0 deletions packages/bundler/src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fs from 'fs'
import { BundlerConfig, bundlerConfigDefault, BundlerConfigShape } from './BundlerConfig'
import { Wallet, Signer } from 'ethers'
import { JsonRpcProvider } from '@ethersproject/providers'
import { AltMempoolConfig, validateAltMempoolConfigShape } from '@account-abstraction/validation-manager'

function getCommandLineParams (programOpts: any): Partial<BundlerConfig> {
const params: any = {}
Expand Down Expand Up @@ -60,3 +61,17 @@ export async function resolveConfiguration (programOpts: any): Promise<{ config:
}
return { config, provider, wallet }
}

export async function resolveAltMempoolConfig (programOpts: any): Promise<AltMempoolConfig> {
const configFileName: string = programOpts.altMempoolConfig
if (!fs.existsSync(configFileName)) {
return {}
}
try {
const fileConfig = JSON.parse(fs.readFileSync(configFileName, 'ascii'))
validateAltMempoolConfigShape(fileConfig)
return fileConfig
} catch (e: any) {
throw new Error(`Unable to read --altMempoolConfig ${configFileName}: ${e.message as string}`)
}
}
7 changes: 4 additions & 3 deletions packages/bundler/src/modules/ExecutionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ReputationManager } from './ReputationManager'
import { IBundleManager } from './IBundleManager'
import {
EmptyValidateUserOpResult,
IValidationManager, ValidationManager
IValidationManager, ValidateUserOpResult, ValidationManager
} from '@account-abstraction/validation-manager'
import { DepositManager } from './DepositManager'
import { BigNumberish, Signer } from 'ethers'
Expand Down Expand Up @@ -56,7 +56,7 @@ export class ExecutionManager {
await this.mutex.runExclusive(async () => {
debug('sendUserOperation')
this.validationManager.validateInputParameters(userOp, entryPointInput)
let validationResult = EmptyValidateUserOpResult
let validationResult: ValidateUserOpResult = EmptyValidateUserOpResult
if (!skipValidation) {
validationResult = await this.validationManager.validateUserOp(userOp)
}
Expand Down Expand Up @@ -150,7 +150,8 @@ export class ExecutionManager {
const { configuration, entryPoint, unsafe } = this.validationManager._getDebugConfiguration()
const mergedConfiguration = Object.assign({}, configuration, configOverrides)
const pvgc = new PreVerificationGasCalculator(mergedConfiguration)
const erc7562Parser = new ERC7562Parser(entryPoint.address, mergedConfiguration.senderCreator ?? '')
const bailOnViolation = Object.keys(this.mempoolManager.altMempoolConfig).length === 0
const erc7562Parser = new ERC7562Parser(bailOnViolation, entryPoint.address, mergedConfiguration.senderCreator ?? '')
this.validationManager = new ValidationManager(
entryPoint,
unsafe,
Expand Down
2 changes: 2 additions & 0 deletions packages/bundler/src/modules/MempoolEntry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BigNumber, BigNumberish } from 'ethers'
import { OperationBase, ReferencedCodeHashes, UserOperation } from '@account-abstraction/utils'
import { ERC7562Violation } from '@account-abstraction/validation-manager/dist/src/ERC7562Violation'

export class MempoolEntry {
userOpMaxGas: BigNumber
Expand All @@ -9,6 +10,7 @@ export class MempoolEntry {
readonly userOpHash: string,
readonly prefund: BigNumberish,
readonly referencedContracts: ReferencedCodeHashes,
readonly ruleViolations: ERC7562Violation[],
readonly skipValidation: boolean,
readonly aggregator?: string
) {
Expand Down
43 changes: 36 additions & 7 deletions packages/bundler/src/modules/MempoolManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
requireCond
} from '@account-abstraction/utils'
import {
AltMempoolConfig, ERC7562Rule,
ValidateUserOpResult,
ValidationResult
} from '@account-abstraction/validation-manager'

import { MempoolEntry } from './MempoolEntry'
import { ReputationManager } from './ReputationManager'
import { BaseAltMempoolRule } from '@account-abstraction/validation-manager/src/altmempool/AltMempoolConfig'

const debug = Debug('aa.mempool')

Expand All @@ -25,10 +27,19 @@ const THROTTLED_ENTITY_MEMPOOL_COUNT = 4

export class MempoolManager {
private mempool: MempoolEntry[] = []
private altMempools: { [mempoolId: number]: MempoolEntry[] } = {}

// count entities in mempool.
private _entryCount: { [addr: string]: number | undefined } = {}

constructor (
readonly reputationManager: ReputationManager,
readonly altMempoolConfig: AltMempoolConfig) {
for (const id of Object.keys(this.altMempoolConfig)){
this.altMempools[parseInt(id)] = []
}
}

entryCount (address: string): number | undefined {
return this._entryCount[address.toLowerCase()]
}
Expand All @@ -53,10 +64,6 @@ export class MempoolManager {
}
}

constructor (
readonly reputationManager: ReputationManager) {
}

count (): number {
return this.mempool.length
}
Expand All @@ -68,13 +75,14 @@ export class MempoolManager {
skipValidation: boolean,
userOp: OperationBase,
userOpHash: string,
validationResult: ValidationResult
validationResult: ValidateUserOpResult
): void {
const entry = new MempoolEntry(
userOp,
userOpHash,
validationResult.returnInfo.prefund ?? 0,
(validationResult as ValidateUserOpResult).referencedContracts,
validationResult.referencedContracts,
validationResult.ruleViolations,
skipValidation,
validationResult.aggregatorInfo?.addr
)
Expand All @@ -99,7 +107,7 @@ export class MempoolManager {
if (userOp.factory != null) {
this.incrementEntryCount(userOp.factory)
}
this.mempool.push(entry)
this.tryAssignToMempool(entry)
}
if (oldEntry != null) {
this.updateSeenStatus(oldEntry.aggregator, oldEntry.userOp, validationResult.senderInfo, -1)
Expand Down Expand Up @@ -300,4 +308,25 @@ export class MempoolManager {
}
}
}

private tryAssignToMempool (entry: MempoolEntry): number[] {
if (entry.ruleViolations.length === 0) {
this.mempool.push(entry)
return [0]
}
const mempoolIds: number[] = []
for (const violation of entry.ruleViolations) {
console.log(`Violation: ${JSON.stringify(violation)}`)
for (const [id, config] of Object.entries(this.altMempoolConfig)) {
console.log(`Mempool ID: ${id}`)
for (const [erc7562Rule, override] of Object.entries(config) as [ERC7562Rule, BaseAltMempoolRule][]) {
console.log(` Rule: ${erc7562Rule}, Enabled: ${override.enabled}`)
if (violation.rule === erc7562Rule) {
console.error('MATCHES THE VIOLATION')
}
}
}
}
return mempoolIds
}
}
12 changes: 7 additions & 5 deletions packages/bundler/src/modules/initServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
AA_ENTRY_POINT,
AA_NONCE_MANAGER,
AA_SENDER_CREATOR,
AA_STAKE_MANAGER,
AA_STAKE_MANAGER, AltMempoolConfig,
IValidationManager,
ValidationManager,
ValidationManagerRIP7560
Expand All @@ -31,25 +31,27 @@ import { ERC7562Parser } from '@account-abstraction/validation-manager/dist/src/
* initialize server modules.
* returns the ExecutionManager and EventsManager (for handling events, to update reputation)
* @param config
* @param altMempoolConfig
* @param signer
*/
export function initServer (config: BundlerConfig, signer: Signer): [ExecutionManager, EventsManager, ReputationManager, MempoolManager, PreVerificationGasCalculator] {
export function initServer (config: BundlerConfig, altMempoolConfig: AltMempoolConfig, signer: Signer): [ExecutionManager, EventsManager, ReputationManager, MempoolManager, PreVerificationGasCalculator] {
const entryPoint = IEntryPoint__factory.connect(config.entryPoint, signer)
const reputationManager = new ReputationManager(getNetworkProvider(config.network), BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
const mempoolManager = new MempoolManager(reputationManager)
const mempoolManager = new MempoolManager(reputationManager, altMempoolConfig)
const eventsManager = new EventsManager(entryPoint, mempoolManager, reputationManager)
const mergedPvgcConfig = Object.assign({}, ChainConfigs[config.chainId] ?? {}, config)
const preVerificationGasCalculator = new PreVerificationGasCalculator(mergedPvgcConfig)
let validationManager: IValidationManager
let bundleManager: IBundleManager
if (!config.rip7560) {
const erc7562Parser = new ERC7562Parser(entryPoint.address, config.senderCreator)
const bailOnViolation = Object.keys(altMempoolConfig).length === 0
const erc7562Parser = new ERC7562Parser(bailOnViolation, entryPoint.address, config.senderCreator)
const tracerProvider = config.tracerRpcUrl == null ? undefined : getNetworkProvider(config.tracerRpcUrl)
validationManager = new ValidationManager(entryPoint, config.unsafe, preVerificationGasCalculator, erc7562Parser, tracerProvider)
bundleManager = new BundleManager(entryPoint, entryPoint.provider as JsonRpcProvider, signer, eventsManager, mempoolManager, validationManager, reputationManager,
config.beneficiary, parseEther(config.minBalance), config.maxBundleGas, config.conditionalRpc)
} else {
const erc7562Parser = new ERC7562Parser(AA_ENTRY_POINT, AA_SENDER_CREATOR, AA_NONCE_MANAGER)
const erc7562Parser = new ERC7562Parser(true, AA_ENTRY_POINT, AA_SENDER_CREATOR, AA_NONCE_MANAGER)
const stakeManager = IRip7560StakeManager__factory.connect(AA_STAKE_MANAGER, signer)
validationManager = new ValidationManagerRIP7560(stakeManager, entryPoint.provider as JsonRpcProvider, erc7562Parser, config.unsafe)
bundleManager = new BundleManagerRIP7560(entryPoint.provider as JsonRpcProvider, signer, eventsManager, mempoolManager, validationManager, reputationManager,
Expand Down
7 changes: 5 additions & 2 deletions packages/bundler/src/runBundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { MethodHandlerERC4337 } from './MethodHandlerERC4337'
import { initServer } from './modules/initServer'
import { DebugMethodHandler } from './DebugMethodHandler'
import { supportsDebugTraceCall, supportsNativeTracer } from '@account-abstraction/validation-manager'
import { resolveConfiguration } from './Config'
import { resolveAltMempoolConfig, resolveConfiguration } from './Config'
import { bundlerConfigDefault } from './BundlerConfig'
import { parseEther } from 'ethers/lib/utils'
import { MethodHandlerRIP7560 } from './MethodHandlerRIP7560'
Expand All @@ -32,6 +32,7 @@ ethers.BigNumber.prototype[inspectCustomSymbol] = function () {
}

const CONFIG_FILE_NAME = 'workdir/bundler.config.json'
const ALT_MEMPOOL_FILE_NAME = 'workdir/alt.mempool.config.json'

export let showStackTraces = false

Expand Down Expand Up @@ -89,6 +90,7 @@ export async function runBundler (argv: string[], overrideExit = true): Promise<
.option('--rip7560', 'Use this bundler as an RIP-7560 node')
.option('--rip7560Mode <string>', 'PUSH mode sends bundles to node at an interval, PULL mode waits for node to query bundle')
.option('--gethDevMode', 'In PULL mode send 1 wei transaction to trigger block creation')
.option('--altMempoolConfig <string>', 'path to Alt-Mempool config files (overrides to ERC-7562 rules)', ALT_MEMPOOL_FILE_NAME)

const programOpts = program.parse(argv).opts()
showStackTraces = programOpts.showStackTraces
Expand All @@ -107,6 +109,7 @@ export async function runBundler (argv: string[], overrideExit = true): Promise<
process.exit(1)
}
const { config, provider, wallet } = await resolveConfiguration(programOpts)
const altMempoolConfig = await resolveAltMempoolConfig(programOpts)

const {
// name: chainName,
Expand Down Expand Up @@ -182,7 +185,7 @@ export async function runBundler (argv: string[], overrideExit = true): Promise<
reputationManager,
mempoolManager,
preVerificationGasCalculator
] = initServer(execManagerConfig, wallet)
] = initServer(execManagerConfig, altMempoolConfig, wallet)
const methodHandler = new MethodHandlerERC4337(
execManager,
provider,
Expand Down
8 changes: 4 additions & 4 deletions packages/bundler/test/BundlerManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ describe('#BundlerManager', () => {
}

const repMgr = new ReputationManager(provider, BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
const mempoolMgr = new MempoolManager(repMgr)
const mempoolMgr = new MempoolManager(repMgr, {})
const preVerificationGasCalculator = new PreVerificationGasCalculator(MainnetConfig)
const erc7562Parser = new ERC7562Parser(entryPoint.address, config.senderCreator)
const erc7562Parser = new ERC7562Parser(true, entryPoint.address, config.senderCreator)
const validMgr = new ValidationManager(entryPoint, config.unsafe, preVerificationGasCalculator, erc7562Parser)
const evMgr = new EventsManager(entryPoint, mempoolMgr, repMgr)
bm = new BundleManager(entryPoint, entryPoint.provider as JsonRpcProvider, entryPoint.signer, evMgr, mempoolMgr, validMgr, repMgr, config.beneficiary, parseEther(config.minBalance), config.maxBundleGas, config.conditionalRpc)
Expand Down Expand Up @@ -121,9 +121,9 @@ describe('#BundlerManager', () => {
eip7702Support: false
}
const repMgr = new ReputationManager(provider, BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
const mempoolMgr = new MempoolManager(repMgr)
const mempoolMgr = new MempoolManager(repMgr, {})
const preVerificationGasCalculator = new PreVerificationGasCalculator(MainnetConfig)
const erc7562Parser = new ERC7562Parser(entryPoint.address, config.senderCreator)
const erc7562Parser = new ERC7562Parser(true, entryPoint.address, config.senderCreator)
const validMgr = new ValidationManager(_entryPoint, config.unsafe, preVerificationGasCalculator, erc7562Parser)
const evMgr = new EventsManager(_entryPoint, mempoolMgr, repMgr)
bundleMgr = new BundleManager(_entryPoint, _entryPoint.provider as JsonRpcProvider, _entryPoint.signer, evMgr, mempoolMgr, validMgr, repMgr, config.beneficiary, parseEther(config.minBalance), config.maxBundleGas, false)
Expand Down
4 changes: 2 additions & 2 deletions packages/bundler/test/BundlerServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ describe('BundleServer', function () {
}

const repMgr = new ReputationManager(provider, BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
const mempoolMgr = new MempoolManager(repMgr)
const mempoolMgr = new MempoolManager(repMgr, {})
const preVerificationGasCalculator = new PreVerificationGasCalculator(MainnetConfig)
const erc7562Parser = new ERC7562Parser(entryPoint.address, config.senderCreator)
const erc7562Parser = new ERC7562Parser(true, entryPoint.address, config.senderCreator)
const validMgr = new ValidationManager(entryPoint, config.unsafe, preVerificationGasCalculator, erc7562Parser)
const evMgr = new EventsManager(entryPoint, mempoolMgr, repMgr)
const bundleMgr = new BundleManager(entryPoint, entryPoint.provider as JsonRpcProvider, entryPoint.signer, evMgr, mempoolMgr, validMgr, repMgr, config.beneficiary, parseEther(config.minBalance), config.maxBundleGas, false)
Expand Down
4 changes: 2 additions & 2 deletions packages/bundler/test/DebugMethodHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ describe('#DebugMethodHandler', () => {
}

const repMgr = new ReputationManager(provider, BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
const mempoolMgr = new MempoolManager(repMgr)
const mempoolMgr = new MempoolManager(repMgr, {})
const preVerificationGasCalculator = new PreVerificationGasCalculator(MainnetConfig)
const erc7562Parser = new ERC7562Parser(entryPoint.address, config.senderCreator)
const erc7562Parser = new ERC7562Parser(true, entryPoint.address, config.senderCreator)
const validMgr = new ValidationManager(entryPoint, config.unsafe, preVerificationGasCalculator, erc7562Parser)
const eventsManager = new EventsManager(entryPoint, mempoolMgr, repMgr)
const bundleMgr = new BundleManager(entryPoint, entryPoint.provider as JsonRpcProvider, entryPoint.signer, eventsManager, mempoolMgr, validMgr, repMgr,
Expand Down
2 changes: 1 addition & 1 deletion packages/bundler/test/RIP7560Mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe.skip('RIP7560Mode', function () {
// fund deployment of the EntryPoint contract
await signer.sendTransaction({ to: await wallet.getAddress(), value: parseEther('1') })

const [execManager] = initServer(config, signer)
const [execManager] = initServer(config, {}, signer)

// spy on the underlying ExecutionManager provider 'send' function
// @ts-ignore
Expand Down
4 changes: 2 additions & 2 deletions packages/bundler/test/UserOpMethodHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ describe('UserOpMethodHandler', function () {
}

const repMgr = new ReputationManager(provider, BundlerReputationParams, parseEther(config.minStake), config.minUnstakeDelay)
mempoolMgr = new MempoolManager(repMgr)
mempoolMgr = new MempoolManager(repMgr, {})
const preVerificationGasCalculator = new PreVerificationGasCalculator(MainnetConfig)
const erc7562Parser = new ERC7562Parser(entryPoint.address, config.senderCreator)
const erc7562Parser = new ERC7562Parser(true, entryPoint.address, config.senderCreator)
const validMgr = new ValidationManager(entryPoint, config.unsafe, preVerificationGasCalculator, erc7562Parser)
const evMgr = new EventsManager(entryPoint, mempoolMgr, repMgr)
const bundleMgr = new BundleManager(entryPoint, entryPoint.provider as JsonRpcProvider, entryPoint.signer, evMgr, mempoolMgr, validMgr, repMgr, config.beneficiary, parseEther(config.minBalance), config.maxBundleGas, false)
Expand Down
2 changes: 1 addition & 1 deletion packages/bundler/test/ValidateManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ describe('#ValidationManager', () => {
const preVerificationGasCalculator = new PreVerificationGasCalculator(MainnetConfig)

const senderCreator = '0xefc2c1444ebcc4db75e7613d20c6a62ff67a167c'
const erc7562Parser = new ERC7562Parser(entryPoint.address, senderCreator)
const erc7562Parser = new ERC7562Parser(true, entryPoint.address, senderCreator)
vm = new ValidationManager(entryPoint, unsafe, preVerificationGasCalculator, erc7562Parser)

if (!await supportsDebugTraceCall(ethers.provider, false)) {
Expand Down
6 changes: 3 additions & 3 deletions packages/validation-manager/src/ERC7562Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,15 @@ export class ERC7562Parser {
private contractAddresses: string[] = []
private storageMap: StorageMap = {}

private bailOnViolation: boolean = false

constructor (
public bailOnViolation: boolean,
readonly entryPointAddress: string,
readonly senderCreatorAddress: string,
readonly nonceManagerAddress?: string
) {}

/**
* TODO: remove - currently only used by 7560
* Analyzes the tracing results for the given UserOperation.
* Throws an exception in case canonical ERC-7562 rule violation was detected.
*
Expand All @@ -284,7 +284,7 @@ export class ERC7562Parser {
/**
* Analyzes the tracing results for the given UserOperation.
*
* Unlike {@link requireCompliance}, does not throw an exception in case a rule violation was detected.
* If {@link bailOnViolation} is true throws an exception once the first rule violation is detected.
*
* @returns {@link ERC7562ValidationResults} containing addresses and storage slots accessed by the UserOperation,
* @returns an array of ERC-7562 rules that were violated by the UserOperation.
Expand Down
3 changes: 3 additions & 0 deletions packages/validation-manager/src/IValidationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
StorageMap
} from '@account-abstraction/utils'
import { PreVerificationGasCalculatorConfig } from '@account-abstraction/sdk'
import { ERC7562Violation } from './ERC7562Violation'

/**
* result from successful validation
Expand All @@ -28,6 +29,7 @@ export interface ValidationResult {
}

export interface ValidateUserOpResult extends ValidationResult {
ruleViolations: ERC7562Violation[]
referencedContracts: ReferencedCodeHashes
storageMap: StorageMap
}
Expand All @@ -49,6 +51,7 @@ export const EmptyValidateUserOpResult: ValidateUserOpResult = {
addresses: [],
hash: ''
},
ruleViolations: [],
storageMap: {}
}

Expand Down
Loading

0 comments on commit 54170ff

Please sign in to comment.