diff --git a/README.md b/README.md index 796c7690..7d995699 100644 --- a/README.md +++ b/README.md @@ -227,10 +227,6 @@ Documentation can be found [here](packages/chopsticks/src/plugins/try-runtime/RE ## FAQ -### 127.0.0.1:8000 Abnormal Closure - -Chopsticks listen on `localhost:8000` by default, if you are on `macos`, it may not resolve to `127.0.0.1` to `localhost`. You can access chopsticks using `localhost:8000` instead, or you can start chopsticks with `--addr=127.0.0.1`. - ### What is mocked? What are things that could work with chopsticks, but still fail in production? Generally, anything that involves something more than onchain STF `new_state = f(old_state)` are not guaranteed to work in production. diff --git a/packages/chopsticks/src/cli.ts b/packages/chopsticks/src/cli.ts index 0c470b7c..2ad95fdd 100644 --- a/packages/chopsticks/src/cli.ts +++ b/packages/chopsticks/src/cli.ts @@ -45,7 +45,8 @@ const commands = yargs(hideBin(process.argv)) 'Path to config file with default options', () => ({}), // we load config in middleware ) - .options(getYargsOptions(configSchema.shape)), + .options(getYargsOptions(configSchema.shape)) + .deprecateOption('addr', '⚠️ Use --host instead.'), async (argv) => { await setupWithServer(configSchema.parse(argv)) }, @@ -101,6 +102,7 @@ const commands = yargs(hideBin(process.argv)) .alias('wasm-override', 'w') .usage('Usage: $0 [options]') .example('$0', '-c acala') + .showHelpOnFail(false) if (!environment.DISABLE_PLUGINS) { pluginExtendCli( diff --git a/packages/chopsticks/src/plugins/follow-chain/cli.ts b/packages/chopsticks/src/plugins/follow-chain/cli.ts index 77c71bc5..7ffe84f8 100644 --- a/packages/chopsticks/src/plugins/follow-chain/cli.ts +++ b/packages/chopsticks/src/plugins/follow-chain/cli.ts @@ -38,8 +38,8 @@ export const cli = (y: Argv) => { }) const context = await setupContext(config, true) - const { close, port: listenPort } = await createServer(handler(context), config.addr, config.port) - logger.info(`${await context.chain.api.getSystemChain()} RPC listening on ${config.addr}:${listenPort}`) + const { close, addr } = await createServer(handler(context), config.port, config.host) + logger.info(`${await context.chain.api.getSystemChain()} RPC listening on http://${addr} and ws://${addr}`) const chain = context.chain diff --git a/packages/chopsticks/src/plugins/index.ts b/packages/chopsticks/src/plugins/index.ts index 44b24c2b..f836e910 100644 --- a/packages/chopsticks/src/plugins/index.ts +++ b/packages/chopsticks/src/plugins/index.ts @@ -1,10 +1,10 @@ import { Handlers, environment } from '@acala-network/chopsticks-core' -import { lstatSync, readFileSync, readdirSync } from 'fs' +import { lstatSync, readFileSync, readdirSync } from 'node:fs' import _ from 'lodash' import type { Argv } from 'yargs' import { defaultLogger } from '../logger.js' -import { resolve } from 'path' +import { resolve } from 'node:path' const logger = defaultLogger.child({ name: 'plugin' }) diff --git a/packages/chopsticks/src/plugins/trace-transaction/index.ts b/packages/chopsticks/src/plugins/trace-transaction/index.ts index 109376b2..24320fbf 100644 --- a/packages/chopsticks/src/plugins/trace-transaction/index.ts +++ b/packages/chopsticks/src/plugins/trace-transaction/index.ts @@ -1,6 +1,6 @@ import { Argv } from 'yargs' import { pinoLogger } from '@acala-network/chopsticks-core' -import { writeFileSync } from 'fs' +import { writeFileSync } from 'node:fs' import { z } from 'zod' import _ from 'lodash' diff --git a/packages/chopsticks/src/plugins/try-runtime/index.ts b/packages/chopsticks/src/plugins/try-runtime/index.ts index f5c8bc61..1df26b1a 100644 --- a/packages/chopsticks/src/plugins/try-runtime/index.ts +++ b/packages/chopsticks/src/plugins/try-runtime/index.ts @@ -39,7 +39,7 @@ export const cli = (y: Argv) => { } const context = await setupContext({ ...config, - addr: 'localhost', + host: 'localhost', port: 8000, 'build-block-mode': BuildBlockMode.Manual, }) diff --git a/packages/chopsticks/src/schema/index.ts b/packages/chopsticks/src/schema/index.ts index f90e8ac6..04dfd7da 100644 --- a/packages/chopsticks/src/schema/index.ts +++ b/packages/chopsticks/src/schema/index.ts @@ -12,11 +12,12 @@ export const zHex = z.custom((val: any) => /^0x\w+$/.test(val)) export const zHash = z.string().length(66).and(zHex) export const configSchema = z.object({ - addr: z + addr: z.union([z.literal('localhost'), z.string().ip()]).optional(), + host: z .union([z.literal('localhost'), z.string().ip()], { description: 'Server listening interface', }) - .default('localhost'), + .optional(), port: z.number({ description: 'Server listening port' }).default(8000), endpoint: z.union([z.string(), z.array(z.string())], { description: 'Endpoint to connect to' }).optional(), block: z diff --git a/packages/chopsticks/src/schema/options.test.ts b/packages/chopsticks/src/schema/options.test.ts index 8156658a..5e1cb939 100644 --- a/packages/chopsticks/src/schema/options.test.ts +++ b/packages/chopsticks/src/schema/options.test.ts @@ -7,7 +7,7 @@ it('get yargs options from zod schema', () => { "addr": { "choices": undefined, "demandOption": false, - "description": "Server listening interface", + "description": undefined, "type": "string", }, "allow-unresolved-imports": { @@ -56,6 +56,12 @@ it('get yargs options from zod schema', () => { "description": "Alias to \`chain-spec\`. URL to chain spec file. NOTE: Only parachains with AURA consensus are supported!", "type": "string", }, + "host": { + "choices": undefined, + "demandOption": false, + "description": "Server listening interface", + "type": "string", + }, "import-storage": { "choices": undefined, "demandOption": false, diff --git a/packages/chopsticks/src/schema/parse.test.ts b/packages/chopsticks/src/schema/parse.test.ts index fcb3ac97..21ad7c3c 100644 --- a/packages/chopsticks/src/schema/parse.test.ts +++ b/packages/chopsticks/src/schema/parse.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' -import { readdirSync } from 'fs' +import { readdirSync } from 'node:fs' import _ from 'lodash' -import path from 'path' +import path from 'node:path' import { configSchema, fetchConfig } from './index.js' @@ -28,7 +28,6 @@ describe('Existing configs', async () => { describe('Parsed options', () => { const defaults = { - addr: 'localhost', port: 8000, 'build-block-mode': 'Batch', } diff --git a/packages/chopsticks/src/server.ts b/packages/chopsticks/src/server.ts index efc03fb1..5c6aebac 100644 --- a/packages/chopsticks/src/server.ts +++ b/packages/chopsticks/src/server.ts @@ -57,7 +57,7 @@ const respond = (res: http.ServerResponse, data?: any) => { res.end() } -const portInUse = async (port: number, addr: string) => { +const portInUse = async (port: number, host?: string) => { const server = http.createServer() const inUse = await new Promise((resolve) => { server.once('error', (e: any) => { @@ -71,16 +71,17 @@ const portInUse = async (port: number, addr: string) => { server.close() resolve(false) }) - server.listen(port, addr) + server.listen(port, host) }) server.removeAllListeners() server.unref() + await new Promise((r) => setTimeout(r, 50)) return inUse } -export const createServer = async (handler: Handler, addr: string, port: number) => { +export const createServer = async (handler: Handler, port: number, host?: string) => { let wss: WebSocketServer | undefined - let listenPort: number | undefined + let addressInfo: AddressInfo | undefined const emptySubscriptionManager = { subscribe: () => { @@ -151,7 +152,7 @@ export const createServer = async (handler: Handler, addr: string, port: number) }) for (let i = 0; i < 10; i++) { - if (port && (await portInUse(port + i, addr))) { + if (port && (await portInUse(port + i, host))) { continue } const preferPort = port ? port + i : undefined @@ -162,9 +163,9 @@ export const createServer = async (handler: Handler, addr: string, port: number) reject(e) } server.once('error', onError) - server.listen(preferPort, addr, () => { + server.listen(preferPort, host, () => { wss = new WebSocketServer({ server, maxPayload: 1024 * 1024 * 100 }) - listenPort = (server.address() as AddressInfo).port + addressInfo = server.address() as AddressInfo server.removeListener('error', onError) resolve() }) @@ -172,7 +173,7 @@ export const createServer = async (handler: Handler, addr: string, port: number) break } - if (!wss || !listenPort) { + if (!wss || !addressInfo) { throw new Error(`Failed to create WebsocketServer at port ${port}`) } @@ -289,7 +290,8 @@ export const createServer = async (handler: Handler, addr: string, port: number) }) return { - port: listenPort, + addr: `${addressInfo.family === 'IPv6' ? `[${addressInfo.address}]` : addressInfo.address}:${addressInfo.port}`, + port: addressInfo.port, close: async () => { server.close() server.closeAllConnections() diff --git a/packages/chopsticks/src/setup-with-server.ts b/packages/chopsticks/src/setup-with-server.ts index 8ef8bcf5..95d04d17 100644 --- a/packages/chopsticks/src/setup-with-server.ts +++ b/packages/chopsticks/src/setup-with-server.ts @@ -5,17 +5,18 @@ import { handler } from './rpc/index.js' import { setupContext } from './context.js' export const setupWithServer = async (argv: Config) => { + if (argv.addr) { + defaultLogger.warn({}, `⚠️ Option --addr is deprecated, please use --host instead.`) + argv.host ??= argv.addr + } const context = await setupContext(argv) - const addr = argv.addr ?? 'localhost' - const { close, port: listenPort } = await createServer(handler(context), addr, argv.port) - - defaultLogger.info(`${await context.chain.api.getSystemChain()} RPC listening on ${addr}:${listenPort}`) + const { close, addr } = await createServer(handler(context), argv.port, argv.host) + defaultLogger.info(`${await context.chain.api.getSystemChain()} RPC listening on http://${addr} and ws://${addr}`) return { ...context, - addr: argv.addr, - listenPort, + addr, async close() { await context.chain.close() await context.fetchStorageWorker?.terminate() diff --git a/packages/chopsticks/src/utils/tunnel.ts b/packages/chopsticks/src/utils/tunnel.ts index 8f33162f..a0d795ce 100644 --- a/packages/chopsticks/src/utils/tunnel.ts +++ b/packages/chopsticks/src/utils/tunnel.ts @@ -5,11 +5,11 @@ import npmConf from '@pnpm/npm-conf' const npmConfig = npmConf().config -global.GLOBAL_AGENT.HTTP_PROXY = +globalThis.GLOBAL_AGENT.HTTP_PROXY = environment.HTTP_PROXY || environment.http_proxy || environment.HTTPS_PROXY || environment.https_proxy || npmConfig.get('proxy') || npmConfig.get('https-proxy') || - global.GLOBAL_AGENT.HTTP_PROXY + globalThis.GLOBAL_AGENT.HTTP_PROXY diff --git a/packages/e2e/src/genesis-provider.test.ts b/packages/e2e/src/genesis-provider.test.ts index 0fefd23b..3b49b298 100644 --- a/packages/e2e/src/genesis-provider.test.ts +++ b/packages/e2e/src/genesis-provider.test.ts @@ -13,7 +13,7 @@ describe.each([ ['Asset Hub Kusama', new URL('../blobs/asset-hub-kusama.json', import.meta.url).pathname], ])(`genesis provider works %s`, async (name, genesis) => { const { chain, dev, api, teardown } = await setupContextWithConfig({ - addr: 'localhost', + host: 'localhost', port: 1234, genesis, 'build-block-mode': BuildBlockMode.Manual, diff --git a/packages/e2e/src/helper.ts b/packages/e2e/src/helper.ts index 70485d30..4ecc7a36 100644 --- a/packages/e2e/src/helper.ts +++ b/packages/e2e/src/helper.ts @@ -102,8 +102,8 @@ export const setupAll = async ({ await chain.newBlock() } - const { port, close } = await createServer(handler({ chain }), 'localhost', 0) - const ws = new WsProvider(`ws://localhost:${port}`, 3_000, undefined, 300_000) + const { addr, port, close } = await createServer(handler({ chain }), 0, 'localhost') + const ws = new WsProvider(`ws://${addr}`, 3_000, undefined, 300_000) return { chain, diff --git a/packages/e2e/src/import-storage/index.test.ts b/packages/e2e/src/import-storage/index.test.ts index d0b43a7c..d5fe44d1 100644 --- a/packages/e2e/src/import-storage/index.test.ts +++ b/packages/e2e/src/import-storage/index.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import path from 'path' +import path from 'node:path' import { api, chain, setupApi } from '../helper.js' import { compactHex } from '@acala-network/chopsticks' diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 16628bb1..aed7792c 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -27,7 +27,7 @@ export type SetupOption = { wasmOverride?: string db?: string timeout?: number - addr?: string + host?: string port?: number maxMemoryBlockCount?: number resume?: boolean | HexString | number @@ -47,7 +47,7 @@ export const createConfig = ({ wasmOverride, db, timeout, - addr, + host, port, maxMemoryBlockCount, resume, @@ -55,12 +55,11 @@ export const createConfig = ({ allowUnresolvedImports, processQueuedMessages, }: SetupOption): SetupConfig => { - addr = addr ?? 'localhost' // random port if not specified port = port ?? Math.floor(Math.random() * 10000) + 10000 const config = { endpoint, - addr, + host, port, block: blockNumber || blockHash, 'mock-signature-host': true, @@ -82,9 +81,9 @@ export const setupContext = async (option: SetupOption) => { } export const setupContextWithConfig = async ({ timeout, ...config }: SetupConfig) => { - const { chain, addr, listenPort, close } = await setupWithServer(config) + const { chain, addr, close } = await setupWithServer(config) - const url = `ws://${addr}:${listenPort}` + const url = `ws://${addr}` const ws = new WsProvider(url, 3_000, undefined, timeout) const api = await ApiPromise.create({ provider: ws, diff --git a/yarn.lock b/yarn.lock index 008659d8..94711d80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1259,14 +1259,14 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.3": +"@noble/hashes@npm:1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" checksum: 10c0/8c3f005ee72e7b8f9cff756dfae1241485187254e3f743873e22073d63906863df5d4f13d441b7530ea614b7a093f0d889309f28b59850f33b66cb26a779a4a5 languageName: node linkType: hard -"@noble/hashes@npm:^1.4.0": +"@noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0": version: 1.5.0 resolution: "@noble/hashes@npm:1.5.0" checksum: 10c0/1b46539695fbfe4477c0822d90c881a04d4fa2921c08c552375b444a48cac9930cb1ee68de0a3c7859e676554d0f3771999716606dc4d8f826e414c11692cdd9 @@ -7755,14 +7755,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": - version: 1.0.1 - resolution: "picocolors@npm:1.0.1" - checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400 - languageName: node - linkType: hard - -"picocolors@npm:^1.1.0": +"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.0": version: 1.1.0 resolution: "picocolors@npm:1.1.0" checksum: 10c0/86946f6032148801ef09c051c6fb13b5cf942eaf147e30ea79edb91dd32d700934edebe782a1078ff859fb2b816792e97ef4dab03d7f0b804f6b01a0df35e023 @@ -7899,18 +7892,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.40": - version: 8.4.41 - resolution: "postcss@npm:8.4.41" - dependencies: - nanoid: "npm:^3.3.7" - picocolors: "npm:^1.0.1" - source-map-js: "npm:^1.2.0" - checksum: 10c0/c1828fc59e7ec1a3bf52b3a42f615dba53c67960ed82a81df6441b485fe43c20aba7f4e7c55425762fd99c594ecabbaaba8cf5b30fd79dfec5b52a9f63a2d690 - languageName: node - linkType: hard - -"postcss@npm:^8.4.43": +"postcss@npm:^8.4.40, postcss@npm:^8.4.43": version: 8.4.47 resolution: "postcss@npm:8.4.47" dependencies: @@ -8869,14 +8851,7 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.2.0": - version: 1.2.0 - resolution: "source-map-js@npm:1.2.0" - checksum: 10c0/7e5f896ac10a3a50fe2898e5009c58ff0dc102dcb056ed27a354623a0ece8954d4b2649e1a1b2b52ef2e161d26f8859c7710350930751640e71e374fe2d321a4 - languageName: node - linkType: hard - -"source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf