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

Add support for custom compilers in solc-typed-ast versions #273

Merged
merged 1 commit into from
Sep 16, 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
3 changes: 2 additions & 1 deletion src/bin/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
FunctionDefinition,
FunctionVisibility,
InferType,
isCustom,
isExact,
LatestCompilerVersion,
PathOptions,
Expand Down Expand Up @@ -193,7 +194,7 @@ function error(message: string): never {

const compilerVersion: string = options.compilerVersion;

if (!(compilerVersion === "auto" || isExact(compilerVersion))) {
if (!(compilerVersion === "auto" || isExact(compilerVersion) || isCustom(compilerVersion))) {
const message = [
`Invalid compiler version "${compilerVersion}".`,
'Possible values: "auto" or exact version string.'
Expand Down
107 changes: 58 additions & 49 deletions src/compile/kinds/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import path from "path";
import { CompilerKind, CompilerVersions } from "..";
import { assert } from "../../misc";
import { SolcInput } from "../input";
import { isExact } from "../version";
import { getCustomPath, isCustom, isExact } from "../version";
import {
BINARIES_URL,
CACHE_DIR,
Expand Down Expand Up @@ -97,71 +97,80 @@ export async function getCompilerForVersion<T extends CompilerMapping>(
version: string,
kind: T[0]
): Promise<T[1] | undefined> {
assert(
isExact(version),
"Version string must contain exact SemVer-formatted version without any operators"
);
let compilerLocalPath: string;

let prefix: string | undefined;

if (kind === CompilerKind.Native) {
prefix = getCompilerPrefixForOs();
} else if (kind === CompilerKind.WASM) {
prefix = "wasm";
if (isCustom(version)) {
compilerLocalPath = getCustomPath(version);
} else {
throw new Error(`Unsupported compiler kind "${kind}"`);
}
assert(
isExact(version),
"Version string must contain exact SemVer-formatted version without any operators"
);

assert(CompilerVersions.includes(version), `Unsupported ${kind} compiler version ${version}`);
let prefix: string | undefined;

if (prefix === undefined) {
return undefined;
}
if (kind === CompilerKind.Native) {
prefix = getCompilerPrefixForOs();
} else if (kind === CompilerKind.WASM) {
prefix = "wasm";
} else {
throw new Error(`Unsupported compiler kind "${kind}"`);
}

const md = await getCompilerMDForPlatform(prefix, version);
const compilerFileName = md.releases[version];
assert(
CompilerVersions.includes(version),
`Unsupported ${kind} compiler version ${version}`
);

if (compilerFileName === undefined) {
return undefined;
}
if (prefix === undefined) {
return undefined;
}

const md = await getCompilerMDForPlatform(prefix, version);
const compilerFileName = md.releases[version];

const compilerLocalPath = getCompilerLocalPath(prefix, compilerFileName);
if (compilerFileName === undefined) {
return undefined;
}

if (!fse.existsSync(compilerLocalPath)) {
const build = md.builds.find((b) => b.version === version);
compilerLocalPath = getCompilerLocalPath(prefix, compilerFileName);

assert(
build !== undefined,
`Unable to find build metadata for ${prefix} compiler ${version} in "list.json"`
);
if (!fse.existsSync(compilerLocalPath)) {
const build = md.builds.find((b) => b.version === version);

const response = await axios.get<ArrayBuffer>(
`${BINARIES_URL}/${prefix}/${compilerFileName}`,
{
responseType: "arraybuffer"
}
);
assert(
build !== undefined,
`Unable to find build metadata for ${prefix} compiler ${version} in "list.json"`
);

const response = await axios.get<ArrayBuffer>(
`${BINARIES_URL}/${prefix}/${compilerFileName}`,
{
responseType: "arraybuffer"
}
);

const buf = Buffer.from(response.data);
const buf = Buffer.from(response.data);

const hash = crypto.createHash("sha256");
const hash = crypto.createHash("sha256");

hash.update(buf);
hash.update(buf);

const digest = "0x" + hash.digest("hex");
const digest = "0x" + hash.digest("hex");

assert(
digest === build.sha256,
`Downloaded ${prefix} compiler ${version} hash ${digest} does not match hash ${build.sha256} from "list.json"`
);
assert(
digest === build.sha256,
`Downloaded ${prefix} compiler ${version} hash ${digest} does not match hash ${build.sha256} from "list.json"`
);

/**
* Native compilers are exeсutable files, so give them proper permissions.
* WASM compilers are loaded by NodeJS, so write them as readonly common files.
*/
const permissions = kind === CompilerKind.Native ? 0o555 : 0o444;
/**
* Native compilers are exeсutable files, so give them proper permissions.
* WASM compilers are loaded by NodeJS, so write them as readonly common files.
*/
const permissions = kind === CompilerKind.Native ? 0o555 : 0o444;

await fse.writeFile(compilerLocalPath, buf, { mode: permissions });
await fse.writeFile(compilerLocalPath, buf, { mode: permissions });
}
}

if (kind === CompilerKind.Native) {
Expand Down
15 changes: 14 additions & 1 deletion src/compile/version.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import semver from "semver";
import { assert } from "../misc";

const rx = {
comments: /\/\*[\s\S]*?\*\/|\/\/.*$/gm,
Expand All @@ -9,7 +10,8 @@ const rx = {
spaceDash: /( -)/g,

fixed: /^=?\d+\.\d+\.\d+$/,
exact: /^\d+.\d+.\d+$/
exact: /^\d+.\d+.\d+$/,
custom: /^custom:(.*)/
};

export function isFixed(version: string): boolean {
Expand All @@ -24,6 +26,17 @@ export function isExact(version: string): boolean {
return rx.exact.test(version);
}

export function isCustom(version: string): boolean {
return rx.custom.test(version);
}

export function getCustomPath(version: string): string {
const m = version.match(rx.custom);
assert(m !== null, `Bad custom version {0}`, version);

return m[1];
}

export function getCompilerVersionsBySpecifiers(
specifiers: string[],
versions: string[]
Expand Down
4 changes: 3 additions & 1 deletion src/types/infer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,9 @@ export class InferType {
return new UserDefinedType(getFQDefName(def), def);
}

throw new Error(`NYI converting user-defined AST type ${def.print()} to TypeNode`);
throw new Error(
`NYI converting user-defined AST type ${def != undefined ? def.print() : undefined} to TypeNode`
);
}

if (node instanceof FunctionTypeName) {
Expand Down