Skip to content

Commit

Permalink
Feat/fork test (#443)
Browse files Browse the repository at this point in the history
* feat: ✨ Added default fork config

* feat: ♻️ Overhaul command parsing

* refactor: ♻️ Refactor to use invariant

* test: ✅ Added fork test to CI

* test: ✅ add fork test

* refactor: ♻️ Fix block arg
  • Loading branch information
timbrinded authored Nov 27, 2024
1 parent 9e53242 commit c792425
Show file tree
Hide file tree
Showing 43 changed files with 404 additions and 170 deletions.
11 changes: 11 additions & 0 deletions .changeset/lucky-boats-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@moonwall/types": major
"@moonwall/cli": major
"@moonwall/tests": major
"@moonwall/docs": major
"@moonwall/util": major
---

Added Fork config to dev foundations

- BETA: Added ability to use moonbeam's fork API both via moonwall.config and also in a test
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
strategy:
fail-fast: false
matrix:
suite: ["dev_test", "dev_multi", "dev_seq", "dev_smoke", "papi_dev"]
suite: ["dev_test", "dev_multi", "dev_seq", "dev_smoke", "papi_dev", "fork_test"]
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
Expand Down
7 changes: 1 addition & 6 deletions docs/guide/intro/foundations.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,4 @@ Use Read Only if Moonwall doesn't need to start any networks - you've already go

::: tip
Zombie is the ideal Foundation for testing cross chain interactions including XCM.
:::


### Fork:

- 🚧 Not yet implemented! Will be part of a new way of forking the network with a real client.
:::
1 change: 0 additions & 1 deletion docs/guide/intro/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ This isn't too important as you will always be able to create new environment sp
- `chopsticks` : Using Acala Foundation's Chopsticks to start a lazily-forked network.
- `read_only`: Not starting a network but instead connecting to one that already exists.
- `zombie`: Using ParityTech's ZombieNetwork framework to run a multi-node network
- `fork` : 🚧 Not yet implemented! Will be part of a new way of forking the network with a real client

::: tip
This is the very brief rundown of foundations. For their specific information please visit the relevant sections in [Config](/guide/intro/foundations).
Expand Down
3 changes: 1 addition & 2 deletions packages/cli/src/cmds/runTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ export async function executeTests(env: Environment, testRunArgs?: testRunArgs)
const testFileDir =
additionalArgs?.subDirectory !== undefined
? env.testFileDir.map((folder) =>
// @ts-expect-error - bug in tsc
path.join(folder, additionalArgs.subDirectory)
path.join(folder, additionalArgs.subDirectory || "error")
)
: env.testFileDir;

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/internal/cmdFunctions/initialisation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export function createConfig(options: {
testFileDir: [options.testDir],
foundation: {
type: options.foundation as any,
},
} as any,
},
],
};
Expand Down
151 changes: 122 additions & 29 deletions packages/cli/src/internal/commandParsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import type {
DevLaunchSpec,
RepoSpec,
ZombieLaunchSpec,
LaunchOverrides,
ForkConfig,
} from "@moonwall/types";
import chalk from "chalk";
import path from "node:path";
import { standardRepos } from "../lib/repoDefinitions";
import invariant from "tiny-invariant";

export function parseZombieCmd(launchSpec: ZombieLaunchSpec) {
if (launchSpec) {
Expand Down Expand Up @@ -38,42 +41,127 @@ function fetchDefaultArgs(binName: string, additionalRepos: RepoSpec[] = []): st
return defaultArgs;
}

export async function parseRunCmd(launchSpec: DevLaunchSpec, additionalRepos?: RepoSpec[]) {
const launch = !launchSpec.running ? true : launchSpec.running;
const cmd = launchSpec.binPath;
const args = launchSpec.options
? [...launchSpec.options]
: fetchDefaultArgs(path.basename(launchSpec.binPath), additionalRepos);

if (launchSpec.ports) {
const ports = launchSpec.ports;
if (ports.p2pPort) {
args.push(`--port=${ports.p2pPort}`);
export class LaunchCommandParser {
private args: string[];
private cmd: string;
private launch: boolean;
private launchSpec: DevLaunchSpec;
private additionalRepos?: RepoSpec[];
private launchOverrides?: LaunchOverrides;

constructor(options: {
launchSpec: DevLaunchSpec;
additionalRepos?: RepoSpec[];
launchOverrides?: LaunchOverrides;
}) {
const { launchSpec, additionalRepos, launchOverrides } = options;
this.launchSpec = launchSpec;
this.additionalRepos = additionalRepos;
this.launchOverrides = launchOverrides;
this.launch = !launchSpec.running ? true : launchSpec.running;
this.cmd = launchSpec.binPath;
this.args = launchSpec.options
? [...launchSpec.options]
: fetchDefaultArgs(path.basename(launchSpec.binPath), additionalRepos);
}

private overrideArg(newArg: string): void {
const newArgKey = newArg.split("=")[0];
const existingIndex = this.args.findIndex((arg) => arg.startsWith(`${newArgKey}=`));

if (existingIndex !== -1) {
this.args[existingIndex] = newArg;
} else {
this.args.push(newArg);
}
if (ports.wsPort) {
args.push(`--ws-port=${ports.wsPort}`);
}

withPorts() {
if (this.launchSpec.ports) {
const ports = this.launchSpec.ports;
if (ports.p2pPort) {
this.overrideArg(`--port=${ports.p2pPort}`);
}
if (ports.wsPort) {
this.overrideArg(`--ws-port=${ports.wsPort}`);
}
if (ports.rpcPort) {
this.overrideArg(`--rpc-port=${ports.rpcPort}`);
}
} else {
const freePort = getFreePort().toString();
process.env.MOONWALL_RPC_PORT = freePort;

if (this.launchSpec.newRpcBehaviour) {
this.overrideArg(`--rpc-port=${freePort}`);
} else {
this.overrideArg(`--ws-port=${freePort}`);
}
}
if (ports.rpcPort) {
args.push(`--rpc-port=${ports.rpcPort}`);
return this;
}

withDefaultForkConfig(): LaunchCommandParser {
const forkOptions = this.launchSpec.defaultForkConfig;
if (forkOptions) {
this.applyForkOptions(forkOptions);
}
} else {
const freePort = (await getFreePort()).toString();
process.env.MOONWALL_RPC_PORT = freePort;
return this;
}

if (launchSpec.newRpcBehaviour) {
args.push(`--rpc-port=${freePort}`);
} else {
args.push(`--ws-port=${freePort}`);
withLaunchOverrides(): LaunchCommandParser {
if (this.launchOverrides?.forkConfig) {
this.applyForkOptions(this.launchOverrides.forkConfig);
}
return this;
}
return { cmd, args, launch };
}

export const getFreePort = async () => {
const notionalPort = 10000 + Number(process.env.VITEST_POOL_ID || 1) * 100;
// return getPort({ port: notionalPort });
return notionalPort;
};
private print() {
console.log(chalk.cyan(`Command to run is: ${chalk.bold(this.cmd)}`));
console.log(chalk.cyan(`Arguments are: ${chalk.bold(this.args.join(" "))}`));
return this;
}

private applyForkOptions(forkOptions: ForkConfig): void {
if (forkOptions.url) {
invariant(forkOptions.url.startsWith("http"), "Fork URL must start with http:// or https://");
this.overrideArg(`--fork-chain-from-rpc=${forkOptions.url}`);
}
if (forkOptions.blockHash) {
this.overrideArg(`--block=${forkOptions.blockHash}`);
}
if (forkOptions.stateOverridePath) {
this.overrideArg(`--fork-state-overrides=${forkOptions.stateOverridePath}`);
}
if (forkOptions.verbose) {
this.overrideArg("-llazy-loading=trace");
}
}

build(): { cmd: string; args: string[]; launch: boolean } {
return {
cmd: this.cmd,
args: this.args,
launch: this.launch,
};
}

static create(options: {
launchSpec: DevLaunchSpec;
additionalRepos?: RepoSpec[];
launchOverrides?: LaunchOverrides;
verbose?: boolean;
}) {
const parser = new LaunchCommandParser(options);
const parsed = parser.withPorts().withDefaultForkConfig().withLaunchOverrides();

if (options.verbose) {
parsed.print();
}

return parsed.build();
}
}

export function parseChopsticksRunCmd(launchSpecs: ChopsticksLaunchSpec[]): {
cmd: string;
Expand Down Expand Up @@ -132,3 +220,8 @@ export function parseChopsticksRunCmd(launchSpecs: ChopsticksLaunchSpec[]): {
launch,
};
}

export const getFreePort = () => {
const notionalPort = 10000 + Number(process.env.VITEST_POOL_ID || 1) * 100;
return notionalPort;
};
Loading

0 comments on commit c792425

Please sign in to comment.