From e9df4ca103de8bc5b4c087e5b31ae0219c3f84fd Mon Sep 17 00:00:00 2001 From: Utkir S Date: Tue, 16 Jan 2024 14:47:17 +0500 Subject: [PATCH] feat: serve one chain only (#140) --- .gitignore | 1 + README.md | 97 +++--- config.json.default | 20 +- packages/api/src/app.ts | 40 +-- packages/api/src/modules/redirect.ts | 7 +- packages/cli/package.json | 3 +- packages/cli/src/cmds/node/handler.ts | 12 +- packages/cli/src/cmds/standalone/handler.ts | 45 ++- packages/cli/src/util/git.ts | 88 +++++ packages/cli/src/util/version.ts | 5 +- packages/cli/src/util/writeGitData.ts | 6 + packages/executor/src/config.ts | 307 ++++++------------ packages/executor/src/executor.ts | 59 ++-- packages/executor/src/interfaces.ts | 16 +- packages/executor/src/modules/eth.ts | 11 +- packages/executor/src/modules/skandha.ts | 10 +- packages/executor/src/modules/web3.ts | 6 +- .../services/BundlingService/relayers/base.ts | 11 +- .../BundlingService/relayers/classic.ts | 5 +- .../BundlingService/relayers/flashbots.ts | 6 +- .../src/services/BundlingService/service.ts | 9 +- packages/executor/src/services/P2PService.ts | 12 +- .../src/services/UserOpValidation/service.ts | 9 +- .../UserOpValidation/validators/safe.ts | 3 +- packages/node/src/index.ts | 78 +++-- packages/node/src/network/network.ts | 49 ++- .../src/network/processor/gossipHandlers.ts | 13 +- .../src/network/reqresp/handlers/index.ts | 8 +- .../reqresp/handlers/pooledUserOpHashes.ts | 35 +- .../reqresp/handlers/pooledUserOpsByHash.ts | 18 +- .../src/network/reqresp/handlers/status.ts | 11 +- .../src/network/reqresp/pooledUserOpHashes.ts | 4 +- .../network/reqresp/pooledUserOpsByHash.ts | 4 +- .../validation/userOpsWithEntryPoint.ts | 7 +- packages/params/src/networks/dev.ts | 1 - packages/params/src/networks/goerli.ts | 1 - packages/params/src/networks/mainnet.ts | 1 - packages/params/src/networks/matic.ts | 1 - packages/params/src/networks/mumbai.ts | 1 - packages/params/src/networks/sepolia.ts | 1 - packages/params/src/networks/xdai.ts | 1 - packages/params/src/types/index.ts | 4 - packages/params/src/utils/userOp.ts | 2 +- packages/types/src/executor/index.ts | 6 + packages/types/src/index.ts | 1 - 45 files changed, 438 insertions(+), 597 deletions(-) create mode 100644 packages/cli/src/util/git.ts create mode 100644 packages/cli/src/util/writeGitData.ts diff --git a/.gitignore b/.gitignore index 1a1b480b..eeeb2938 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,4 @@ scripts/ packages/*/lib skandha db +packages/cli/.git-data.json diff --git a/README.md b/README.md index 82cf967d..dcf7a841 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,7 @@ Or follow the steps below: 4. edit `config.json` 5. (optional) run local geth-node from `test/geth-dev` 6. run `./skandha` -7. Skandha will run for all chains available in `config.json` -8. Networks will be available at `http://localhost:14337/{chainId}/` (e.g. for dev `http://localhost:14337/1337/`) +7. The bundler will be available on `http://localhost:14337/rpc/` ## 🐳 How to run (a Docker image) @@ -68,16 +67,12 @@ Or follow the steps below: #### Simplest config.json ```yaml { - "networks": { - "mumbai": { - "entryPoints": [ - "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - ], - "relayer": "0x{RELAYER-PRIVATE-KEY}", - "beneficiary": "0x{BENEFICIARY-ADDRESS}", - "rpcEndpoint": "https://polygon-mumbai.blockpi.network/v1/rpc/public" - } - } + "entryPoints": [ + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + ], + "relayer": "0x{RELAYER-PRIVATE-KEY}", + "beneficiary": "0x{BENEFICIARY-ADDRESS}", + "rpcEndpoint": "https://polygon-mumbai.blockpi.network/v1/rpc/public" } ``` @@ -85,47 +80,43 @@ Or follow the steps below: ```yaml { - "networks": { - "dev": { # network Id (check packages/params/src/networks/.ts) - "entryPoints": [ # supported entry points - "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - ], - "relayers": [ - "0x0101010101010101010101010101010101010101010101010101010101010101", - "test test test test test test test test test test test junk" - ], # relayers private keys, can access from here or via environment variables (SKANDHA_MUMBAI_RELAYERS | SKANDHA_DEV_RELAYERS | etc.) - "beneficiary": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", # optional, fee collector, avaiable via env var (SKANDHA_MUMBAI_BENEFICIARY | etc) - if not set, relayer will be used - "rpcEndpoint": "http://localhost:8545", # rpc provider, also available via env variable (SKANDHA_MUMBAI_RPC | etc) - "minInclusionDenominator": 10, # optional, see EIP-4337 - "throttlingSlack": 10, # optional, see EIP-4337 - "banSlack": 50 # optional, see EIP-4337 - "minStake": 10000000000, # optional, min stake of an entity (in wei) - "minUnstakeDelay": 0, # optional, min unstake delay of an entity - "minSignerBalance": 1, # optional, default is 0.1 ETH. If the relayer's balance drops lower than this, it will be selected as a fee collector - "multicall": "0xcA11bde05977b3631167028862bE2a173976CA11", # optional, multicall3 contract (see https://github.com/mds1/multicall#multicall3-contract-addresses) - "estimationStaticBuffer": 21000, # optional,adds certain amount of gas to callGasLimit on estimation - "validationGasLimit": 10e6, # optional,gas limit during simulateHandleOps and simulateValidation calls - "receiptLookupRange": 1024, # optional,limits the block range of getUserOperationByHash and getUserOperationReceipt - "etherscanApiKey": "", # optional,etherscan api is used to fetch gas prices - "conditionalTransactions": false, # optional,enable conditional transactions - "rpcEndpointSubmit": "", # optional,rpc endpoint that is used only during submission of a bundle - "gasPriceMarkup": 0, # optional,adds % markup on reported gas price via skandha_getGasPrice, 10000 = 100.00%, 500 = 5% - "enforceGasPrice": false, # optional,do not bundle userops with low gas prices - "enforceGasPriceThreshold": 1000, # optional,gas price threshold in bps. If set to 500, userops' gas price is allowed to be 5% lower than the network's gas price - "eip2930": false, # optional, enables eip-2930 - "useropsTTL": 300, # optional, Userops time to live (in seconds) - "whitelistedEntities": { # optional, Entities that bypass stake and opcode validation (array of addresses) - "factory": [], - "paymaster": [], - "account": [] - }, - "bundleGasLimitMarkup": 25000, # optional, adds some amount of additional gas to a bundle tx - "relayingMode": "classic"; # optional, allows to switch to Flashbots Builder api if set to "flashbots", see packages/executor/src/interfaces.ts for more - "bundleInterval": 10000, # bundle creation interval - "bundleSize": 4, # optional, max size of a bundle, 4 userops by default - "pvgMarkup": 0 # optional, adds some gas on top of estimated PVG - } - } + "entryPoints": [ # supported entry points + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + ], + "relayers": [ + "0x0101010101010101010101010101010101010101010101010101010101010101", + "test test test test test test test test test test test junk" + ], # relayers private keys, can access from here or via environment variables (SKANDHA_MUMBAI_RELAYERS | SKANDHA_DEV_RELAYERS | etc.) + "beneficiary": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", # optional, fee collector, avaiable via env var (SKANDHA_MUMBAI_BENEFICIARY | etc) - if not set, relayer will be used + "rpcEndpoint": "http://localhost:8545", # rpc provider, also available via env variable (SKANDHA_MUMBAI_RPC | etc) + "minInclusionDenominator": 10, # optional, see EIP-4337 + "throttlingSlack": 10, # optional, see EIP-4337 + "banSlack": 50 # optional, see EIP-4337 + "minStake": 10000000000, # optional, min stake of an entity (in wei) + "minUnstakeDelay": 0, # optional, min unstake delay of an entity + "minSignerBalance": 1, # optional, default is 0.1 ETH. If the relayer's balance drops lower than this, it will be selected as a fee collector + "multicall": "0xcA11bde05977b3631167028862bE2a173976CA11", # optional, multicall3 contract (see https://github.com/mds1/multicall#multicall3-contract-addresses) + "estimationStaticBuffer": 21000, # optional,adds certain amount of gas to callGasLimit on estimation + "validationGasLimit": 10e6, # optional,gas limit during simulateHandleOps and simulateValidation calls + "receiptLookupRange": 1024, # optional,limits the block range of getUserOperationByHash and getUserOperationReceipt + "etherscanApiKey": "", # optional,etherscan api is used to fetch gas prices + "conditionalTransactions": false, # optional,enable conditional transactions + "rpcEndpointSubmit": "", # optional,rpc endpoint that is used only during submission of a bundle + "gasPriceMarkup": 0, # optional,adds % markup on reported gas price via skandha_getGasPrice, 10000 = 100.00%, 500 = 5% + "enforceGasPrice": false, # optional,do not bundle userops with low gas prices + "enforceGasPriceThreshold": 1000, # optional,gas price threshold in bps. If set to 500, userops' gas price is allowed to be 5% lower than the network's gas price + "eip2930": false, # optional, enables eip-2930 + "useropsTTL": 300, # optional, Userops time to live (in seconds) + "whitelistedEntities": { # optional, Entities that bypass stake and opcode validation (array of addresses) + "factory": [], + "paymaster": [], + "account": [] + }, + "bundleGasLimitMarkup": 25000, # optional, adds some amount of additional gas to a bundle tx + "relayingMode": "classic"; # optional, allows to switch to Flashbots Builder api if set to "flashbots", see packages/executor/src/interfaces.ts for more + "bundleInterval": 10000, # bundle creation interval + "bundleSize": 4, # optional, max size of a bundle, 4 userops by default + "pvgMarkup": 0 # optional, adds some gas on top of estimated PVG } ``` ## 💬 Contact diff --git a/config.json.default b/config.json.default index e16c2790..6c71f4fd 100644 --- a/config.json.default +++ b/config.json.default @@ -1,14 +1,10 @@ { - "networks": { - "dev": { - "entryPoints": [ - "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - ], - "relayers": [ - "test test test test test test test test test test test junk", - "0x0101010101010101010101010101010101010101010101010101010101010101" - ], - "rpcEndpoint": "http://localhost:8545" - } - } + "entryPoints": [ + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + ], + "relayers": [ + "test test test test test test test test test test test junk", + "0x0101010101010101010101010101010101010101010101010101010101010101" + ], + "rpcEndpoint": "http://localhost:8545" } diff --git a/packages/api/src/app.ts b/packages/api/src/app.ts index 46426468..1042ae1c 100644 --- a/packages/api/src/app.ts +++ b/packages/api/src/app.ts @@ -1,12 +1,8 @@ -import { NetworkName } from "types/lib"; -import { IDbController } from "types/lib"; import { Executor } from "executor/lib/executor"; -import { Executors } from "executor/lib/interfaces"; import { Config } from "executor/lib/config"; import RpcError from "types/lib/api/errors/rpc-error"; import * as RpcErrorCodes from "types/lib/api/errors/rpc-error-codes"; import { FastifyInstance, RouteHandler } from "fastify"; -import logger from "./logger"; import { BundlerRPCMethods, CustomRPCMethods, @@ -18,16 +14,13 @@ import { deepHexlify } from "./utils"; import { SkandhaAPI } from "./modules/skandha"; export interface RpcHandlerOptions { - network: NetworkName; - db: IDbController; config: Config; } export interface EtherspotBundlerOptions { server: FastifyInstance; config: Config; - db: IDbController; - executors: Executors; + executor: Executor; testingMode: boolean; redirectRpc: boolean; } @@ -43,8 +36,7 @@ export interface RelayerAPI { export class ApiApp { private server: FastifyInstance; private config: Config; - private db: IDbController; - private executors: Executors; + private executor: Executor; private testingMode = false; private redirectRpc = false; @@ -52,36 +44,18 @@ export class ApiApp { constructor(options: EtherspotBundlerOptions) { this.server = options.server; this.config = options.config; - this.db = options.db; this.testingMode = options.testingMode; this.redirectRpc = options.redirectRpc; - this.executors = options.executors; - this.setupRoutes(); + this.executor = options.executor; + this.server.post("/rpc/", this.setupRoutes()); } - private setupRoutes(): void { - if (this.testingMode) { - this.server.post("/rpc/", this.setupRouteFor(1337)); - logger.info("Setup route for dev: /rpc/"); - return; - } - - const networkNames = this.config.supportedNetworks; - for (const [network, chainId] of Object.entries(networkNames)) { - this.server.post(`/${chainId}`, this.setupRouteFor(chainId)); - logger.info(`Setup route for ${network}: /${chainId}/`); - } - } - - private setupRouteFor(chainId: number): RouteHandler { - const executor = this.executors.get(chainId); - if (!executor) { - throw new Error("Couldn't find executor"); - } + private setupRoutes(): RouteHandler { + const { executor } = this; const ethApi = new EthAPI(executor.eth); const debugApi = new DebugAPI(executor.debug); const web3Api = new Web3API(executor.web3); - const redirectApi = new RedirectAPI(executor.networkName, this.config); + const redirectApi = new RedirectAPI(this.config); const skandhaApi = new SkandhaAPI(executor.eth, executor.skandha); const handleRpc = async (ip: string, request: any): Promise => { diff --git a/packages/api/src/modules/redirect.ts b/packages/api/src/modules/redirect.ts index c3f9dc62..fe687dff 100644 --- a/packages/api/src/modules/redirect.ts +++ b/packages/api/src/modules/redirect.ts @@ -1,14 +1,11 @@ import { providers } from "ethers"; import { Config } from "executor/lib/config"; -import { NetworkName } from "types/lib"; export class RedirectAPI { private provider: providers.JsonRpcProvider; - constructor(private network: NetworkName, private config: Config) { - this.provider = this.config.getNetworkProvider( - this.network - ) as providers.JsonRpcProvider; + constructor(private config: Config) { + this.provider = this.config.getNetworkProvider(); } async redirect(method: string, params: any[]): Promise { diff --git a/packages/cli/package.json b/packages/cli/package.json index b0d871de..34764f1d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -19,7 +19,8 @@ }, "scripts": { "clean": "rm -rf lib && rm -f *.tsbuildinfo", - "build": "tsc -p tsconfig.build.json", + "build": "tsc -p tsconfig.build.json && yarn write-git-data", + "write-git-data": "node lib/util/writeGitData.js", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", diff --git a/packages/cli/src/cmds/node/handler.ts b/packages/cli/src/cmds/node/handler.ts index cc7e6418..56475ba9 100644 --- a/packages/cli/src/cmds/node/handler.ts +++ b/packages/cli/src/cmds/node/handler.ts @@ -1,7 +1,6 @@ -/* eslint-disable no-console */ import { Config } from "executor/lib/config"; import { Namespace, getNamespaceByValue, RocksDbController } from "db/lib"; -import { ConfigOptions } from "executor/lib/interfaces"; +import { NetworkConfig } from "executor/lib/interfaces"; import { BundlerNode, IBundlerNodeOptions, defaultOptions } from "node/lib"; import { initNetworkOptions } from "node/lib"; import logger from "api/lib/logger"; @@ -9,6 +8,7 @@ import { ExecutorOptions, ApiOptions, P2POptions } from "types/lib/options"; import { MetricsOptions } from "types/lib/options/metrics"; import { IGlobalArgs } from "../../options"; import { mkdir, readFile } from "../../util"; +import { getVersionData } from "../../util/version"; import { initPeerIdAndEnr } from "./initPeerIdAndEnr"; export async function nodeHandler(args: IGlobalArgs): Promise { @@ -28,9 +28,9 @@ export async function nodeHandler(args: IGlobalArgs): Promise { let config: Config; try { - const configOptions = readFile(params.configFile) as ConfigOptions; + const networkConfig = readFile(params.configFile) as NetworkConfig; config = await Config.init({ - networks: configOptions.networks, + config: networkConfig, testingMode: params.testingMode, unsafeMode: params.unsafeMode, redirectRpc: params.redirectRpc, @@ -42,7 +42,7 @@ export async function nodeHandler(args: IGlobalArgs): Promise { } logger.info("Config file not found. Proceeding with env vars..."); config = await Config.init({ - networks: {}, + config: null, testingMode: params.testingMode, unsafeMode: params.unsafeMode, redirectRpc: params.redirectRpc, @@ -68,6 +68,7 @@ export async function nodeHandler(args: IGlobalArgs): Promise { network: initNetworkOptions(enr, params.p2p, params.dataDir), }; + const version = getVersionData(); const node = await BundlerNode.init({ nodeOptions: options, relayersConfig: config, @@ -77,6 +78,7 @@ export async function nodeHandler(args: IGlobalArgs): Promise { bundlingMode: params.executor.bundlingMode, peerId, metricsOptions: params.metrics, + version, }); await node.start(); diff --git a/packages/cli/src/cmds/standalone/handler.ts b/packages/cli/src/cmds/standalone/handler.ts index 6b0933ab..03618d6d 100644 --- a/packages/cli/src/cmds/standalone/handler.ts +++ b/packages/cli/src/cmds/standalone/handler.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import { Server } from "api/lib/server"; import { ApiApp } from "api/lib/app"; import { Config } from "executor/lib/config"; @@ -8,14 +7,14 @@ import { RocksDbController, LocalDbController, } from "db/lib"; -import { ConfigOptions } from "executor/lib/interfaces"; +import { NetworkConfig } from "executor/lib/interfaces"; import { IDbController } from "types/lib"; -import { Executors } from "executor/lib/interfaces"; import { Executor } from "executor/lib/executor"; import logger from "api/lib/logger"; import { createMetrics, getHttpMetricsServer } from "monitoring/lib"; import { mkdir, readFile } from "../../util"; import { IStandaloneGlobalArgs } from "../../options"; +import { getVersionData } from "../../util/version"; export async function bundlerHandler( args: IStandaloneGlobalArgs @@ -36,9 +35,9 @@ export async function bundlerHandler( let config: Config; try { - const configOptions = readFile(configFile) as ConfigOptions; + const networkConfig = readFile(configFile) as NetworkConfig; config = await Config.init({ - networks: configOptions.networks, + config: networkConfig, testingMode, unsafeMode, redirectRpc, @@ -50,7 +49,7 @@ export async function bundlerHandler( } logger.debug("Config file not found. Proceeding with env vars..."); config = await Config.init({ - networks: {}, + config: null, testingMode, unsafeMode, redirectRpc, @@ -88,33 +87,30 @@ export async function bundlerHandler( ? createMetrics({ p2p: false }, logger) : null; - const executors: Executors = new Map(); + const version = getVersionData(); + let executor: Executor; if (config.testingMode) { metrics?.addChain(1337); - const executor = new Executor({ - network: "dev", + executor = new Executor({ chainId: 1337, db: db, config: config, logger: logger, bundlingMode: args["executor.bundlingMode"], metrics: metrics?.chains[1337] || null, + version, }); - executors.set(1337, executor); } else { - for (const [network, chainId] of Object.entries(config.supportedNetworks)) { - metrics?.addChain(chainId); - const executor = new Executor({ - network, - chainId, - db: db, - config: config, - logger: logger, - bundlingMode: args["executor.bundlingMode"], - metrics: metrics?.chains[chainId] || null, - }); - executors.set(chainId, executor); - } + metrics?.addChain(config.chainId); + executor = new Executor({ + chainId: config.chainId, + db: db, + config: config, + logger: logger, + bundlingMode: args["executor.bundlingMode"], + metrics: metrics?.chains[config.chainId] || null, + version, + }); } args["metrics.enable"] @@ -129,10 +125,9 @@ export async function bundlerHandler( new ApiApp({ server: server.application, config: config, - db, testingMode, redirectRpc, - executors, + executor, }); await server.listen(); diff --git a/packages/cli/src/util/git.ts b/packages/cli/src/util/git.ts new file mode 100644 index 00000000..0ce1cf1a --- /dev/null +++ b/packages/cli/src/util/git.ts @@ -0,0 +1,88 @@ +import { execSync } from "node:child_process"; +import path from "node:path"; +import fs from "node:fs"; +import { fileURLToPath } from "node:url"; + +/** Git data type used to construct version information string and persistence. */ +export type GitData = { + branch: string; + commit: string; +}; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +export const gitDataPath = path.resolve(__dirname, "../../.git-data.json"); + +/** Writes a persistent git data file. */ +export function writeGitDataFile(gitData: GitData): void { + fs.writeFileSync(gitDataPath, JSON.stringify(gitData, null, 2)); +} + +/** Reads the persistent git data file. */ +export function readGitDataFile(): GitData { + return JSON.parse(fs.readFileSync(gitDataPath, "utf8")) as GitData; +} + +export function readAndGetGitData(): GitData { + try { + // Gets git data containing current branch and commit info from persistent file. + let persistedGitData: Partial; + try { + persistedGitData = readGitDataFile(); + } catch (e) { + persistedGitData = {}; + } + + const currentGitData = getGitData(); + + return { + // If the CLI is run from source, prioritze current git data + // over `.git-data.json` file, which might be stale here. + branch: + currentGitData.branch && currentGitData.branch.length > 0 + ? currentGitData.branch + : persistedGitData.branch ?? "", + commit: + currentGitData.commit && currentGitData.commit.length > 0 + ? currentGitData.commit + : persistedGitData.commit ?? "", + }; + } catch (e) { + return { + branch: "", + commit: "", + }; + } +} + +/** Gets git data containing current branch and commit info from CLI. */ +export function getGitData(): GitData { + return { + branch: getBranch(), + commit: getCommit(), + }; +} + +/** Tries to get branch from git CLI. */ +export function getBranch(): string { + try { + return shellSilent("git rev-parse --abbrev-ref HEAD"); + } catch (e) { + return ""; + } +} + +/** Tries to get commit from git from git CLI. */ +export function getCommit(): string { + try { + return shellSilent("git rev-parse --verify HEAD"); + } catch (e) { + return ""; + } +} + +/** Silent shell that won't pollute stdout, or stderr */ +function shellSilent(cmd: string): string { + return execSync(cmd, { stdio: ["ignore", "pipe", "ignore"] }) + .toString() + .trim(); +} diff --git a/packages/cli/src/util/version.ts b/packages/cli/src/util/version.ts index 12d76e54..8b95bf71 100644 --- a/packages/cli/src/util/version.ts +++ b/packages/cli/src/util/version.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import findUp from "find-up"; +import { readAndGetGitData } from "./git"; const __dirname = process.cwd(); @@ -17,7 +18,7 @@ export function getVersionData(): { commit: string; } { const parts: string[] = []; - const commit = ""; + const gitData = readAndGetGitData(); /** Returns local version from `lerna.json` or `package.json` as `"0.28.2"` */ const localVersion = readCliPackageJson() || readVersionFromLernaJson(); @@ -28,7 +29,7 @@ export function getVersionData(): { return { // Guard against empty parts array version: parts.length > 0 ? parts.join("/") : "unknown", - commit, + commit: gitData.commit, }; } diff --git a/packages/cli/src/util/writeGitData.ts b/packages/cli/src/util/writeGitData.ts new file mode 100644 index 00000000..1f5d706b --- /dev/null +++ b/packages/cli/src/util/writeGitData.ts @@ -0,0 +1,6 @@ +#!/usr/bin/env node + +import { getGitData, writeGitDataFile } from "./git.js"; + +// Script to write the git data file (json) used by the build procedures to persist git data. +writeGitDataFile(getGitData()); diff --git a/packages/executor/src/config.ts b/packages/executor/src/config.ts index fb7e568f..a6056792 100644 --- a/packages/executor/src/config.ts +++ b/packages/executor/src/config.ts @@ -1,59 +1,43 @@ // TODO: create a new package "config" instead of this file and refactor import { BigNumber, Wallet, providers, utils } from "ethers"; -import { NetworkName } from "types/lib"; import { IEntity, RelayingMode } from "types/lib/executor"; import { getAddress } from "ethers/lib/utils"; -import { - BundlerConfig, - ConfigOptions, - NetworkConfig, - Networks, -} from "./interfaces"; +import { BundlerConfig, ConfigOptions, NetworkConfig } from "./interfaces"; export class Config { - supportedNetworks: { - [networkName in NetworkName]: number; - }; - networks: Networks; testingMode: boolean; unsafeMode: boolean; redirectRpc: boolean; - - constructor(private config: ConfigOptions) { - this.testingMode = config.testingMode ?? false; - this.unsafeMode = config.unsafeMode ?? false; - this.redirectRpc = config.redirectRpc ?? false; - this.supportedNetworks = this.parseSupportedNetworks(); - this.networks = this.parseNetworkConfigs(); + config: NetworkConfig; + chainId: number; + + constructor(options: ConfigOptions) { + this.testingMode = options.testingMode ?? false; + this.unsafeMode = options.unsafeMode ?? false; + this.redirectRpc = options.redirectRpc ?? false; + this.config = this.getDefaultNetworkConfig(options.config); + this.chainId = 0; } static async init(configOptions: ConfigOptions): Promise { const config = new Config(configOptions); - await config.fetchChainIds(); + await config.fetchChainId(); return config; } - getNetworkProvider(network: string): providers.JsonRpcProvider | null { - const conf = this.networks[network]; - const endpoint = conf?.rpcEndpoint; - return endpoint ? new providers.JsonRpcProvider(endpoint) : null; + getNetworkProvider(): providers.JsonRpcProvider { + return new providers.JsonRpcProvider(this.config.rpcEndpoint); } - getRelayers(network: string): Wallet[] | providers.JsonRpcSigner[] | null { - const config = this.getNetworkConfig(network); - if (!config) return null; - - const provider = this.getNetworkProvider(network); - if (!provider) { - throw new Error("no provider"); - } + getRelayers(): Wallet[] | providers.JsonRpcSigner[] | null { + const provider = this.getNetworkProvider(); if (this.testingMode) { return [provider.getSigner()]; } const wallets = []; - for (const privKey of config.relayers) { + for (const privKey of this.config.relayers) { if (privKey.startsWith("0x")) { wallets.push(new Wallet(privKey, provider)); } else { @@ -63,259 +47,171 @@ export class Config { return wallets; } - getBeneficiary(network: string): string | null { - const config = this.getNetworkConfig(network); - if (!config) return null; - return config.beneficiary; - } - - getNetworkConfig(network: string): NetworkConfig | null { - const config = this.networks[network]; - if (!config) { - return null; - } - return config; + getBeneficiary(): string | null { + return this.config.beneficiary; } - async fetchChainIds(): Promise { - for (const networkName of Object.keys(this.supportedNetworks)) { - const provider = this.getNetworkProvider(networkName); - if (!provider) { - throw new Error(`No provider for ${networkName}`); - } - try { - const network = await provider.getNetwork(); - this.supportedNetworks[networkName] = network.chainId; - } catch (err) { - throw new Error(`Could not fetch chain id for ${networkName}`); - } - } + getNetworkConfig(): NetworkConfig { + return this.config; } - isNetworkSupported(network: NetworkName | number): boolean { - if (typeof network === "number") { - return Object.values(this.supportedNetworks).some( - (chainId) => chainId === network - ); + async fetchChainId(): Promise { + const provider = this.getNetworkProvider(); + try { + const network = await provider.getNetwork(); + this.chainId = network.chainId; + } catch (err) { + throw new Error("Could not fetch chain id"); } - return Object.keys(this.supportedNetworks).some((name) => name === network); } - isEntryPointSupported( - network: NetworkName | number, - entryPoint: string - ): boolean { - if (typeof network === "number") { - const networkName = this.getNetworkNameByChainId(network); - if (!networkName) return false; - return this.isEntryPointSupported(networkName, entryPoint); - } - const config = this.getNetworkConfig(network); - return !!config?.entryPoints.some( + isEntryPointSupported(entryPoint: string): boolean { + return !!this.config.entryPoints.some( (addr) => addr.toLowerCase() === entryPoint.toLowerCase() ); } - getNetworkNameByChainId(chainId: number): string | undefined { - return Object.keys(this.supportedNetworks).find( - (name) => this.supportedNetworks[name] === chainId - ); - } - - private parseSupportedNetworks(): { [name: string]: number } { - if (this.testingMode) { - return { dev: 1337 }; - } - const envNetworks = NETWORKS_ENV(); - let networkNames = envNetworks; - if (!networkNames) { - networkNames = Object.keys(this.config.networks); - } - return networkNames.reduce((networks, networkName) => { - networks[networkName] = 0; - return networks; - }, {} as { [name: string]: number }); - } - - private parseNetworkConfigs(): Networks { - const networks: Networks = {}; - for (const network of Object.keys(this.supportedNetworks)) { - const config = this.getDefaultNetworkConfig(network); - networks[network] = { - ...config, - name: network, - }; - } - return networks; - } - - private getDefaultNetworkConfig(network: string): NetworkConfig { - let conf = this.config.networks[network]; - if (!conf) { - conf = {} as NetworkConfig; - } - conf.entryPoints = fromEnvVar( - network, + private getDefaultNetworkConfig(config: NetworkConfig | null): NetworkConfig { + if (config == null) config = {} as NetworkConfig; + config.entryPoints = fromEnvVar( "ENTRYPOINTS", - conf.entryPoints, + config.entryPoints, true ) as string[]; - conf.relayer = fromEnvVar(network, "RELAYER", conf.relayer) as string; // deprecated - conf.relayers = fromEnvVar( - network, - "RELAYERS", - conf.relayers ?? [conf.relayer], // fallback to `relayer` if `relayers` not found - true - ) as string[]; + config.relayers = fromEnvVar("RELAYERS", config.relayers, true) as string[]; - conf.beneficiary = fromEnvVar( - network, + config.beneficiary = fromEnvVar( "BENEFICIARY", - conf.beneficiary || bundlerDefaultConfigs.beneficiary + config.beneficiary || bundlerDefaultConfigs.beneficiary ) as string; - conf.rpcEndpoint = fromEnvVar(network, "RPC", conf.rpcEndpoint) as string; - if (this.testingMode && !conf.rpcEndpoint) { - conf.rpcEndpoint = "http://localhost:8545"; // local geth + config.rpcEndpoint = fromEnvVar("RPC", config.rpcEndpoint) as string; + + if (this.testingMode && !config.rpcEndpoint) { + config.rpcEndpoint = "http://localhost:8545"; // local geth } - conf.etherscanApiKey = fromEnvVar( - network, + config.etherscanApiKey = fromEnvVar( "ETHERSCAN_API_KEY", - conf.etherscanApiKey || bundlerDefaultConfigs.etherscanApiKey + config.etherscanApiKey || bundlerDefaultConfigs.etherscanApiKey ) as string; - conf.receiptLookupRange = Number( + config.receiptLookupRange = Number( fromEnvVar( - network, "RECEIPT_LOOKUP_RANGE", - conf.receiptLookupRange || bundlerDefaultConfigs.receiptLookupRange + config.receiptLookupRange || bundlerDefaultConfigs.receiptLookupRange ) ); - conf.conditionalTransactions = Boolean( + config.conditionalTransactions = Boolean( fromEnvVar( - network, "CONDITIONAL_TRANSACTIONS", - conf.conditionalTransactions || + config.conditionalTransactions || bundlerDefaultConfigs.conditionalTransactions ) ); - conf.rpcEndpointSubmit = fromEnvVar( - network, + config.rpcEndpointSubmit = fromEnvVar( "RPC_SUBMIT", - conf.rpcEndpointSubmit || bundlerDefaultConfigs.rpcEndpointSubmit + config.rpcEndpointSubmit || bundlerDefaultConfigs.rpcEndpointSubmit ) as string; - conf.gasPriceMarkup = Number( + config.gasPriceMarkup = Number( fromEnvVar( - network, "GAS_PRICE_MARKUP", - conf.gasPriceMarkup || bundlerDefaultConfigs.gasPriceMarkup + config.gasPriceMarkup || bundlerDefaultConfigs.gasPriceMarkup ) ); - conf.enforceGasPrice = Boolean( + config.enforceGasPrice = Boolean( fromEnvVar( - network, "ENFORCE_GAS_PRICE", - conf.enforceGasPrice || bundlerDefaultConfigs.enforceGasPrice + config.enforceGasPrice || bundlerDefaultConfigs.enforceGasPrice ) ); - conf.enforceGasPriceThreshold = Number( + config.enforceGasPriceThreshold = Number( fromEnvVar( - network, "ENFORCE_GAS_PRICE_THRESHOLD", - conf.enforceGasPriceThreshold || + config.enforceGasPriceThreshold || bundlerDefaultConfigs.enforceGasPriceThreshold ) ); - conf.eip2930 = Boolean( - fromEnvVar( - network, - "EIP2930", - conf.eip2930 || bundlerDefaultConfigs.eip2930 - ) + config.eip2930 = Boolean( + fromEnvVar("EIP2930", config.eip2930 || bundlerDefaultConfigs.eip2930) ); - conf.useropsTTL = Number( + config.useropsTTL = Number( fromEnvVar( - network, "USEROPS_TTL", - conf.useropsTTL || bundlerDefaultConfigs.useropsTTL + config.useropsTTL || bundlerDefaultConfigs.useropsTTL ) ); - conf.estimationStaticBuffer = Number( + config.estimationStaticBuffer = Number( fromEnvVar( - network, "ESTIMATION_STATIC_BUFFER", - conf.estimationStaticBuffer || + config.estimationStaticBuffer || bundlerDefaultConfigs.estimationStaticBuffer ) ); - conf.minStake = BigNumber.from( - fromEnvVar( - network, - "MIN_STAKE", - conf.minStake ?? bundlerDefaultConfigs.minStake - ) + config.minStake = BigNumber.from( + fromEnvVar("MIN_STAKE", config.minStake ?? bundlerDefaultConfigs.minStake) ); - conf.minUnstakeDelay = Number( + config.minUnstakeDelay = Number( fromEnvVar( - network, "MIN_UNSTAKE_DELAY", - conf.minUnstakeDelay || bundlerDefaultConfigs.minUnstakeDelay + config.minUnstakeDelay || bundlerDefaultConfigs.minUnstakeDelay ) ); - conf.bundleGasLimitMarkup = Number( + config.bundleGasLimitMarkup = Number( fromEnvVar( - network, "BUNDLE_GAS_LIMIT_MARKUP", - conf.bundleGasLimitMarkup || bundlerDefaultConfigs.bundleGasLimitMarkup + config.bundleGasLimitMarkup || + bundlerDefaultConfigs.bundleGasLimitMarkup ) ); - conf.relayingMode = fromEnvVar( - network, + config.relayingMode = fromEnvVar( "RELAYING_MODE", - conf.relayingMode || bundlerDefaultConfigs.relayingMode + config.relayingMode || bundlerDefaultConfigs.relayingMode ) as RelayingMode; - conf.bundleInterval = Number( + config.bundleInterval = Number( fromEnvVar( - network, "BUNDLE_INTERVAL", - conf.bundleInterval || bundlerDefaultConfigs.bundleInterval + config.bundleInterval || bundlerDefaultConfigs.bundleInterval ) ); - conf.bundleSize = Number( + config.bundleSize = Number( fromEnvVar( - network, "BUNDLE_SIZE", - conf.bundleSize || bundlerDefaultConfigs.bundleSize + config.bundleSize || bundlerDefaultConfigs.bundleSize ) ); - conf.pvgMarkup = Number( + config.pvgMarkup = Number( fromEnvVar( - network, "PVG_MARKUP", - conf.pvgMarkup || bundlerDefaultConfigs.pvgMarkup + config.pvgMarkup || bundlerDefaultConfigs.pvgMarkup + ) + ); + + config.canonicalMempoolId = String( + fromEnvVar( + "CANONICAL_MEMPOOL", + config.canonicalMempoolId || bundlerDefaultConfigs.canonicalMempoolId ) ); // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (!conf.whitelistedEntities) { - conf.whitelistedEntities = bundlerDefaultConfigs.whitelistedEntities; + if (!config.whitelistedEntities) { + config.whitelistedEntities = bundlerDefaultConfigs.whitelistedEntities; } /** * validate whitelist addresses */ for (const entity of ["paymaster", "account", "factory"]) { - conf.whitelistedEntities[entity as IEntity] = fromEnvVar( - network, + config.whitelistedEntities[entity as IEntity] = fromEnvVar( `WL_${entity.toUpperCase()}`, - conf.whitelistedEntities[entity as IEntity], + config.whitelistedEntities[entity as IEntity], true ) as string[]; - const entities = conf.whitelistedEntities[entity as IEntity]; + const entities = config.whitelistedEntities[entity as IEntity]; if (typeof entities != "undefined" && typeof entities != "object") { throw new Error("Invalid config"); } @@ -327,7 +223,7 @@ export class Config { } } - return Object.assign({}, bundlerDefaultConfigs, conf); + return Object.assign({}, bundlerDefaultConfigs, config); } } @@ -357,29 +253,9 @@ const bundlerDefaultConfigs: BundlerConfig = { bundleSize: 4, // max size of bundle (in terms of user ops) relayingMode: "classic", pvgMarkup: 0, + canonicalMempoolId: "", }; -const NETWORKS_ENV = (): string[] | undefined => { - const networks = process.env["SKANDHA_NETWORKS"]; - if (networks) { - return networks.replace(/ /g, "").split(","); - } - return undefined; -}; - -/** - * str = baseGoerli => SKANDHA_BASE_GOERLI - * str = goerli = SKANDHA_GOERLI - * str = baseGoerli, suffix = ENTRYPOINTS => SKANDHA_BASE_GOERLI_ENTRYPOINTS - */ -function strToEnv(str: string, suffix = ""): string { - const prefix = `SKANDHA_${str.replace(/([A-Z])+/, "_$1").toUpperCase()}`; - if (suffix) { - return `${prefix}_${suffix}`; - } - return prefix; -} - function getEnvVar(envVar: string, fallback: T): T | string { const env = process.env[envVar]; if (!env) return fallback; @@ -387,12 +263,11 @@ function getEnvVar(envVar: string, fallback: T): T | string { } function fromEnvVar( - networkName: string, - suffix = "", + envVar = "", fallback: T, isArray = false ): T | string | string[] { - const envVarName = strToEnv(networkName, suffix); + const envVarName = `SKANDHA_${envVar}`; const envVarOrFallback = getEnvVar(envVarName, fallback); if (isArray && typeof envVarOrFallback === "string") { return (envVarOrFallback as string) diff --git a/packages/executor/src/executor.ts b/packages/executor/src/executor.ts index b57c86ca..7e223cfc 100644 --- a/packages/executor/src/executor.ts +++ b/packages/executor/src/executor.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/explicit-member-accessibility */ import { BigNumber, providers } from "ethers"; -import { IDbController, NetworkName, Logger } from "types/lib"; -import { INodeAPI } from "types/lib/node"; +import { IDbController, Logger } from "types/lib"; import { chainsWithoutEIP1559 } from "params/lib"; import { PerChainMetrics } from "monitoring/lib"; +import { SkandhaVersion } from "types/lib/executor"; import { Web3, Debug, Eth, Skandha } from "./modules"; import { MempoolService, @@ -14,15 +14,15 @@ import { EventsService, } from "./services"; import { Config } from "./config"; -import { BundlingMode, NetworkConfig } from "./interfaces"; +import { BundlingMode, GetNodeAPI, NetworkConfig } from "./interfaces"; export interface ExecutorOptions { - network: NetworkName; + version: SkandhaVersion; chainId: number; db: IDbController; config: Config; logger: Logger; - nodeApi?: INodeAPI; + getNodeApi?: GetNodeAPI; bundlingMode: BundlingMode; metrics: PerChainMetrics | null; } @@ -32,8 +32,8 @@ export class Executor { private logger: Logger; private metrics: PerChainMetrics | null; + public version: SkandhaVersion; public chainId: number; - public networkName: NetworkName; public config: Config; public provider: providers.JsonRpcProvider; @@ -51,24 +51,20 @@ export class Executor { private db: IDbController; - private nodeApi: INodeAPI | undefined; + private getNodeApi: GetNodeAPI; constructor(options: ExecutorOptions) { + this.version = options.version; this.db = options.db; - this.networkName = options.network; this.config = options.config; this.logger = options.logger; this.chainId = options.chainId; - this.nodeApi = options.nodeApi; + this.getNodeApi = options.getNodeApi ?? (() => null); this.metrics = options.metrics; - this.networkConfig = options.config.networks[ - options.network - ] as NetworkConfig; + this.networkConfig = options.config.getNetworkConfig(); - this.provider = this.config.getNetworkProvider( - this.networkName - ) as providers.JsonRpcProvider; + this.provider = this.config.getNetworkProvider(); this.reputationService = new ReputationService( this.db, @@ -83,7 +79,6 @@ export class Executor { this.provider, this.reputationService, this.chainId, - this.networkName, this.config, this.logger ); @@ -95,7 +90,6 @@ export class Executor { ); this.bundlingService = new BundlingService( this.chainId, - this.networkName, this.provider, this.mempoolService, this.userOpValidationService, @@ -115,7 +109,7 @@ export class Executor { ); this.eventsService.initEventListener(); - this.web3 = new Web3(this.config); + this.web3 = new Web3(this.config, this.version); this.debug = new Debug( this.provider, this.bundlingService, @@ -124,7 +118,6 @@ export class Executor { this.networkConfig ); this.skandha = new Skandha( - this.networkName, this.chainId, this.provider, this.config, @@ -139,19 +132,13 @@ export class Executor { this.networkConfig, this.logger, this.metrics, - this.nodeApi - ); - this.p2pService = new P2PService( - this.provider, - this.mempoolService, - this.bundlingService, - this.config, - this.logger + this.getNodeApi ); + this.p2pService = new P2PService(this.mempoolService); if (this.config.testingMode || options.bundlingMode == "manual") { this.bundlingService.setBundlingMode("manual"); - this.logger.info(`${this.networkName}: [X] MANUAL BUNDLING`); + this.logger.info("[X] MANUAL BUNDLING"); } if (this.config.testingMode) { this.bundlingService.setMaxBundleSize(10); @@ -162,21 +149,19 @@ export class Executor { throw Error( "If you want to use Flashbots Builder API, please set API url in 'rpcEndpointSubmit' in config file" ); - this.logger.info(`${this.networkName}: [X] FLASHBOTS BUIDLER API`); + this.logger.info("[X] FLASHBOTS BUIDLER API"); } if (this.networkConfig.conditionalTransactions) { - this.logger.info(`${this.networkName}: [x] CONDITIONAL TRANSACTIONS`); + this.logger.info("[x] CONDITIONAL TRANSACTIONS"); } if (this.networkConfig.rpcEndpointSubmit) { - this.logger.info( - `${this.networkName}: [x] SEPARATE RPC FOR SUBMITTING BUNDLES` - ); + this.logger.info("[x] SEPARATE RPC FOR SUBMITTING BUNDLES"); } if (this.networkConfig.enforceGasPrice) { - this.logger.info(`${this.networkName}: [x] ENFORCING GAS PRICES`); + this.logger.info("[x] ENFORCING GAS PRICES"); } // can't use eip2930 in unsafeMode and on chains that dont support 1559 @@ -192,11 +177,9 @@ export class Executor { } if (this.networkConfig.eip2930) { - this.logger.info(`${this.networkName}: [x] EIP2930 ENABLED`); + this.logger.info("[x] EIP2930 ENABLED"); } - this.logger.info( - `${this.networkName}: [x] USEROPS TTL - ${this.networkConfig.useropsTTL}` - ); + this.logger.info(`[x] USEROPS TTL - ${this.networkConfig.useropsTTL}`); } } diff --git a/packages/executor/src/interfaces.ts b/packages/executor/src/interfaces.ts index 7febdb79..f90dd277 100644 --- a/packages/executor/src/interfaces.ts +++ b/packages/executor/src/interfaces.ts @@ -1,7 +1,6 @@ import { BigNumber, BigNumberish, BytesLike } from "ethers"; -import { NetworkName } from "types/lib"; import { IWhitelistedEntities, RelayingMode } from "types/lib/executor"; -import { Executor } from "./executor"; +import { INodeAPI } from "types/lib/node"; import { MempoolEntry } from "./entities/MempoolEntry"; export interface Log { @@ -72,13 +71,12 @@ export type EthChainIdResponse = { chainId: number }; export type BundlingMode = "auto" | "manual"; -export type Executors = Map; +export type GetNodeAPI = () => INodeAPI | null; + export interface NetworkConfig { entryPoints: string[]; - relayer: string; // deprecated, but kept for backwards compatibility relayers: string[]; beneficiary: string; - name?: NetworkName; rpcEndpoint: string; minInclusionDenominator: number; throttlingSlack: number; @@ -146,6 +144,8 @@ export interface NetworkConfig { // 1000 = adds 1000 gas on top of estimated PVG // default = 0 pvgMarkup: number; + // canonical mempool id + canonicalMempoolId: string; } export type BundlerConfig = Omit< @@ -153,12 +153,8 @@ export type BundlerConfig = Omit< "entryPoints" | "rpcEndpoint" | "relayer" | "relayers" >; -export type Networks = { - [network in NetworkName]?: NetworkConfig; -}; - export interface ConfigOptions { - networks: Networks; + config: NetworkConfig | null; testingMode?: boolean; unsafeMode: boolean; redirectRpc: boolean; diff --git a/packages/executor/src/modules/eth.ts b/packages/executor/src/modules/eth.ts index 01876412..9e47faae 100644 --- a/packages/executor/src/modules/eth.ts +++ b/packages/executor/src/modules/eth.ts @@ -13,7 +13,6 @@ import { UserOperationReceipt, } from "types/lib/api/interfaces"; import { IEntryPoint__factory } from "types/lib/executor/contracts/factories"; -import { INodeAPI } from "types/lib/node"; import { IPVGEstimator } from "params/lib/types/IPVGEstimator"; import { estimateOptimismPVG, @@ -25,7 +24,7 @@ import { Logger } from "types/lib"; import { PerChainMetrics } from "monitoring/lib"; import { deepHexlify, packUserOp } from "../utils"; import { UserOpValidationService, MempoolService } from "../services"; -import { Log, NetworkConfig } from "../interfaces"; +import { GetNodeAPI, Log, NetworkConfig } from "../interfaces"; import { EstimateUserOperationGasArgs, SendUserOperationGasArgs, @@ -44,7 +43,7 @@ export class Eth { private config: NetworkConfig, private logger: Logger, private metrics: PerChainMetrics | null, - private nodeApi?: INodeAPI + private getNodeAPI: GetNodeAPI = () => null ) { // ["arbitrum", "arbitrumNova"] if ([42161, 42170].includes(this.chainId)) { @@ -105,10 +104,12 @@ export class Eth { this.metrics?.useropsInMempool.inc(); try { - if (this.nodeApi) { + const nodeApi = this.getNodeAPI(); + if (nodeApi != null) { + const nodeApi = this.getNodeAPI(); const blockNumber = await this.provider.getBlockNumber(); // TODO: fetch blockNumber from simulateValidation const chainId = await this.getChainId(); - await this.nodeApi.publishUserOpsWithEntryPointJSON( + await nodeApi!.publishUserOpsWithEntryPointJSON( entryPoint, chainId, [userOp], diff --git a/packages/executor/src/modules/skandha.ts b/packages/executor/src/modules/skandha.ts index 51c0f43f..decc2461 100644 --- a/packages/executor/src/modules/skandha.ts +++ b/packages/executor/src/modules/skandha.ts @@ -1,5 +1,5 @@ import { BigNumber, BigNumberish, ethers } from "ethers"; -import { Logger, NetworkName } from "types/lib"; +import { Logger } from "types/lib"; import { GetConfigResponse, GetFeeHistoryResponse, @@ -19,16 +19,12 @@ export class Skandha { networkConfig: NetworkConfig; constructor( - private networkName: NetworkName, private chainId: number, private provider: ethers.providers.JsonRpcProvider, private config: Config, private logger: Logger ) { - const networkConfig = this.config.getNetworkConfig(this.networkName); - if (!networkConfig) { - throw new Error("No network config"); - } + const networkConfig = this.config.getNetworkConfig(); this.networkConfig = networkConfig; } @@ -69,7 +65,7 @@ export class Skandha { } async getConfig(): Promise { - const wallets = this.config.getRelayers(this.networkName); + const wallets = this.config.getRelayers(); const walletAddresses = []; if (wallets) { for (const wallet of wallets) { diff --git a/packages/executor/src/modules/web3.ts b/packages/executor/src/modules/web3.ts index 6e86c07b..5709d800 100644 --- a/packages/executor/src/modules/web3.ts +++ b/packages/executor/src/modules/web3.ts @@ -1,8 +1,10 @@ +import { SkandhaVersion } from "types/lib/executor"; import { Config } from "../config"; + export class Web3 { - constructor(private config: Config) {} + constructor(private config: Config, private version: SkandhaVersion) {} clientVersion(): string { - return `skandha/${this.config.unsafeMode ? "unsafe/" : ""}0.0.3`; // TODO: get version based on commit hash + return `skandha/${this.version.version}-${this.version.commit}`; } } diff --git a/packages/executor/src/services/BundlingService/relayers/base.ts b/packages/executor/src/services/BundlingService/relayers/base.ts index 50b0aaaf..c5f08980 100644 --- a/packages/executor/src/services/BundlingService/relayers/base.ts +++ b/packages/executor/src/services/BundlingService/relayers/base.ts @@ -1,6 +1,6 @@ import { Mutex } from "async-mutex"; import { constants, providers, utils } from "ethers"; -import { Logger, NetworkName } from "types/lib"; +import { Logger } from "types/lib"; import { PerChainMetrics } from "monitoring/lib"; import { Config } from "../../../config"; import { Bundle, NetworkConfig } from "../../../interfaces"; @@ -19,7 +19,6 @@ export abstract class BaseRelayer implements IRelayingMode { constructor( protected logger: Logger, protected chainId: number, - protected network: NetworkName, protected provider: providers.JsonRpcProvider, protected config: Config, protected networkConfig: NetworkConfig, @@ -27,7 +26,7 @@ export abstract class BaseRelayer implements IRelayingMode { protected reputationService: ReputationService, protected metrics: PerChainMetrics | null ) { - const relayers = this.config.getRelayers(this.network); + const relayers = this.config.getRelayers(); if (!relayers) throw new Error("Relayers are not set"); this.relayers = [...relayers]; this.mutexes = this.relayers.map(() => new Mutex()); @@ -126,8 +125,8 @@ export abstract class BaseRelayer implements IRelayingMode { * if signer's balance is too low, send it to signer. otherwise, send to configured beneficiary. */ protected async selectBeneficiary(relayer: Relayer): Promise { - const config = this.config.getNetworkConfig(this.network); - let beneficiary = this.config.getBeneficiary(this.network); + const config = this.config.getNetworkConfig(); + let beneficiary = this.config.getBeneficiary(); if (!beneficiary || !utils.isAddress(beneficiary)) { return relayer.getAddress(); } @@ -135,7 +134,7 @@ export abstract class BaseRelayer implements IRelayingMode { const signerAddress = await relayer.getAddress(); const currentBalance = await this.provider.getBalance(signerAddress); - if (currentBalance.lte(config!.minSignerBalance) || !beneficiary) { + if (currentBalance.lte(config.minSignerBalance) || !beneficiary) { beneficiary = signerAddress; this.logger.info( `low balance on ${signerAddress}. using it as beneficiary` diff --git a/packages/executor/src/services/BundlingService/relayers/classic.ts b/packages/executor/src/services/BundlingService/relayers/classic.ts index 9d21836e..dbac4fb9 100644 --- a/packages/executor/src/services/BundlingService/relayers/classic.ts +++ b/packages/executor/src/services/BundlingService/relayers/classic.ts @@ -1,5 +1,5 @@ import { providers } from "ethers"; -import { NetworkName, Logger } from "types/lib"; +import { Logger } from "types/lib"; import { PerChainMetrics } from "monitoring/lib"; import { IEntryPoint__factory } from "types/lib/executor/contracts"; import { chainsWithoutEIP1559 } from "params/lib"; @@ -12,13 +12,11 @@ import { MempoolService } from "../../MempoolService"; import { estimateBundleGasLimit } from "../utils"; import { ReputationService } from "../../ReputationService"; import { BaseRelayer } from "./base"; -import { wait } from "../../../utils"; export class ClassicRelayer extends BaseRelayer { constructor( logger: Logger, chainId: number, - network: NetworkName, provider: providers.JsonRpcProvider, config: Config, networkConfig: NetworkConfig, @@ -29,7 +27,6 @@ export class ClassicRelayer extends BaseRelayer { super( logger, chainId, - network, provider, config, networkConfig, diff --git a/packages/executor/src/services/BundlingService/relayers/flashbots.ts b/packages/executor/src/services/BundlingService/relayers/flashbots.ts index 7f7816dd..0ceef01f 100644 --- a/packages/executor/src/services/BundlingService/relayers/flashbots.ts +++ b/packages/executor/src/services/BundlingService/relayers/flashbots.ts @@ -1,6 +1,6 @@ import { providers } from "ethers"; import { PerChainMetrics } from "monitoring/lib"; -import { Logger, NetworkName } from "types/lib"; +import { Logger } from "types/lib"; import { IEntryPoint__factory } from "types/lib/executor/contracts"; import { FlashbotsBundleProvider, @@ -22,7 +22,6 @@ export class FlashbotsRelayer extends BaseRelayer { constructor( logger: Logger, chainId: number, - network: NetworkName, provider: providers.JsonRpcProvider, config: Config, networkConfig: NetworkConfig, @@ -33,7 +32,6 @@ export class FlashbotsRelayer extends BaseRelayer { super( logger, chainId, - network, provider, config, networkConfig, @@ -138,7 +136,7 @@ export class FlashbotsRelayer extends BaseRelayer { this.provider, signer, this.networkConfig.rpcEndpointSubmit, - this.network + this.config.chainId ); const submitStart = now(); return new Promise((resolve, reject) => { diff --git a/packages/executor/src/services/BundlingService/service.ts b/packages/executor/src/services/BundlingService/service.ts index 2a607396..bfff7b03 100644 --- a/packages/executor/src/services/BundlingService/service.ts +++ b/packages/executor/src/services/BundlingService/service.ts @@ -1,6 +1,6 @@ import { BigNumber, providers } from "ethers"; import { PerChainMetrics } from "monitoring/lib"; -import { NetworkName, Logger } from "types/lib"; +import { Logger } from "types/lib"; import { BundlingMode } from "types/lib/api/interfaces"; import { IEntryPoint__factory } from "types/lib/executor/contracts"; import { @@ -38,7 +38,6 @@ export class BundlingService { constructor( private chainId: number, - private network: NetworkName, private provider: providers.JsonRpcProvider, private mempoolService: MempoolService, private userOpValidationService: UserOpValidationService, @@ -49,14 +48,13 @@ export class BundlingService { relayingMode: RelayingMode ) { this.mutex = new Mutex(); - this.networkConfig = config.getNetworkConfig(network)!; + this.networkConfig = config.getNetworkConfig(); if (relayingMode === "flashbots") { - this.logger.debug(`${this.network}: Using flashbots relayer`); + this.logger.debug("Using flashbots relayer"); this.relayer = new FlashbotsRelayer( this.logger, this.chainId, - this.network, this.provider, this.config, this.networkConfig, @@ -68,7 +66,6 @@ export class BundlingService { this.relayer = new ClassicRelayer( this.logger, this.chainId, - this.network, this.provider, this.config, this.networkConfig, diff --git a/packages/executor/src/services/P2PService.ts b/packages/executor/src/services/P2PService.ts index 08dc4cf2..af3be416 100644 --- a/packages/executor/src/services/P2PService.ts +++ b/packages/executor/src/services/P2PService.ts @@ -1,8 +1,4 @@ -import { providers } from "ethers"; import { UserOperationStruct } from "types/lib/executor/contracts/EntryPoint"; -import { Logger } from "types/lib"; -import { Config } from "../config"; -import { BundlingService } from "./BundlingService"; import { MempoolService } from "./MempoolService"; export type PooledUserOpHashesResponse = { @@ -13,13 +9,7 @@ export type PooledUserOpHashesResponse = { export type PooledUseropsByHashResponse = UserOperationStruct[]; export class P2PService { - constructor( - private provider: providers.JsonRpcProvider, - private mempoolService: MempoolService, - private bundlingService: BundlingService, - private config: Config, - private logger: Logger - ) {} + constructor(private mempoolService: MempoolService) {} async getPooledUserOpHashes( limit: number, diff --git a/packages/executor/src/services/UserOpValidation/service.ts b/packages/executor/src/services/UserOpValidation/service.ts index 725e55b2..5f91f2b9 100644 --- a/packages/executor/src/services/UserOpValidation/service.ts +++ b/packages/executor/src/services/UserOpValidation/service.ts @@ -1,5 +1,5 @@ import { BigNumber, providers } from "ethers"; -import { NetworkName, Logger } from "types/lib"; +import { Logger } from "types/lib"; import { UserOperationStruct } from "types/lib/executor/contracts/EntryPoint"; import RpcError from "types/lib/api/errors/rpc-error"; import * as RpcErrorCodes from "types/lib/api/errors/rpc-error-codes"; @@ -27,14 +27,10 @@ export class UserOpValidationService { private provider: providers.Provider, private reputationService: ReputationService, private chainId: number, - private network: NetworkName, private config: Config, private logger: Logger ) { - const networkConfig = config.getNetworkConfig(network); - if (!networkConfig) { - throw new Error(`No config found for ${network}`); - } + const networkConfig = config.getNetworkConfig(); this.networkConfig = networkConfig; this.estimationService = new EstimationService(this.provider, this.logger); @@ -43,7 +39,6 @@ export class UserOpValidationService { this.reputationService, this.chainId, this.networkConfig, - this.network, this.logger ); this.unsafeValidationService = new UnsafeValidationService( diff --git a/packages/executor/src/services/UserOpValidation/validators/safe.ts b/packages/executor/src/services/UserOpValidation/validators/safe.ts index edd5f658..8db0f555 100644 --- a/packages/executor/src/services/UserOpValidation/validators/safe.ts +++ b/packages/executor/src/services/UserOpValidation/validators/safe.ts @@ -7,7 +7,7 @@ import { BigNumber, ethers, providers } from "ethers"; import { BundlerCollectorReturn, ExitInfo } from "types/lib/executor"; import RpcError from "types/lib/api/errors/rpc-error"; import * as RpcErrorCodes from "types/lib/api/errors/rpc-error-codes"; -import { NetworkName, Logger } from "types/lib"; +import { Logger } from "types/lib"; import { IWhitelistedEntities } from "types/lib/executor"; import { NetworkConfig, @@ -59,7 +59,6 @@ export class SafeValidationService { private reputationService: ReputationService, private chainId: number, private networkConfig: NetworkConfig, - private network: NetworkName, private logger: Logger ) { this.gethTracer = new GethTracer( diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 7c01f888..cecc0b7d 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -7,10 +7,11 @@ import { SignableENR } from "@chainsafe/discv5"; import { INodeAPI } from "types/lib/node"; import { Executor } from "executor/lib/executor"; import logger from "api/lib/logger"; -import { Executors } from "executor/lib/interfaces"; import { BundlingMode } from "types/lib/api/interfaces"; import { createMetrics, getHttpMetricsServer } from "monitoring/lib"; import { MetricsOptions } from "types/lib/options/metrics"; +import { GetNodeAPI } from "executor/lib/interfaces"; +import { SkandhaVersion } from "types/lib/executor"; import { Network } from "./network/network"; import { SyncService } from "./sync"; import { IBundlerNodeOptions } from "./options"; @@ -30,7 +31,7 @@ export interface BundlerNodeOptions { server: Server; bundler: ApiApp; nodeApi: INodeAPI; - executors: Executors; + executor: Executor; syncService: SyncService; } @@ -43,6 +44,7 @@ export interface BundlerNodeInitOptions { redirectRpc: boolean; bundlingMode: BundlingMode; metricsOptions: MetricsOptions; + version: SkandhaVersion; } export class BundlerNode { @@ -69,6 +71,7 @@ export class BundlerNode { redirectRpc, bundlingMode, metricsOptions, + version, } = opts; let { peerId } = opts; @@ -77,18 +80,46 @@ export class BundlerNode { peerId = await enr.peerId(); } - const executors: Executors = new Map(); + let executor: Executor; + let nodeApi: INodeAPI | null = null; const metrics = metricsOptions.enable ? createMetrics({ p2p: true }, logger) : null; + const getNodeApi: GetNodeAPI = () => nodeApi; + if (relayersConfig.testingMode) { + metrics?.addChain(1337); + executor = new Executor({ + chainId: 1337, + db: relayerDb, + config: relayersConfig, + logger: logger, + getNodeApi, + bundlingMode, + metrics: metrics?.chains[1337] || null, + version, + }); + } else { + metrics?.addChain(relayersConfig.chainId); + executor = new Executor({ + chainId: relayersConfig.chainId, + db: relayerDb, + config: relayersConfig, + logger: logger, + getNodeApi, + bundlingMode, + metrics: metrics?.chains[relayersConfig.chainId] || null, + version, + }); + } + const network = await Network.init({ opts: nodeOptions.network, relayersConfig: relayersConfig, peerId: peerId, peerStoreDir: nodeOptions.network.dataDir, - executors, // ok: is empty at the moment + executor, // ok: is null at the moment metrics: metrics?.chains || null, }); @@ -97,7 +128,7 @@ export class BundlerNode { metrics: metrics?.chains || null, }); - const nodeApi = getApi({ network }); + nodeApi = getApi({ network }); await relayerDb.start(); @@ -108,38 +139,6 @@ export class BundlerNode { cors: nodeOptions.api.cors, }); - if (relayersConfig.testingMode) { - metrics?.addChain(1337); - const executor = new Executor({ - network: "dev", - chainId: 1337, - db: relayerDb, - config: relayersConfig, - logger: logger, - nodeApi, - bundlingMode, - metrics: metrics?.chains[1337] || null, - }); - executors.set(1337, executor); - } else { - for (const [networkName, chainId] of Object.entries( - relayersConfig.supportedNetworks - )) { - metrics?.addChain(chainId); - const executor = new Executor({ - network: networkName, - chainId, - db: relayerDb, - config: relayersConfig, - logger: logger, - nodeApi, - bundlingMode, - metrics: metrics?.chains[chainId] || null, - }); - executors.set(chainId, executor); - } - } - metricsOptions.enable ? await getHttpMetricsServer( metricsOptions.port, @@ -152,10 +151,9 @@ export class BundlerNode { const bundler = new ApiApp({ server: server.application, config: relayersConfig, - db: relayerDb, testingMode, redirectRpc, - executors, + executor, }); return new BundlerNode({ @@ -163,7 +161,7 @@ export class BundlerNode { server, bundler, nodeApi, - executors, + executor, syncService, }); } diff --git a/packages/node/src/network/network.ts b/packages/node/src/network/network.ts index e6d4e516..e16250fc 100644 --- a/packages/node/src/network/network.ts +++ b/packages/node/src/network/network.ts @@ -8,9 +8,9 @@ import logger, { Logger } from "api/lib/logger"; import { networksConfig } from "params/lib"; import { deserializeMempoolId } from "params/lib"; import { Config } from "executor/lib/config"; -import { Executors } from "executor/lib/interfaces"; import { toHexString } from "utils/lib"; import { AllChainsMetrics } from "monitoring/lib"; +import { Executor } from "executor/lib/executor"; import { INetworkOptions } from "../options"; import { getConnectionsMap } from "../utils"; import { INetwork, Libp2p } from "./interface"; @@ -38,7 +38,7 @@ type NetworkModules = { peerId: PeerId; networkProcessor: NetworkProcessor; relayersConfig: Config; - executors: Executors; + executor: Executor; metrics: AllChainsMetrics | null; }; @@ -46,7 +46,7 @@ export type NetworkInitOptions = { opts: INetworkOptions; relayersConfig: Config; peerId: PeerId; - executors: Executors; + executor: Executor; peerStoreDir?: string; metrics: AllChainsMetrics | null; }; @@ -63,7 +63,7 @@ export class Network implements INetwork { peerManager: PeerManager; libp2p: Libp2p; networkProcessor: NetworkProcessor; - executors: Executors; + executor: Executor; metrics: AllChainsMetrics | null; relayersConfig: Config; @@ -81,7 +81,7 @@ export class Network implements INetwork { peerId, networkProcessor, relayersConfig, - executors, + executor, metrics, } = opts; this.libp2p = libp2p; @@ -94,13 +94,13 @@ export class Network implements INetwork { this.peerId = peerId; this.networkProcessor = networkProcessor; this.relayersConfig = relayersConfig; - this.executors = executors; + this.executor = executor; this.metrics = metrics; this.logger.info("Initialised the bundler node module", "node"); } static async init(options: NetworkInitOptions): Promise { - const { peerId, relayersConfig, executors, metrics } = options; + const { peerId, relayersConfig, executor, metrics } = options; const libp2p = await createNodeJsLibp2p(peerId, options.opts, { peerStoreDir: options.peerStoreDir, }); @@ -118,7 +118,7 @@ export class Network implements INetwork { libp2p, peersData, logger, - reqRespHandlers: getReqRespHandlers(executors, relayersConfig, metrics), + reqRespHandlers: getReqRespHandlers(executor, relayersConfig, metrics), metadata, peerRpcScores, networkEventBus, @@ -126,7 +126,7 @@ export class Network implements INetwork { }); const networkProcessor = new NetworkProcessor( - { events: networkEventBus, relayersConfig, executors, metrics }, + { events: networkEventBus, relayersConfig, executor, metrics }, {} ); @@ -151,7 +151,7 @@ export class Network implements INetwork { peerId, networkProcessor, relayersConfig, - executors, + executor, metrics, }); } @@ -189,21 +189,20 @@ export class Network implements INetwork { const enr = await this.getEnr(); - const { supportedNetworks } = this.relayersConfig; - for (const [_, chainId] of Object.entries(supportedNetworks)) { - const mempoolIds = networksConfig[chainId]?.MEMPOOL_IDS; - if (mempoolIds) { - for (const mempoolIdHex of mempoolIds) { - this.mempoolToExecutor.set( - toHexString(mempoolIdHex), - this.executors.get(chainId)! - ); - - const mempoolId = deserializeMempoolId(mempoolIdHex); - this.subscribeGossipCoreTopics(mempoolId); - } + const mempoolIds = networksConfig[this.relayersConfig.chainId]?.MEMPOOL_IDS; + if (mempoolIds) { + for (const mempoolIdHex of mempoolIds) { + this.mempoolToExecutor.set(toHexString(mempoolIdHex), this.executor); + + const mempoolId = deserializeMempoolId(mempoolIdHex); + this.subscribeGossipCoreTopics(mempoolId); } } + if (this.relayersConfig.config.canonicalMempoolId) { + this.subscribeGossipCoreTopics( + this.relayersConfig.config.canonicalMempoolId + ); + } if (enr) { this.logger.info(`ENR: ${enr.encodeTxt()}`); @@ -273,7 +272,7 @@ export class Network implements INetwork { return await pooledUserOpHashes( this.reqResp, peerId, - this.executors, + this.executor, this.relayersConfig, req ); @@ -286,7 +285,7 @@ export class Network implements INetwork { return await pooledUserOpsByHash( this.reqResp, peerId, - this.executors, + this.executor, this.relayersConfig, req ); diff --git a/packages/node/src/network/processor/gossipHandlers.ts b/packages/node/src/network/processor/gossipHandlers.ts index 44696264..b63f938c 100644 --- a/packages/node/src/network/processor/gossipHandlers.ts +++ b/packages/node/src/network/processor/gossipHandlers.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { ts, NetworkName } from "types/lib"; +import { ts } from "types/lib"; import logger from "api/lib/logger"; import { Config } from "executor/lib/config"; -import { Executors } from "executor/lib/interfaces"; import { deserializeUserOpsWithEP } from "params/lib/utils/userOp"; import { AllChainsMetrics } from "monitoring/lib"; +import { Executor } from "executor/lib/executor"; import { GossipHandlers, GossipType } from "../gossip/interface"; import { validateGossipUserOpsWithEntryPoint } from "../validation"; import { NetworkEventBus } from "../events"; @@ -13,14 +13,14 @@ import { GossipValidationError } from "../gossip/errors"; export type ValidatorFnsModules = { relayersConfig: Config; events: NetworkEventBus; - executors: Executors; + executor: Executor; metrics: AllChainsMetrics | null; }; export function getGossipHandlers( modules: ValidatorFnsModules ): GossipHandlers { - const { relayersConfig, executors } = modules; + const { relayersConfig, executor } = modules; async function validateUserOpsWithEntryPoint( userOp: ts.UserOpsWithEntryPoint, mempool: string, @@ -57,11 +57,6 @@ export function getGossipHandlers( ): Promise { const { entryPoint, chainId, userOps } = deserializeUserOpsWithEP(userOpsWithEP); - const executor = executors.get(chainId); - if (!executor) { - logger.error(`Executor for ${chainId} not found`); - return; - } for (const userOp of userOps) { try { const isNewOrReplacing = diff --git a/packages/node/src/network/reqresp/handlers/index.ts b/packages/node/src/network/reqresp/handlers/index.ts index 23646c05..75fe039d 100644 --- a/packages/node/src/network/reqresp/handlers/index.ts +++ b/packages/node/src/network/reqresp/handlers/index.ts @@ -1,5 +1,5 @@ import { Config } from "executor/lib/config"; -import { Executors } from "executor/lib/interfaces"; +import { Executor } from "executor/lib/executor"; import { AllChainsMetrics } from "monitoring/lib"; import * as protocols from "../../../reqresp/protocols"; import { HandlerTypeFromMessage } from "../../../reqresp/types"; @@ -18,7 +18,7 @@ export interface ReqRespHandlers { } export function getReqRespHandlers( - executors: Executors, + executor: Executor, config: Config, metrics: AllChainsMetrics | null ): ReqRespHandlers { @@ -27,10 +27,10 @@ export function getReqRespHandlers( yield* onStatus(config); }, async *onPooledUserOpHashes(req) { - yield* onPooledUserOpHashes(executors, config, req); + yield* onPooledUserOpHashes(executor, config, req); }, async *onPooledUserOpsByHash(req) { - yield* onPooledUserOpsByHash(executors, config, req, metrics); + yield* onPooledUserOpsByHash(executor, config, req, metrics); }, }; } diff --git a/packages/node/src/network/reqresp/handlers/pooledUserOpHashes.ts b/packages/node/src/network/reqresp/handlers/pooledUserOpHashes.ts index e33b3def..50539a73 100644 --- a/packages/node/src/network/reqresp/handlers/pooledUserOpHashes.ts +++ b/packages/node/src/network/reqresp/handlers/pooledUserOpHashes.ts @@ -1,6 +1,6 @@ import { ts, ssz } from "types/lib"; import { Config } from "executor/lib/config"; -import { Executors } from "executor/lib/interfaces"; +import { Executor } from "executor/lib/executor"; import { networksConfig, deserializeMempoolId } from "params/lib"; import { MAX_OPS_PER_REQUEST } from "types/lib/sszTypes"; import logger from "api/lib/logger"; @@ -10,33 +10,24 @@ import { ResponseError } from "../../../reqresp/response"; import { RespStatus } from "../interface"; export async function* onPooledUserOpHashes( - executors: Executors, + executor: Executor, relayersConfig: Config, req: ts.PooledUserOpHashesRequest ): AsyncIterable> { - const { supportedNetworks } = relayersConfig; - let chainId: number | null = null; - for (const [_, id] of Object.entries(supportedNetworks)) { - const mempoolIds = networksConfig[id]?.MEMPOOL_IDS; - if (mempoolIds) { - for (const mempoolIdHex of mempoolIds) { - const mempoolId = deserializeMempoolId(mempoolIdHex); - if (mempoolId == deserializeMempoolId(req.mempool)) { - chainId = id; - } - } - } - } - - if (chainId == null) { + const mempoolIds = networksConfig[relayersConfig.chainId]?.MEMPOOL_IDS; + if ( + !mempoolIds || + !mempoolIds.some( + (mempoolIdHex) => + deserializeMempoolId(mempoolIdHex) == + deserializeMempoolId(req.mempool) || + deserializeMempoolId(req.mempool) == + relayersConfig.config.canonicalMempoolId + ) + ) { throw new ResponseError(RespStatus.INVALID_REQUEST, "Unsupported mempool"); } - const executor = executors.get(chainId); - if (!executor) { - throw new ResponseError(RespStatus.SERVER_ERROR, "Executor not found"); - } - const pooledUserOpHashes = await executor.p2pService.getPooledUserOpHashes( MAX_OPS_PER_REQUEST, Number(req.offset) diff --git a/packages/node/src/network/reqresp/handlers/pooledUserOpsByHash.ts b/packages/node/src/network/reqresp/handlers/pooledUserOpsByHash.ts index 38607d58..8e7a309e 100644 --- a/packages/node/src/network/reqresp/handlers/pooledUserOpsByHash.ts +++ b/packages/node/src/network/reqresp/handlers/pooledUserOpsByHash.ts @@ -1,31 +1,19 @@ import { ts } from "types/lib"; import { Config } from "executor/lib/config"; -import { Executors } from "executor/lib/interfaces"; +import { Executor } from "executor/lib/executor"; import { serializeUserOp, userOpHashToString } from "params/lib/utils/userOp"; import logger from "api/lib/logger"; import { AllChainsMetrics } from "monitoring/lib"; import { EncodedPayload, EncodedPayloadType } from "../../../reqresp/types"; -import { ResponseError } from "../../../reqresp/response"; -import { RespStatus } from "../interface"; export async function* onPooledUserOpsByHash( - executors: Executors, + executor: Executor, relayersConfig: Config, req: ts.PooledUserOpsByHashRequest, metrics: AllChainsMetrics | null ): AsyncIterable> { const userOpHashes = req.hashes.map((hash) => userOpHashToString(hash)); logger.debug(`UserOpsByHash, received hashes: ${userOpHashes.join(", ")}`); - const { supportedNetworks } = relayersConfig; - const chainId = Object.values(supportedNetworks).at(0); // OK: any network works - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (!chainId) { - throw new ResponseError(RespStatus.SERVER_ERROR, "No network found"); - } - const executor = executors.get(chainId); - if (!executor) { - throw new ResponseError(RespStatus.SERVER_ERROR, "Executor not found"); - } const userOps = await executor.p2pService.getPooledUserOpsByHash( userOpHashes ); @@ -34,7 +22,7 @@ export async function* onPooledUserOpsByHash( const sszUserOps = userOps.map((userOp) => serializeUserOp(userOp)); - if (metrics) metrics[chainId].useropsSent?.inc(userOps.length); + if (metrics) metrics[relayersConfig.chainId].useropsSent?.inc(userOps.length); yield { type: EncodedPayloadType.ssz, diff --git a/packages/node/src/network/reqresp/handlers/status.ts b/packages/node/src/network/reqresp/handlers/status.ts index 14abda26..7c62536d 100644 --- a/packages/node/src/network/reqresp/handlers/status.ts +++ b/packages/node/src/network/reqresp/handlers/status.ts @@ -6,14 +6,11 @@ import { EncodedPayload, EncodedPayloadType } from "../../../reqresp/types"; export async function* onStatus( relayersConfig: Config ): AsyncIterable> { - const { supportedNetworks } = relayersConfig; const data: ts.Status = []; - for (const chainId of Object.values(supportedNetworks)) { - const mempoolIds = networksConfig[chainId]?.MEMPOOL_IDS; - if (mempoolIds) { - for (const mempoolIdHex of mempoolIds) { - data.push(mempoolIdHex); - } + const mempoolIds = networksConfig[relayersConfig.chainId]?.MEMPOOL_IDS; + if (mempoolIds) { + for (const mempoolIdHex of mempoolIds) { + data.push(mempoolIdHex); } } yield { type: EncodedPayloadType.ssz, data }; diff --git a/packages/node/src/network/reqresp/pooledUserOpHashes.ts b/packages/node/src/network/reqresp/pooledUserOpHashes.ts index 1163814b..46d9dfc9 100644 --- a/packages/node/src/network/reqresp/pooledUserOpHashes.ts +++ b/packages/node/src/network/reqresp/pooledUserOpHashes.ts @@ -1,4 +1,4 @@ -import { Executors } from "executor/lib/interfaces"; +import { Executor } from "executor/lib/executor"; import { Config } from "executor/lib/config"; import { ts } from "types/lib"; import { PeerId } from "@libp2p/interface-peer-id"; @@ -7,7 +7,7 @@ import { IReqRespNode } from "./interface"; export async function pooledUserOpHashes( reqResp: IReqRespNode, peerId: PeerId, - executors: Executors, + executor: Executor, relayersConfig: Config, req: ts.PooledUserOpHashesRequest ): Promise { diff --git a/packages/node/src/network/reqresp/pooledUserOpsByHash.ts b/packages/node/src/network/reqresp/pooledUserOpsByHash.ts index 51ff0cc7..8a94776c 100644 --- a/packages/node/src/network/reqresp/pooledUserOpsByHash.ts +++ b/packages/node/src/network/reqresp/pooledUserOpsByHash.ts @@ -1,4 +1,4 @@ -import { Executors } from "executor/lib/interfaces"; +import { Executor } from "executor/lib/executor"; import { Config } from "executor/lib/config"; import { ts } from "types/lib"; import { PeerId } from "@libp2p/interface-peer-id"; @@ -7,7 +7,7 @@ import { IReqRespNode } from "./interface"; export async function pooledUserOpsByHash( reqResp: IReqRespNode, peerId: PeerId, - executors: Executors, + executor: Executor, relayersConfig: Config, req: ts.PooledUserOpsByHashRequest ): Promise { diff --git a/packages/node/src/network/validation/userOpsWithEntryPoint.ts b/packages/node/src/network/validation/userOpsWithEntryPoint.ts index 40703e62..13800ae0 100644 --- a/packages/node/src/network/validation/userOpsWithEntryPoint.ts +++ b/packages/node/src/network/validation/userOpsWithEntryPoint.ts @@ -11,22 +11,21 @@ export async function validateGossipUserOpsWithEntryPoint( const entryPoint = toHexString(userOpWithEP.entry_point_contract); const blockHash = Number(userOpWithEP.verified_at_block_hash); - if (!relayersConfig.isNetworkSupported(chainId)) { + if (relayersConfig.chainId != chainId) { throw new GossipValidationError( GossipErrorCode.INVALID_CHAIN_ID, "Network is not supported" ); } - if (!relayersConfig.isEntryPointSupported(chainId, entryPoint)) { + if (!relayersConfig.isEntryPointSupported(entryPoint)) { throw new GossipValidationError( GossipErrorCode.INVALID_ENTRY_POINT, "Entrypoint is not supported" ); } - const networkName = relayersConfig.getNetworkNameByChainId(chainId); - const networkProvider = relayersConfig.getNetworkProvider(networkName!); + const networkProvider = relayersConfig.getNetworkProvider(); const blockNumber = await networkProvider?.getBlockNumber(); if (blockNumber == null || blockHash + 20 < blockNumber) { diff --git a/packages/params/src/networks/dev.ts b/packages/params/src/networks/dev.ts index dd51952a..3718fc21 100644 --- a/packages/params/src/networks/dev.ts +++ b/packages/params/src/networks/dev.ts @@ -3,7 +3,6 @@ import { serializeMempoolId } from "../utils"; import { INetworkParams } from "../types"; export const devNetworkConfig: INetworkParams = { - CONFIG_NAME: "dev", CHAIN_ID: 1337, ENTRY_POINT_CONTRACT: [b("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")], MEMPOOL_IDS: [ diff --git a/packages/params/src/networks/goerli.ts b/packages/params/src/networks/goerli.ts index 43648236..4762e0c5 100644 --- a/packages/params/src/networks/goerli.ts +++ b/packages/params/src/networks/goerli.ts @@ -3,7 +3,6 @@ import { INetworkParams } from "../types"; import { serializeMempoolId } from "../utils"; export const goerliNetworkConfig: INetworkParams = { - CONFIG_NAME: "goerli", CHAIN_ID: 5, ENTRY_POINT_CONTRACT: [b("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")], MEMPOOL_IDS: [ diff --git a/packages/params/src/networks/mainnet.ts b/packages/params/src/networks/mainnet.ts index e54d14fa..5f0cc862 100644 --- a/packages/params/src/networks/mainnet.ts +++ b/packages/params/src/networks/mainnet.ts @@ -2,7 +2,6 @@ import { fromHexString as b } from "@chainsafe/ssz"; import { INetworkParams } from "../types"; export const mainnetNetworkConfig: INetworkParams = { - CONFIG_NAME: "mainnet", CHAIN_ID: 1, ENTRY_POINT_CONTRACT: [b("0x0576a174D229E3cFA37253523E645A78A0C91B57")], MEMPOOL_IDS: [b("")], diff --git a/packages/params/src/networks/matic.ts b/packages/params/src/networks/matic.ts index b0e23ed5..d3afc541 100644 --- a/packages/params/src/networks/matic.ts +++ b/packages/params/src/networks/matic.ts @@ -2,7 +2,6 @@ import { fromHexString as b } from "@chainsafe/ssz"; import { INetworkParams } from "../types"; export const maticNetworkConfig: INetworkParams = { - CONFIG_NAME: "matic", CHAIN_ID: 137, ENTRY_POINT_CONTRACT: [b("0x0576a174D229E3cFA37253523E645A78A0C91B57")], MEMPOOL_IDS: [b("")], diff --git a/packages/params/src/networks/mumbai.ts b/packages/params/src/networks/mumbai.ts index f7890ecf..a0d7f97b 100644 --- a/packages/params/src/networks/mumbai.ts +++ b/packages/params/src/networks/mumbai.ts @@ -3,7 +3,6 @@ import { serializeMempoolId } from "../utils"; import { INetworkParams } from "../types"; export const mumbaiNetworkConfig: INetworkParams = { - CONFIG_NAME: "mumbai", CHAIN_ID: 80001, ENTRY_POINT_CONTRACT: [b("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")], MEMPOOL_IDS: [ diff --git a/packages/params/src/networks/sepolia.ts b/packages/params/src/networks/sepolia.ts index d507b36c..85cd4606 100644 --- a/packages/params/src/networks/sepolia.ts +++ b/packages/params/src/networks/sepolia.ts @@ -3,7 +3,6 @@ import { serializeMempoolId } from "../utils"; import { INetworkParams } from "../types"; export const sepoliaNetworkConfig: INetworkParams = { - CONFIG_NAME: "sepolia", CHAIN_ID: 11155111, ENTRY_POINT_CONTRACT: [b("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")], MEMPOOL_IDS: [ diff --git a/packages/params/src/networks/xdai.ts b/packages/params/src/networks/xdai.ts index c85227f3..f47d5658 100644 --- a/packages/params/src/networks/xdai.ts +++ b/packages/params/src/networks/xdai.ts @@ -2,7 +2,6 @@ import { fromHexString as b } from "@chainsafe/ssz"; import { INetworkParams } from "../types"; export const xdaiNetworkConfig: INetworkParams = { - CONFIG_NAME: "xdai", CHAIN_ID: 100, ENTRY_POINT_CONTRACT: [b("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")], MEMPOOL_IDS: [b("")], diff --git a/packages/params/src/types/index.ts b/packages/params/src/types/index.ts index 1741c899..b5a4807d 100644 --- a/packages/params/src/types/index.ts +++ b/packages/params/src/types/index.ts @@ -1,8 +1,4 @@ -import { NetworkName } from "types/lib"; - export type INetworkParams = { - CONFIG_NAME: NetworkName; - // chainId CHAIN_ID: number; diff --git a/packages/params/src/utils/userOp.ts b/packages/params/src/utils/userOp.ts index 5a676f8a..8027f719 100644 --- a/packages/params/src/utils/userOp.ts +++ b/packages/params/src/utils/userOp.ts @@ -10,7 +10,7 @@ const bigintToBigNumber = (bn: bigint): BigNumberish => { }; const bigNumberishToBigint = (bn: BigNumberish): bigint => { - return UintBn256.fromJson(BigNumber.from(bn).toNumber()); + return UintBn256.fromJson(BigNumber.from(bn).toBigInt()); }; export const userOpHashToBytes = (hash: string): ts.Bytes32 => { diff --git a/packages/types/src/executor/index.ts b/packages/types/src/executor/index.ts index 89699564..dba509d8 100644 --- a/packages/types/src/executor/index.ts +++ b/packages/types/src/executor/index.ts @@ -1,3 +1,9 @@ +export type SkandhaVersion = { + /** "0.28.2" */ + version: string; + commit: string; +}; + export type RelayingMode = "flashbots" | "classic"; export interface SendBundleReturn { transactionHash: string; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index b1a08bac..ca08e504 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -2,4 +2,3 @@ export * as ts from "./types"; export * as ssz from "./sszTypes"; export * from "./db"; export * from "./logger"; -export type NetworkName = string;