UNPKG

@truffle/compile-solidity

Version:
238 lines 10.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NoUrlError = exports.VersionRange = void 0; const debug_1 = __importDefault(require("debug")); const debug = debug_1.default("compile:compilerSupplier"); const require_from_string_1 = __importDefault(require("require-from-string")); const original_require_1 = __importDefault(require("original-require")); const axios_1 = __importDefault(require("axios")); const semver_1 = __importDefault(require("semver")); const wrapper_1 = __importDefault(require("solc/wrapper")); const Cache_1 = require("../Cache"); const observeListeners_1 = require("../observeListeners"); const errors_1 = require("../errors"); class VersionRange { constructor(options) { const defaultConfig = { compilerRoots: [ // NOTE this relay address exists so that we have a backup option in // case more official distribution mechanisms fail. // // currently this URL just redirects (302 Found); we may alter this to // host for real in the future. "https://relay.trufflesuite.com/solc/bin/", "https://solc-bin.ethereum.org/bin/", "https://ethereum.github.io/solc-bin/bin/" ] }; this.config = Object.assign({}, defaultConfig, options); this.cache = new Cache_1.Cache(); } load(versionRange) { return __awaiter(this, void 0, void 0, function* () { const rangeIsSingleVersion = semver_1.default.valid(versionRange); if (rangeIsSingleVersion && this.versionIsCached(versionRange)) { return this.getCachedSolcByVersionRange(versionRange); } try { return yield this.getSolcFromCacheOrUrl(versionRange); } catch (error) { if (error.message.includes("Failed to complete request")) { return this.getSatisfyingVersionFromCache(versionRange); } throw error; } }); } list() { return __awaiter(this, void 0, void 0, function* () { const data = yield this.getSolcVersions(); const { latestRelease } = data; const prereleases = data.builds .filter(build => build["prerelease"]) .map(build => build["longVersion"]); // ensure releases are listed in descending order const releases = semver_1.default.rsort(Object.keys(data.releases)); return { prereleases, releases, latestRelease }; }); } compilerFromString(code) { const listeners = observeListeners_1.observeListeners(); try { const soljson = require_from_string_1.default(code); return wrapper_1.default(soljson); } finally { listeners.cleanup(); } } findNewestValidVersion(version, allVersions) { return semver_1.default.maxSatisfying(Object.keys((allVersions === null || allVersions === void 0 ? void 0 : allVersions.releases) || {}), version); } getCachedSolcByFileName(fileName) { const listeners = observeListeners_1.observeListeners(); try { const filePath = this.cache.resolve(fileName); const soljson = original_require_1.default(filePath); debug("soljson %o", soljson); return wrapper_1.default(soljson); } finally { listeners.cleanup(); } } // Range can also be a single version specification like "0.5.0" getCachedSolcByVersionRange(version) { const cachedCompilerFileNames = this.cache.list(); const validVersions = cachedCompilerFileNames.filter(fileName => { const match = fileName.match(/v\d+\.\d+\.\d+.*/); if (match) return semver_1.default.satisfies(match[0], version); }); const multipleValidVersions = validVersions.length > 1; const compilerFileName = multipleValidVersions ? this.getMostRecentVersionOfCompiler(validVersions) : validVersions[0]; return this.getCachedSolcByFileName(compilerFileName); } getCachedSolcFileName(commit) { const cachedCompilerFileNames = this.cache.list(); return cachedCompilerFileNames.find(fileName => { return fileName.includes(commit); }); } getMostRecentVersionOfCompiler(versions) { return versions.reduce((mostRecentVersionFileName, fileName) => { const match = fileName.match(/v\d+\.\d+\.\d+.*/); const mostRecentVersionMatch = mostRecentVersionFileName.match(/v\d+\.\d+\.\d+.*/); return semver_1.default.gtr(match[0], mostRecentVersionMatch[0]) ? fileName : mostRecentVersionFileName; }, "-v0.0.0+commit"); } getSatisfyingVersionFromCache(versionRange) { if (this.versionIsCached(versionRange)) { return this.getCachedSolcByVersionRange(versionRange); } throw new errors_1.NoVersionError(versionRange); } getAndCacheSolcByUrl(fileName, index = 0) { return __awaiter(this, void 0, void 0, function* () { const url = `${this.config.compilerRoots[index].replace(/\/+$/, "")}/${fileName}`; const { events } = this.config; events.emit("downloadCompiler:start", { attemptNumber: index + 1 }); try { const response = yield axios_1.default.get(url, { maxRedirects: 50 }); events.emit("downloadCompiler:succeed"); this.cache.add(response.data, fileName); return this.compilerFromString(response.data); } catch (error) { events.emit("downloadCompiler:fail"); if (index >= this.config.compilerRoots.length - 1) { throw new errors_1.NoRequestError("compiler URLs", error); } return this.getAndCacheSolcByUrl(fileName, index + 1); } }); } getSolcFromCacheOrUrl(versionConstraint) { return __awaiter(this, void 0, void 0, function* () { let allVersions, versionToUse; try { allVersions = yield this.getSolcVersions(); } catch (error) { throw new errors_1.NoRequestError(versionConstraint, error); } const isVersionRange = !semver_1.default.valid(versionConstraint); versionToUse = isVersionRange ? this.findNewestValidVersion(versionConstraint, allVersions) : versionConstraint; const fileName = this.getSolcVersionFileName(versionToUse, allVersions); if (!fileName) throw new errors_1.NoVersionError(versionToUse); if (this.cache.has(fileName)) return this.getCachedSolcByFileName(fileName); return this.getAndCacheSolcByUrl(fileName); }); } getSolcVersions(index = 0) { const { events } = this.config; events.emit("fetchSolcList:start", { attemptNumber: index + 1 }); if (!this.config.compilerRoots || this.config.compilerRoots.length < 1) { events.emit("fetchSolcList:fail"); throw new NoUrlError(); } const { compilerRoots } = this.config; // trim trailing slashes from compilerRoot const url = `${compilerRoots[index].replace(/\/+$/, "")}/list.json`; return axios_1.default .get(url, { maxRedirects: 50 }) .then(response => { events.emit("fetchSolcList:succeed"); return response.data; }) .catch(error => { events.emit("fetchSolcList:fail"); if (index >= this.config.compilerRoots.length - 1) { throw new errors_1.NoRequestError("version URLs", error); } return this.getSolcVersions(index + 1); }); } getSolcVersionFileName(version, allVersions) { if (allVersions.releases[version]) return allVersions.releases[version]; const isPrerelease = version.includes("nightly") || version.includes("commit"); if (isPrerelease) { for (let build of allVersions.builds) { const exists = build["prerelease"] === version || build["build"] === version || build["longVersion"] === version; if (exists) return build["path"]; } } const versionToUse = this.findNewestValidVersion(version, allVersions); if (versionToUse) return allVersions.releases[versionToUse]; return null; } versionIsCached(version) { const cachedCompilerFileNames = this.cache.list(); const cachedVersions = cachedCompilerFileNames.map(fileName => { const match = fileName.match(/v\d+\.\d+\.\d+.*/); if (match) return match[0]; }).filter((version) => !!version); return cachedVersions.find(cachedVersion => semver_1.default.satisfies(cachedVersion, version)); } } exports.VersionRange = VersionRange; class NoUrlError extends Error { constructor() { super("compiler root URL missing"); } } exports.NoUrlError = NoUrlError; //# sourceMappingURL=VersionRange.js.map