Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate Zombienet for XCM development and testing #199

Merged
merged 10 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"ora": "6.3.1",
"semver": "7.5.4",
"shelljs": "0.8.5",
"toml": "^3.0.0",
"ts-mocha": "^10.0.0",
"winston": "^3.10.0"
},
Expand Down
43 changes: 42 additions & 1 deletion src/commands/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,47 @@ export class Init extends SwankyCommand<typeof Init> {
shibuya: { url: DEFAULT_SHIBUYA_NETWORK_URL },
},
contracts: {},
zombienet: {
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
version: "1.3.89",
downloadUrl: {
darwin: {
"arm64": "https://github.com/paritytech/zombienet/releases/download/v${version}/zombienet-macos",
"x64": "https://github.com/paritytech/zombienet/releases/download/v${version}/zombienet-macos"
},
linux: {
"arm64": "https://github.com/paritytech/zombienet/releases/download/v${version}/zombienet-linux-arm64",
"x64": "https://github.com/paritytech/zombienet/releases/download/v${version}/zombienet-linux-x64",
}
},
binaries: {
"polkadot": {
version: "0.9.43",
downloadUrl: {
darwin: {
"arm64": "https://github.com/paritytech/polkadot/releases/download/v${version}/polkadot",
"x64": "https://github.com/paritytech/polkadot/releases/download/v${version}/polkadot"
},
linux: {
"arm64": "https://github.com/paritytech/polkadot/releases/download/v${version}/polkadot",
"x64": "https://github.com/paritytech/polkadot/releases/download/v${version}/polkadot",
}
},
},
"astar-collator": {
version: "5.28.0",
downloadUrl: {
darwin: {
"arm64": "https://github.com/AstarNetwork/Astar/releases/download/v${version}/astar-collator-v${version}-macOS-x86_64.tar.gz",
"x64": "https://github.com/AstarNetwork/Astar/releases/download/v${version}/astar-collator-v${version}-macOS-x86_64.tar.gz"
},
linux: {
"arm64": "https://github.com/AstarNetwork/Astar/releases/download/v${version}/astar-collator-v${version}-ubuntu-aarch64.tar.gz",
"x64": "https://github.com/AstarNetwork/Astar/releases/download/v${version}/astar-collator-v${version}-ubuntu-x86_64.tar.gz",
}
},
},
},
},
};

taskQueue: Task[] = [];
Expand Down Expand Up @@ -220,7 +261,7 @@ export class Init extends SwankyCommand<typeof Init> {
callback(result as string);
}
}
this.log("🎉 😎 Swanky project successfully initialised! 😎 🎉");
this.log("🎉 😎 Swanky project successfully initialized! 😎 🎉");
}

async generate(projectName: string) {
Expand Down
66 changes: 66 additions & 0 deletions src/commands/zombienet/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import path from "node:path";
import { Flags } from "@oclif/core";
import { SwankyCommand } from "../../lib/swankyCommand.js";
import {
copyZombienetTemplateFile, downloadZombinetBinaries,
buildZombienetConfigFromBinaries,
getSwankyConfig,
getTemplates,
Spinner,
} from "../../lib/index.js";
import { pathExistsSync } from "fs-extra/esm";

export const zombienetConfig = "zombienet.config.toml";
export class InitZombienet extends SwankyCommand<typeof InitZombienet> {
static description = "Initialize Zomnienet";
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved

static flags = {
binaries: Flags.string({
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
char: "b",
multiple: true,
required: true,
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
description: "Binaries to install",
}),
}

async run(): Promise<void> {
const { flags } = await this.parse(InitZombienet);
await getSwankyConfig();
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved

const spinner = new Spinner(flags.verbose);

const projectPath = path.resolve();
if (pathExistsSync(path.resolve(projectPath, "zombienet", "bin", "zombienet"))) {
this.error("Zombienet config already initialized");
}

const zombienetTemplatePath = getTemplates().zombienetTemplatesPath;

const configPath = path.resolve(projectPath, "zombienet", "config")

if(!flags.binaries || flags.binaries.length < 2) {
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
await spinner.runCommand(
() =>
copyZombienetTemplateFile(zombienetTemplatePath, configPath),
"Copying template files"
);
}
else {
await spinner.runCommand(
() => buildZombienetConfigFromBinaries(flags.binaries, zombienetTemplatePath, configPath),
"Copying template files"
);
}

// Install binaries based on zombie config
await this.spinner.runCommand(
() => downloadZombinetBinaries(projectPath, this.swankyConfig, this.spinner),
"Downloading Zombienet binaries"
);



this.log("ZombieNet config Installed successfully");
}
}

42 changes: 42 additions & 0 deletions src/commands/zombienet/start.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { SwankyCommand } from "../../lib/swankyCommand.js";
import path from "node:path";
import { pathExistsSync } from "fs-extra/esm";
import { execaCommand } from "execa";
import inquirer from "inquirer";
import { readdirSync } from "fs";


export class StartZombienet extends SwankyCommand<typeof StartZombienet> {
static description = "Start Zomnienet";
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved

async run(): Promise<void> {
const projectPath = path.resolve();
const binPath = path.resolve(projectPath, "zombienet", "bin")
if (!pathExistsSync(path.resolve(binPath, "zombienet"))) {
this.error("Zombienet has not initialized. Run `swanky zombienet:init` first");
}

const zombienetConfigPath = path.resolve("zombienet", "config");

const configList = readdirSync(zombienetConfigPath);

const zombienetConfig = (await inquirer.prompt([{
name: "zombienetConfig",
type: "list",
choices: configList,
message: "Select a zombienet config to use",
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
}])).zombienetConfig;

await execaCommand(
`./zombienet/bin/zombienet \
spawn --provider native \
./zombienet/config/${zombienetConfig}
`,
{
stdio: "inherit",
}
);

this.log("ZombieNet started successfully");
}
}
117 changes: 116 additions & 1 deletion src/lib/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import process from "node:process";
import { nodeInfo } from "./nodeInfo.js";
import decompress from "decompress";
import { Spinner } from "./spinner.js";
import { SupportedPlatforms, SupportedArch } from "../types/index.js";
import { SupportedPlatforms, SupportedArch, SwankyConfig, ZombienetConfig } from "../types/index.js";
import { ConfigError, NetworkError } from "./errors.js";
import { BinaryNames } from "./zombienetInfo.js";
import { zombienetConfig } from "../commands/zombienet/init.js";
import { readFileSync } from "fs";
import TOML from "@iarna/toml";
import { writeFileSync } from "node:fs";

export async function checkCliDependencies(spinner: Spinner) {
const dependencyList = [
Expand Down Expand Up @@ -123,6 +128,116 @@ export async function downloadNode(projectPath: string, nodeInfo: nodeInfo, spin

return path.resolve(binPath, dlFileDetails.filePath);
}
export async function copyZombienetTemplateFile(templatePath: string, configPath: string) {
await ensureDir(configPath);
await copy(
path.resolve(templatePath, zombienetConfig),
path.resolve(configPath, zombienetConfig)
);
}
export async function downloadZombinetBinaries(projectPath: string, swankyConfig: SwankyConfig, spinner: Spinner) {
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
const binPath = path.resolve(projectPath, "zombienet", "bin");
await ensureDir(binPath);

const zombienetInfo = swankyConfig.zombienet;

const dlUrls = new Map<string, string>();
if (zombienetInfo.version) {
const version = zombienetInfo.version;
const binaryName = "zombienet";
const platformDlUrls = zombienetInfo.downloadUrl[process.platform as SupportedPlatforms];
if (!platformDlUrls)
throw new ConfigError(
`Could not download ${binaryName}. Platform ${process.platform} not supported!`
);
let dlUrl = platformDlUrls[process.arch as SupportedArch];
if (!dlUrl)
throw new ConfigError(
`Could not download ${binaryName}. Platform ${process.platform} Arch ${process.arch} not supported!`
);
dlUrl = dlUrl.replace("${version}", version);
dlUrls.set(binaryName, dlUrl);
}

for(const binaryName of Object.keys(zombienetInfo.binaries)){
const binaryInfo = zombienetInfo.binaries[binaryName as BinaryNames];
const version = binaryInfo.version;
const platformDlUrls = binaryInfo.downloadUrl[process.platform as SupportedPlatforms];
if (!platformDlUrls)
throw new ConfigError(
`Could not download ${binaryName}. Platform ${process.platform} not supported!`
);
let dlUrl = platformDlUrls[process.arch as SupportedArch];
if (!dlUrl)
throw new ConfigError(
`Could not download ${binaryName}. Platform ${process.platform} Arch ${process.arch} not supported!`
);
dlUrl = dlUrl.replace(/\$\{version\}/gi, version);
dlUrls.set(binaryName, dlUrl);
}

for (const [binaryName, dlUrl] of dlUrls) {
const dlFileDetails = await new Promise<DownloadEndedStats>((resolve, reject) => {
const dl = new DownloaderHelper(dlUrl, binPath);

dl.on("progress", (event) => {
spinner.text(`Downloading ${binaryName} ${event.progress.toFixed(2)}%`);
});
dl.on("end", (event) => {
resolve(event);
});
dl.on("error", (error) => {
reject(new Error(`Error downloading ${binaryName}: , ${error.message}`));
});

dl.start().catch((error: Error) =>
reject(new Error(`Error downloading ${binaryName}: , ${error.message}`))
);
});

if (dlFileDetails.incomplete) {
throw new NetworkError("${binaryName} download incomplete");
}

let fileName = dlFileDetails.fileName;

if (dlFileDetails.filePath.endsWith(".tar.gz")) {
const compressedFilePath = path.resolve(binPath, dlFileDetails.filePath);
const decompressed = await decompress(compressedFilePath, binPath);
await remove(compressedFilePath);
fileName = decompressed[0].path;
}

if(fileName !== binaryName)
{
await execaCommand(`mv ${binPath}/${fileName} ${binPath}/${binaryName}`)
}
await execaCommand(`chmod +x ${binPath}/${binaryName}`);
}
}

export async function buildZombienetConfigFromBinaries(binaries: string[], templatePath: string, configPath: string) {
await ensureDir(configPath);
let configBuilder = {
settings: {
timeout: 1000
},
relaychain:{
default_command: "",
chain: "",
nodes: []
},
parachains:[],
hrmp_channels:[]
} as ZombienetConfig;

for (const binaryName of binaries) {
const tamplate = TOML.parse(readFileSync(path.resolve(templatePath, binaryName+".toml"), "utf8"));
configBuilder = {...configBuilder, ...tamplate};
}

writeFileSync(path.resolve(configPath, zombienetConfig), TOML.stringify(configBuilder as any));
}

export async function installDeps(projectPath: string) {
let installCommand = "npm install";
Expand Down
2 changes: 2 additions & 0 deletions src/lib/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const __dirname = path.dirname(__filename);
export function getTemplates() {
const templatesPath = path.resolve(__dirname, "..", "templates");
const contractTemplatesPath = path.resolve(templatesPath, "contracts");
const zombienetTemplatesPath = path.resolve(templatesPath, "zombienet");
const fileList = readdirSync(contractTemplatesPath, {
withFileTypes: true,
});
Expand All @@ -19,5 +20,6 @@ export function getTemplates() {
templatesPath,
contractTemplatesPath,
contractTemplatesList,
zombienetTemplatesPath,
};
}
44 changes: 44 additions & 0 deletions src/lib/zombienetInfo.ts
ipapandinas marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export type zombienetInfo = typeof zombienetBins;

export type BinaryNames = "zombienet" | "polkadot" | "astar-collator";
export const zombienetBins = {
"zombienet": {
version: "1.3.89",
downloadUrl: {
darwin: {
"arm64": "https://github.com/paritytech/zombienet/releases/download/v1.3.89/zombienet-macos",
"x64": "https://github.com/paritytech/zombienet/releases/download/v1.3.89/zombienet-macos"
},
linux: {
"arm64": "https://github.com/paritytech/zombienet/releases/download/v1.3.89/zombienet-linux-arm64",
"x64": "https://github.com/paritytech/zombienet/releases/download/v1.3.89/zombienet-linux-x64",
}
},
},
"polkadot": {
version: "0.9.43",
downloadUrl: {
darwin: {
"arm64": "https://github.com/paritytech/polkadot/releases/download/v0.9.43/polkadot",
"x64": "https://github.com/paritytech/polkadot/releases/download/v0.9.43/polkadot",
},
linux: {
"arm64": "https://github.com/paritytech/polkadot/releases/download/v0.9.43/polkadot",
"x64": "https://github.com/paritytech/polkadot/releases/download/v0.9.43/polkadot",
}
}
},
"astar-collator": {
version: "5.28.0",
downloadUrl: {
darwin: {
"arm64": "https://github.com/AstarNetwork/Astar/releases/download/v5.28.0/astar-collator-v5.28.0-macOS-x86_64.tar.gz",
"x64": "https://github.com/AstarNetwork/Astar/releases/download/v5.28.0/astar-collator-v5.28.0-macOS-x86_64.tar.gz",
},
linux: {
"arm64": "https://github.com/AstarNetwork/Astar/releases/download/v5.28.0/astar-collator-v5.28.0-ubuntu-aarch64.tar.gz",
"x64": "https://github.com/AstarNetwork/Astar/releases/download/v5.28.0/astar-collator-v5.28.0-ubuntu-x86_64.tar.gz",
}
}
}
};
Loading