From adaf98d9acefe487f6f26325b976bd2895e1f2b5 Mon Sep 17 00:00:00 2001 From: Danilo Tuler Date: Tue, 6 Oct 2026 22:21:48 -0400 Subject: [PATCH 1/2] feat(cli): add --anvil-arg option to run command Pass extra arguments verbatim to anvil (e.g. --slots-in-an-epoch) without modeling every anvil option in the CLI. Co-Authored-By: Claude Opus 5.5 --- .changeset/anvil-extra-args.md | 5 +++ apps/cli/src/commands/run.ts | 8 ++++ apps/cli/src/compose/anvil.ts | 7 +++- apps/cli/src/exec/rollups.ts | 3 ++ apps/cli/tests/unit/compose/anvil.test.ts | 51 +++++++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 .changeset/anvil-extra-args.md create mode 100644 apps/cli/tests/unit/compose/anvil.test.ts diff --git a/.changeset/anvil-extra-args.md b/.changeset/anvil-extra-args.md new file mode 100644 index 00000000..9b9482b6 --- /dev/null +++ b/.changeset/anvil-extra-args.md @@ -0,0 +1,5 @@ +--- +"@cartesi/cli": minor +--- + +add `--anvil-arg` option to `cartesi run` to pass extra arguments to anvil diff --git a/apps/cli/src/commands/run.ts b/apps/cli/src/commands/run.ts index bc84b331..fff0f50a 100755 --- a/apps/cli/src/commands/run.ts +++ b/apps/cli/src/commands/run.ts @@ -309,6 +309,12 @@ export const createRunCommand = () => { "deploy application with PRT consensus", ).default(false), ) + .option( + "--anvil-arg ", + "extra argument passed verbatim to anvil, can be repeated (e.g. --anvil-arg=--slots-in-an-epoch=1)", + (value, prev: string[]) => prev.concat([value]), + [] as string[], + ) .addOption( new Option( "--block-time ", @@ -394,6 +400,7 @@ export const createRunCommand = () => { .option("-v, --verbose", "verbose output", false) .action(async (options, program) => { const { + anvilArg: anvilArgs, prt, blockTime, cpus, @@ -456,6 +463,7 @@ export const createRunCommand = () => { // run compose environment (detached) const { cmd, config } = await startEnvironment({ + anvilArgs, blockTime, cpus, defaultBlock, diff --git a/apps/cli/src/compose/anvil.ts b/apps/cli/src/compose/anvil.ts index c1607fea..ca6c82f6 100644 --- a/apps/cli/src/compose/anvil.ts +++ b/apps/cli/src/compose/anvil.ts @@ -6,6 +6,7 @@ type ServiceOptions = { imageTag?: string; blockTime?: number; forkConfig?: ForkConfig; + extraArgs?: string[]; }; // Anvil service @@ -13,9 +14,10 @@ const service = (options?: ServiceOptions): Service => { const blockTime = options?.blockTime ?? 2; const imageTag = options?.imageTag ?? "latest"; const forkConfig = options?.forkConfig; + const extraArgs = options?.extraArgs ?? []; // command for fork and command for load-state local (non-fork) - const command = forkConfig + const baseCommand = forkConfig ? [ "anvil", "--chain-id", @@ -30,6 +32,9 @@ const service = (options?: ServiceOptions): Service => { ] : ["devnet", "--block-time", blockTime.toString()]; + // extra arguments passed verbatim to anvil + const command = [...baseCommand, ...extraArgs]; + // in case of forked network service is ready only when it responds with target block number const test = forkConfig?.blockNumber ? ["CMD", "eth_isready", forkConfig.blockNumber?.toString()] diff --git a/apps/cli/src/exec/rollups.ts b/apps/cli/src/exec/rollups.ts index 662ed12e..cef75b94 100644 --- a/apps/cli/src/exec/rollups.ts +++ b/apps/cli/src/exec/rollups.ts @@ -314,6 +314,7 @@ const serviceMonitorTask = (options: { }; export const startEnvironment = async (options: { + anvilArgs?: string[]; blockTime: number; cpus?: number; defaultBlock: "latest" | "safe" | "pending" | "finalized"; @@ -343,6 +344,7 @@ export const startEnvironment = async (options: { services, verbose, } = options; + const anvilArgs = options.anvilArgs ?? []; // setup the environment variable used in docker compose const env: NodeJS.ProcessEnv = { @@ -360,6 +362,7 @@ export const startEnvironment = async (options: { const files = [ anvil({ blockTime, + extraArgs: anvilArgs, forkConfig, imageTag: runtimeVersion, }), diff --git a/apps/cli/tests/unit/compose/anvil.test.ts b/apps/cli/tests/unit/compose/anvil.test.ts new file mode 100644 index 00000000..6c645edc --- /dev/null +++ b/apps/cli/tests/unit/compose/anvil.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it } from "bun:test"; +import anvil from "../../../src/compose/anvil.js"; + +describe("compose anvil", () => { + it("should run devnet with block time by default", () => { + const { services } = anvil(); + expect(services?.anvil?.command).toEqual([ + "devnet", + "--block-time", + "2", + ]); + }); + + it("should append extra args to devnet command", () => { + const { services } = anvil({ + blockTime: 5, + extraArgs: ["--slots-in-an-epoch=1", "--gas-limit", "60000000"], + }); + expect(services?.anvil?.command).toEqual([ + "devnet", + "--block-time", + "5", + "--slots-in-an-epoch=1", + "--gas-limit", + "60000000", + ]); + }); + + it("should append extra args to fork command", () => { + const { services } = anvil({ + forkConfig: { + url: "http://localhost:8545", + blockNumber: 10n, + chainId: 1, + }, + extraArgs: ["--slots-in-an-epoch=1"], + }); + expect(services?.anvil?.command).toEqual([ + "anvil", + "--chain-id", + "31337", + "--block-time", + "2", + "--fork-url", + "http://localhost:8545", + "--fork-block-number", + "10", + "--slots-in-an-epoch=1", + ]); + }); +}); From 8a670e212194fe455eeec72c5561e5b8bb85d05b Mon Sep 17 00:00:00 2001 From: Danilo Tuler Date: Tue, 6 Oct 2026 22:34:09 -0400 Subject: [PATCH 2/2] test(cli): raise timeout of docker builder integration tests The first build pulls the riscv64 base image on a cold docker cache, which can exceed bun's default 5s timeout on CI. Co-Authored-By: Claude Opus 5.5 --- apps/cli/tests/integration/builder/docker.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/cli/tests/integration/builder/docker.test.ts b/apps/cli/tests/integration/builder/docker.test.ts index 488b59fd..b97a1948 100644 --- a/apps/cli/tests/integration/builder/docker.test.ts +++ b/apps/cli/tests/integration/builder/docker.test.ts @@ -5,6 +5,7 @@ import { describe, expect, it, + setDefaultTimeout, } from "bun:test"; import fs from "fs-extra"; import path from "node:path"; @@ -14,6 +15,9 @@ import type { DockerDriveConfig } from "../../../src/config.js"; import { setupIntegrationTests, TEST_SDK } from "../config.js"; import { cleanupTempDir, createTempDir } from "./tmpdirTest.js"; +// building pulls the base image on a cold docker cache, which can exceed the default 5s timeout +setDefaultTimeout(60000); + beforeAll( async () => { tmp.setGracefulCleanup();