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

Detect build mode from metadata on deploy #193

Merged
merged 5 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions src/commands/contract/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { spawn } from "node:child_process";
import { pathExists } from "fs-extra/esm";
import { SwankyCommand } from "../../lib/swankyCommand.js";
import { ConfigError, InputError, ProcessError } from "../../lib/errors.js";
import { BuildMode } from "../../index.js";

export class CompileContract extends SwankyCommand<typeof CompileContract> {
static description = "Compile the smart contract(s) in your contracts directory";
Expand Down Expand Up @@ -63,6 +64,7 @@ export class CompileContract extends SwankyCommand<typeof CompileContract> {
throw new InputError(`Contract folder not found at expected path`);
}

let buildMode = BuildMode.Debug;
const compilationResult = await spinner.runCommand(
async () => {
return new Promise<string>((resolve, reject) => {
Expand All @@ -73,9 +75,11 @@ export class CompileContract extends SwankyCommand<typeof CompileContract> {
`contracts/${contractName}/Cargo.toml`,
];
if (flags.release && !flags.verifiable) {
buildMode = BuildMode.Release;
compileArgs.push("--release");
}
if (flags.verifiable) {
buildMode = BuildMode.Verifiable;
const cargoContractVersion = extractCargoContractVersion();
if (cargoContractVersion === null)
throw new InputError(
Expand Down Expand Up @@ -135,6 +139,7 @@ export class CompileContract extends SwankyCommand<typeof CompileContract> {
this.swankyConfig.contracts[contractName].build = {
timestamp: Date.now(),
artifactsPath,
buildMode,
isVerified: false,
};

Expand Down
33 changes: 30 additions & 3 deletions src/commands/contract/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Args, Flags } from "@oclif/core";
import path from "node:path";
import { writeJSON } from "fs-extra/esm";
import { cryptoWaitReady } from "@polkadot/util-crypto/crypto";
import { resolveNetworkUrl, ChainApi, ChainAccount, decrypt, AbiType } from "../../lib/index.js";
import { Encrypted } from "../../types/index.js";
import { AbiType, ChainAccount, ChainApi, decrypt, resolveNetworkUrl } from "../../lib/index.js";
import { BuildMode, Encrypted } from "../../types/index.js";
import inquirer from "inquirer";
import chalk from "chalk";
import { Contract } from "../../lib/contract.js";
import { SwankyCommand } from "../../lib/swankyCommand.js";
import { ApiError, ConfigError, FileError } from "../../lib/errors.js";
import { ApiError, ConfigError, FileError, ProcessError } from "../../lib/errors.js";

export class DeployContract extends SwankyCommand<typeof DeployContract> {
static description = "Deploy contract to a running node";
Expand Down Expand Up @@ -70,6 +70,33 @@ export class DeployContract extends SwankyCommand<typeof DeployContract> {
);
}

if (contract.buildMode === undefined) {
throw new ProcessError(
`Build mode is undefined for contract ${args.contractName}. Please ensure the contract is correctly compiled.`
);
} else if (contract.buildMode !== BuildMode.Verifiable) {
await inquirer
.prompt([
{
type: "confirm",
message: `You are deploying a not verified contract in ${
contract.buildMode === BuildMode.Release ? "release" : "debug"
} mode. Are you sure you want to continue?`,
name: "confirm",
},
])
.then((answers) => {
if (!answers.confirm) {
this.log(
`${chalk.redBright("✖")} Aborted deployment of ${chalk.yellowBright(
args.contractName
)}`
);
process.exit(0);
}
});
}

const accountData = this.findAccountByAlias(flags.account);
const mnemonic = accountData.isDev
? (accountData.mnemonic as string)
Expand Down
4 changes: 2 additions & 2 deletions src/commands/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ async function detectModuleNames(copyList: CopyCandidates): Promise<CopyCandidat
entry.dirent.isDirectory() &&
(await pathExists(path.resolve(entry.path, "Cargo.toml")))
) {
const fileData = await readFile(path.resolve(entry.path, "Cargo.toml"), "utf-8");
const fileData = await readFile(path.resolve(entry.path, "Cargo.toml"), "utf8");
const toml: any = TOML.parse(fileData);
if (toml.package?.name) {
extendedEntry.moduleName = toml.package.name;
Expand Down Expand Up @@ -564,7 +564,7 @@ async function detectTests(pathToExistingProject: string): Promise<string | unde
async function readRootCargoToml(pathToProject: string) {
const rootTomlPath = path.resolve(pathToProject, "Cargo.toml");
if (!(await pathExists(rootTomlPath))) return null;
const fileData = await readFile(rootTomlPath, "utf-8");
const fileData = await readFile(rootTomlPath, "utf8");
const toml: any = TOML.parse(fileData);

if (!toml.workspace) toml.workspace = {};
Expand Down
51 changes: 26 additions & 25 deletions src/lib/contract.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AbiType, consts, printContractInfo } from "./index.js";
import { ContractData, DeploymentData } from "../types/index.js";
import { BuildMode, ContractData, DeploymentData } from "../types/index.js";
import { pathExists, readJSON } from "fs-extra/esm";
import path from "node:path";
import { FileError } from "./errors.js";
Expand All @@ -11,63 +11,64 @@ export class Contract {
deployments: DeploymentData[];
contractPath: string;
artifactsPath: string;
buildMode?: BuildMode;

constructor(contractRecord: ContractData) {
this.name = contractRecord.name;
this.moduleName = contractRecord.moduleName;
this.deployments = contractRecord.deployments;
this.contractPath = path.resolve("contracts", contractRecord.name);
this.artifactsPath = path.resolve(consts.ARTIFACTS_PATH, contractRecord.name);
this.buildMode = contractRecord.build?.buildMode;
}

async pathExists() {
return pathExists(this.contractPath);
}

async artifactsExist() {
const result: { result: boolean; missingPaths: string[]; missingTypes: string[] } = {
result: true,
missingPaths: [],
missingTypes: [],
};

async artifactsExist(): Promise<{ result: boolean; missingPaths: string[] }> {
const missingPaths: string[] = [];
let result = true;

for (const artifactType of Contract.artifactTypes) {
const artifactPath = path.resolve(this.artifactsPath, `${this.moduleName}${artifactType}`);

if (!(await pathExists(artifactPath))) {
result.result = false;
result.missingPaths.push(artifactPath);
result.missingTypes.push(artifactType);
result = false;
missingPaths.push(artifactPath);
}
}
return result;

return { result, missingPaths };
}

async getABI(): Promise<AbiType> {
const check = await this.artifactsExist();
if (!check.result && check.missingTypes.includes(".json")) {
throw new FileError(`Cannot read ABI, path not found: ${check.missingPaths.toString()}`);
}
return readJSON(path.resolve(this.artifactsPath, `${this.moduleName}.json`));
const jsonArtifactPath = `${this.moduleName}.json`;
await this.ensureArtifactExists(jsonArtifactPath);
return readJSON(path.resolve(this.artifactsPath, jsonArtifactPath));
}

async getBundle() {
const check = await this.artifactsExist();
if (!check.result && check.missingTypes.includes(".contract")) {
throw new FileError(
`Cannot read .contract bundle, path not found: ${check.missingPaths.toString()}`
);
}
return readJSON(path.resolve(this.artifactsPath, `${this.moduleName}.contract`), 'utf-8');
const contractArtifactPath = `${this.moduleName}.contract`;
await this.ensureArtifactExists(contractArtifactPath);
return readJSON(path.resolve(this.artifactsPath, contractArtifactPath), 'utf8');
}

async getWasm(): Promise<Buffer> {
const bundle = await this.getBundle();
if (bundle.source?.wasm) return bundle.source.wasm;

throw new FileError(`Cannot find wasm field in the .contract bundle!`);
}

async printInfo(): Promise<void> {
const abi = await this.getABI();
printContractInfo(abi);
}

private async ensureArtifactExists(artifactFileName: string): Promise<void> {
const artifactPath = path.resolve(this.artifactsPath, artifactFileName);
if (!(await pathExists(artifactPath))) {
throw new FileError(`Artifact file not found at path: ${artifactPath}`);
}
}
}
7 changes: 7 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface ContractData {
export interface BuildData {
timestamp: number;
artifactsPath: string;
buildMode: BuildMode;
isVerified: boolean;
}

Expand All @@ -51,5 +52,11 @@ export interface SwankyConfig {
networks: Record<string, {url: string}>
}

export enum BuildMode {
Debug = "Debug",
Release = "Release",
Verifiable = "Verifiable",
}

export type SupportedPlatforms = "darwin" | "linux";
export type SupportedArch = "arm64" | "x64";
Loading