From f4663486265ee41c09914ae5e030bc57532840a2 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 1 Oct 2020 14:54:26 -0400 Subject: [PATCH 01/39] WIP - Add method to profiler for getting imports for a single file source --- .../compile-common/src/profiler/profiler.ts | 25 ++++++++++++++++--- packages/compile-solidity/profiler/index.js | 14 +++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/compile-common/src/profiler/profiler.ts b/packages/compile-common/src/profiler/profiler.ts index 5ed7cd4df21..657b8c81567 100644 --- a/packages/compile-common/src/profiler/profiler.ts +++ b/packages/compile-common/src/profiler/profiler.ts @@ -1,4 +1,3 @@ -import path from "path"; const findContracts = require("@truffle/contract-sources"); const expect = require("@truffle/expect"); @@ -57,8 +56,8 @@ export class Profiler { const updatedPaths = convertToAbsolutePaths(paths, basePath); const allPaths = convertToAbsolutePaths( - await findContracts(options.contracts_directory), - options.base_path + await findContracts(contractsDirectory), + basePath ); return await requiredSources({ @@ -69,4 +68,24 @@ export class Profiler { allPaths }); } + + async requiredSourcesForSingleFile(options: any) { + expect.options(options, ["path", "base_path", "resolver"]); + + const { resolver, path, base_path: basePath } = options; + + const resolve = ({ filePath, importedFrom }: UnresolvedSource) => + resolver.resolve(filePath, importedFrom); + + const allPaths = convertToAbsolutePaths([path], basePath); + const updatedPaths = allPaths; + + return await requiredSources({ + resolve, + parseImports: this.config.parseImports, + shouldIncludePath: this.config.shouldIncludePath, + updatedPaths, + allPaths + }); + } } diff --git a/packages/compile-solidity/profiler/index.js b/packages/compile-solidity/profiler/index.js index 64a8e9ef533..23e85df8882 100644 --- a/packages/compile-solidity/profiler/index.js +++ b/packages/compile-solidity/profiler/index.js @@ -26,5 +26,19 @@ module.exports = { // invoke profiler return await profiler.requiredSources(options); + }, + + requiredSourcesForSingleFile: async options => { + // get parser + const parseImports = await loadParser(options); + + // generate profiler + const profiler = new Common.Profiler({ + parseImports, + shouldIncludePath + }); + + // invoke profiler + return await profiler.requiredSourcesForSingleFile(options); } }; From 56847e520b395fc45a87486240b765d51ef7c312 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 1 Oct 2020 14:56:31 -0400 Subject: [PATCH 02/39] WIP - First draft of analyzeImports code --- packages/compile-solidity/index.js | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/packages/compile-solidity/index.js b/packages/compile-solidity/index.js index 9099acfe1cc..10948f6cc54 100644 --- a/packages/compile-solidity/index.js +++ b/packages/compile-solidity/index.js @@ -37,6 +37,55 @@ const normalizeOptions = options => { return options; }; +const analyzeImports = async ({ paths, options }) => { + const dependencies = {}; + for (const path of paths) { + const config = Config.default().merge(options); + const { allSources, compilationTargets } = await Profiler.requiredSourcesForSingleFile( + config.with({ + path, + base_path: options.contracts_directory, + resolver: options.resolver + }) + ); + dependencies[path] = [allSources]; + } + + let pragmas; + // key is a source - value is an array of pragmas + for (const compilationSet of Object.keys(dependencies)) { + pragmas = await getPragmas(compilationSet); + } + + let bestSolcVersions; + // key is source - value is best satisfying version of Solidity compiler + for (const pragmaSet of pragmas) { + bestSolcVersions = determineBestSatisfyingSolcVersion(); + } + + let compilations; + for (const version of bestSolcVersions) { + const compilation = await run( + // const { sourceIndexes, contracts, compiler } = await run( + allSources, + normalizeOptions(options) + ); + const { name, version } = compiler; + // returns CompilerResult - see @truffle/compile-common + return contracts.length > 0 + ? { + compilations: [ + { + sourceIndexes, + contracts, + compiler: { name, version } + } + ] + } + : { compilations: [] }; + } +} + const Compile = { // this takes an object with keys being the name and values being source // material as well as an options object @@ -74,6 +123,9 @@ const Compile = { // this takes an array of paths and options async sourcesWithDependencies({ paths, options }) { + if (options.analyzeImports) { + await analyzeImports({ paths, options }); + } options.logger = options.logger || console; options.contracts_directory = options.contracts_directory || process.cwd(); From 57dae0fc6e6221216fd0bfec4ff968df0e7c5c05 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 1 Oct 2020 14:58:17 -0400 Subject: [PATCH 03/39] WIP --- packages/compile-solidity/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/compile-solidity/index.js b/packages/compile-solidity/index.js index 10948f6cc54..75704080cf8 100644 --- a/packages/compile-solidity/index.js +++ b/packages/compile-solidity/index.js @@ -41,7 +41,7 @@ const analyzeImports = async ({ paths, options }) => { const dependencies = {}; for (const path of paths) { const config = Config.default().merge(options); - const { allSources, compilationTargets } = await Profiler.requiredSourcesForSingleFile( + const { allSources } = await Profiler.requiredSourcesForSingleFile( config.with({ path, base_path: options.contracts_directory, @@ -60,19 +60,17 @@ const analyzeImports = async ({ paths, options }) => { let bestSolcVersions; // key is source - value is best satisfying version of Solidity compiler for (const pragmaSet of pragmas) { - bestSolcVersions = determineBestSatisfyingSolcVersion(); + bestSolcVersions = determineBestSatisfyingSolcVersion(pragmaSet); } let compilations; for (const version of bestSolcVersions) { const compilation = await run( - // const { sourceIndexes, contracts, compiler } = await run( allSources, normalizeOptions(options) ); const { name, version } = compiler; - // returns CompilerResult - see @truffle/compile-common - return contracts.length > 0 + return compilation.contracts.length > 0 ? { compilations: [ { @@ -84,7 +82,7 @@ const analyzeImports = async ({ paths, options }) => { } : { compilations: [] }; } -} +}; const Compile = { // this takes an object with keys being the name and values being source From 163dabfbf75a3385c96e6bf643403cc28b5d54c0 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 1 Oct 2020 20:23:22 -0400 Subject: [PATCH 04/39] Create analyzeImports utility for compile-solidity --- packages/compile-solidity/analyzeImports.js | 131 ++++++++++++++++++ packages/compile-solidity/index.js | 85 +----------- packages/compile-solidity/normalizeOptions.js | 35 +++++ 3 files changed, 171 insertions(+), 80 deletions(-) create mode 100644 packages/compile-solidity/analyzeImports.js create mode 100644 packages/compile-solidity/normalizeOptions.js diff --git a/packages/compile-solidity/analyzeImports.js b/packages/compile-solidity/analyzeImports.js new file mode 100644 index 00000000000..a6e8363ad9c --- /dev/null +++ b/packages/compile-solidity/analyzeImports.js @@ -0,0 +1,131 @@ +const CompilerSupplier = require("./compilerSupplier"); +const semver = require("semver"); +const Profiler = require("./profiler"); +const { normalizeOptions } = require("./normalizeOptions"); +const fse = require("fs-extra"); +const { run } = require("./run"); + +const getSemverExpression = source => { + return source.match(/pragma solidity(.*);/)[1].trim(); +}; + +const getSemverExpressions = sources => { + return sources.map(source => { + return getSemverExpression(source); + }); +}; + +const determineSolcVersionRange = ranges => { + const splitRanges = ranges.map(range => range.split("||")); + const singletons = splitRanges.map(list => list.map(x => [x.trim()])); + const tuples = singletons.reduce( + (list1, list2) => { + const pairs = []; + for (const l1 of list1) { + for (const l2 of list2) { + pairs.push([...l1, ...l2]); + } + } + return pairs; + }, + [[]] + ); + const disjuncts = tuples.map(tuple => tuple.join(" ")); + return disjuncts.join(" || "); +}; + +const findNewestSatisfyingVersion = ({ solcReleases, versionRange }) => { + // releases are ordered from newest to oldest + const version = solcReleases.find(version => + semver.satisfies(version, versionRange) + ); + if (typeof version === "undefined") { + throw new Error(` + Could not find a version of the Solidity compiler that satisfies all + of the pragma statements for ${source} and its dependencies. + `); + } + return version; +}; + +const analyzeImports = async ({ paths, options }) => { + const supplierOptions = { + events: options.events, + solcConfig: options.compilers.solc + }; + const compilerSupplier = new CompilerSupplier(supplierOptions); + const { releases } = await compilerSupplier.getReleases(); + + const dependencies = {}; + // for each source, collect all its dependencies + for (const path of paths) { + const source = await fse.readFile(path, "utf8"); + const parserVersion = findNewestSatisfyingVersion({ + solcReleases: releases, + versionRange: getSemverExpression(source) + }); + + const { allSources } = await Profiler.requiredSourcesForSingleFile( + options.with({ + path, + base_path: options.contracts_directory, + resolver: options.resolver, + compilers: { + solc: { + version: parserVersion + } + } + }) + ); + dependencies[path] = allSources; + } + + const semverExpressions = {}; + // for each group of sources, collect all the semver expression from pragmas + // key is a source - value is an array of pragmas + for (const source of Object.keys(dependencies)) { + const deps = Object.values(dependencies[source]); + semverExpressions[source] = await getSemverExpressions(deps); + } + + const solcVersionRange = {}; + // for each pragma group, determine the most recent satisfying version + // key is source - value is a version of the Solidity compiler + for (const source of Object.keys(semverExpressions)) { + solcVersionRange[source] = determineSolcVersionRange( + semverExpressions[source] + ); + } + + const versionsToUse = {}; + for (const source of Object.keys(solcVersionRange)) { + versionsToUse[source] = findNewestSatisfyingVersion({ + solcReleases: releases, + versionRange: solcVersionRange[source] + }); + } + + let compilations = []; + for (const source of Object.keys(versionsToUse)) { + const compilationOptions = options.merge({ + compilers: { + solc: { + version: versionsToUse[source] + } + } + }); + + const compilation = await run( + dependencies[source], + normalizeOptions(compilationOptions) + ); + if (compilation.contracts.length > 0) { + compilations.push(compilation); + } + } + return { compilations }; +}; + +module.exports = { + analyzeImports +}; diff --git a/packages/compile-solidity/index.js b/packages/compile-solidity/index.js index 75704080cf8..9f8e0f1f5fd 100644 --- a/packages/compile-solidity/index.js +++ b/packages/compile-solidity/index.js @@ -1,88 +1,13 @@ const debug = require("debug")("compile"); // eslint-disable-line no-unused-vars const path = require("path"); -const expect = require("@truffle/expect"); const findContracts = require("@truffle/contract-sources"); const Config = require("@truffle/config"); const Profiler = require("./profiler"); const CompilerSupplier = require("./compilerSupplier"); const { run } = require("./run"); - -const normalizeOptions = options => { - if (options.logger === undefined) options.logger = console; - - expect.options(options, ["contracts_directory", "compilers"]); - expect.options(options.compilers, ["solc"]); - - options.compilers.solc.settings.evmVersion = - options.compilers.solc.settings.evmVersion || - options.compilers.solc.evmVersion; - options.compilers.solc.settings.optimizer = - options.compilers.solc.settings.optimizer || - options.compilers.solc.optimizer || - {}; - - // Grandfather in old solc config - if (options.solc) { - options.compilers.solc.settings.evmVersion = options.solc.evmVersion; - options.compilers.solc.settings.optimizer = options.solc.optimizer; - } - - // Certain situations result in `{}` as a value for compilationTargets - // Previous implementations treated any value lacking `.length` as equivalent - // to `[]` - if (!options.compilationTargets || !options.compilationTargets.length) { - options.compilationTargets = []; - } - - return options; -}; - -const analyzeImports = async ({ paths, options }) => { - const dependencies = {}; - for (const path of paths) { - const config = Config.default().merge(options); - const { allSources } = await Profiler.requiredSourcesForSingleFile( - config.with({ - path, - base_path: options.contracts_directory, - resolver: options.resolver - }) - ); - dependencies[path] = [allSources]; - } - - let pragmas; - // key is a source - value is an array of pragmas - for (const compilationSet of Object.keys(dependencies)) { - pragmas = await getPragmas(compilationSet); - } - - let bestSolcVersions; - // key is source - value is best satisfying version of Solidity compiler - for (const pragmaSet of pragmas) { - bestSolcVersions = determineBestSatisfyingSolcVersion(pragmaSet); - } - - let compilations; - for (const version of bestSolcVersions) { - const compilation = await run( - allSources, - normalizeOptions(options) - ); - const { name, version } = compiler; - return compilation.contracts.length > 0 - ? { - compilations: [ - { - sourceIndexes, - contracts, - compiler: { name, version } - } - ] - } - : { compilations: [] }; - } -}; +const { normalizeOptions } = require("./normalizeOptions"); +const { analyzeImports } = require("./analyzeImports"); +const expect = require("@truffle/expect"); const Compile = { // this takes an object with keys being the name and values being source @@ -121,8 +46,8 @@ const Compile = { // this takes an array of paths and options async sourcesWithDependencies({ paths, options }) { - if (options.analyzeImports) { - await analyzeImports({ paths, options }); + if (options.compilers.solc.version === "analyze-imports") { + return await analyzeImports({ paths, options }); } options.logger = options.logger || console; options.contracts_directory = options.contracts_directory || process.cwd(); diff --git a/packages/compile-solidity/normalizeOptions.js b/packages/compile-solidity/normalizeOptions.js new file mode 100644 index 00000000000..0a9a5e411b7 --- /dev/null +++ b/packages/compile-solidity/normalizeOptions.js @@ -0,0 +1,35 @@ +const expect = require("@truffle/expect"); + +const normalizeOptions = options => { + if (options.logger === undefined) options.logger = console; + + expect.options(options, ["contracts_directory", "compilers"]); + expect.options(options.compilers, ["solc"]); + + options.compilers.solc.settings.evmVersion = + options.compilers.solc.settings.evmVersion || + options.compilers.solc.evmVersion; + options.compilers.solc.settings.optimizer = + options.compilers.solc.settings.optimizer || + options.compilers.solc.optimizer || + {}; + + // Grandfather in old solc config + if (options.solc) { + options.compilers.solc.settings.evmVersion = options.solc.evmVersion; + options.compilers.solc.settings.optimizer = options.solc.optimizer; + } + + // Certain situations result in `{}` as a value for compilationTargets + // Previous implementations treated any value lacking `.length` as equivalent + // to `[]` + if (!options.compilationTargets || !options.compilationTargets.length) { + options.compilationTargets = []; + } + + return options; +}; + +module.exports = { + normalizeOptions +}; From c2a735d7fa1822b5ddff25526b424622ccbd7790 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 2 Oct 2020 11:24:34 -0400 Subject: [PATCH 05/39] Update some method and file names --- ...analyzeImports.js => compileWithPragmaAnalysis.js} | 4 ++-- packages/compile-solidity/index.js | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) rename packages/compile-solidity/{analyzeImports.js => compileWithPragmaAnalysis.js} (97%) diff --git a/packages/compile-solidity/analyzeImports.js b/packages/compile-solidity/compileWithPragmaAnalysis.js similarity index 97% rename from packages/compile-solidity/analyzeImports.js rename to packages/compile-solidity/compileWithPragmaAnalysis.js index a6e8363ad9c..eceb5963773 100644 --- a/packages/compile-solidity/analyzeImports.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -48,7 +48,7 @@ const findNewestSatisfyingVersion = ({ solcReleases, versionRange }) => { return version; }; -const analyzeImports = async ({ paths, options }) => { +const compileWithPragmaAnalysis = async ({ paths, options }) => { const supplierOptions = { events: options.events, solcConfig: options.compilers.solc @@ -127,5 +127,5 @@ const analyzeImports = async ({ paths, options }) => { }; module.exports = { - analyzeImports + compileWithPragmaAnalysis }; diff --git a/packages/compile-solidity/index.js b/packages/compile-solidity/index.js index 9f8e0f1f5fd..69a17b73844 100644 --- a/packages/compile-solidity/index.js +++ b/packages/compile-solidity/index.js @@ -6,7 +6,7 @@ const Profiler = require("./profiler"); const CompilerSupplier = require("./compilerSupplier"); const { run } = require("./run"); const { normalizeOptions } = require("./normalizeOptions"); -const { analyzeImports } = require("./analyzeImports"); +const { compileWithPragmaAnalysis } = require("./compileWithPragmaAnalysis"); const expect = require("@truffle/expect"); const Compile = { @@ -46,9 +46,10 @@ const Compile = { // this takes an array of paths and options async sourcesWithDependencies({ paths, options }) { - if (options.compilers.solc.version === "analyze-imports") { - return await analyzeImports({ paths, options }); + if (options.compilers.solc.version === "analyzePragmas") { + return await this.sourcesWithPragmaAnalysis({ paths, options }); } + options.logger = options.logger || console; options.contracts_directory = options.contracts_directory || process.cwd(); @@ -98,6 +99,10 @@ const Compile = { : { compilations: [] }; }, + async sourcesWithPragmaAnalysis({ paths, options }) { + return await compileWithPragmaAnalysis({ paths, options }); + }, + display(paths, options) { if (options.quiet !== true) { if (!Array.isArray(paths)) { From 1c63d5aeb33f5534bc87999f78ee30de48188bc7 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 2 Oct 2020 12:35:10 -0400 Subject: [PATCH 06/39] Remove a method and simplify a bit --- .../compileWithPragmaAnalysis.js | 80 +++++-------------- 1 file changed, 22 insertions(+), 58 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index eceb5963773..4c75f510a03 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -10,39 +10,21 @@ const getSemverExpression = source => { }; const getSemverExpressions = sources => { - return sources.map(source => { - return getSemverExpression(source); - }); + return sources.map(source => getSemverExpression(source)); }; -const determineSolcVersionRange = ranges => { - const splitRanges = ranges.map(range => range.split("||")); - const singletons = splitRanges.map(list => list.map(x => [x.trim()])); - const tuples = singletons.reduce( - (list1, list2) => { - const pairs = []; - for (const l1 of list1) { - for (const l2 of list2) { - pairs.push([...l1, ...l2]); - } - } - return pairs; - }, - [[]] - ); - const disjuncts = tuples.map(tuple => tuple.join(" ")); - return disjuncts.join(" || "); -}; - -const findNewestSatisfyingVersion = ({ solcReleases, versionRange }) => { +// takes an array of versions and an array of semver expressions +const findNewestSatisfyingVersion = ({ solcReleases, semverExpressions }) => { // releases are ordered from newest to oldest - const version = solcReleases.find(version => - semver.satisfies(version, versionRange) - ); + const version = solcReleases.find(version => { + return semverExpressions.every(expression => + semver.satisfies(version, expression) + ); + }); if (typeof version === "undefined") { throw new Error(` - Could not find a version of the Solidity compiler that satisfies all - of the pragma statements for ${source} and its dependencies. + Could not find a single version of the Solidity compiler that satisfies + all of the pragma statements for ${source} and its dependencies. `); } return version; @@ -56,15 +38,17 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const compilerSupplier = new CompilerSupplier(supplierOptions); const { releases } = await compilerSupplier.getReleases(); - const dependencies = {}; - // for each source, collect all its dependencies + // for each source, collect all its dependencies and determine the newest + // version of the Solidity compiler to use for compilation of the group + const compilations = []; for (const path of paths) { const source = await fse.readFile(path, "utf8"); const parserVersion = findNewestSatisfyingVersion({ solcReleases: releases, - versionRange: getSemverExpression(source) + semverExpressions: [getSemverExpression(source)] }); + // allSources is of the format { [filename]: string } const { allSources } = await Profiler.requiredSourcesForSingleFile( options.with({ path, @@ -77,46 +61,26 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { } }) ); - dependencies[path] = allSources; - } - - const semverExpressions = {}; - // for each group of sources, collect all the semver expression from pragmas - // key is a source - value is an array of pragmas - for (const source of Object.keys(dependencies)) { - const deps = Object.values(dependencies[source]); - semverExpressions[source] = await getSemverExpressions(deps); - } - const solcVersionRange = {}; - // for each pragma group, determine the most recent satisfying version - // key is source - value is a version of the Solidity compiler - for (const source of Object.keys(semverExpressions)) { - solcVersionRange[source] = determineSolcVersionRange( - semverExpressions[source] + // get an array of all the semver expressions in the sources + const semverExpressions = await getSemverExpressions( + Object.values(allSources) ); - } - - const versionsToUse = {}; - for (const source of Object.keys(solcVersionRange)) { - versionsToUse[source] = findNewestSatisfyingVersion({ + const newestSatisfyingVersion = findNewestSatisfyingVersion({ solcReleases: releases, - versionRange: solcVersionRange[source] + semverExpressions }); - } - let compilations = []; - for (const source of Object.keys(versionsToUse)) { const compilationOptions = options.merge({ compilers: { solc: { - version: versionsToUse[source] + version: newestSatisfyingVersion } } }); const compilation = await run( - dependencies[source], + allSources, normalizeOptions(compilationOptions) ); if (compilation.contracts.length > 0) { From da25a45f99236b6fd8fc0124c3eff821d13a881e Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 6 Oct 2020 16:02:26 -0400 Subject: [PATCH 07/39] Improve messaging for when no version of the Solidity compiler could be found --- .../compileWithPragmaAnalysis.js | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 4c75f510a03..6a93cbf963b 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -4,6 +4,7 @@ const Profiler = require("./profiler"); const { normalizeOptions } = require("./normalizeOptions"); const fse = require("fs-extra"); const { run } = require("./run"); +const OS = require("os"); const getSemverExpression = source => { return source.match(/pragma solidity(.*);/)[1].trim(); @@ -14,20 +15,23 @@ const getSemverExpressions = sources => { }; // takes an array of versions and an array of semver expressions +// returns a version of the compiler or undefined if none can be found const findNewestSatisfyingVersion = ({ solcReleases, semverExpressions }) => { // releases are ordered from newest to oldest - const version = solcReleases.find(version => { + return solcReleases.find(version => { return semverExpressions.every(expression => semver.satisfies(version, expression) ); }); - if (typeof version === "undefined") { - throw new Error(` - Could not find a single version of the Solidity compiler that satisfies - all of the pragma statements for ${source} and its dependencies. - `); - } - return version; +}; + +const throwCompilerVersionNotFound = ({ path, semverExpressions }) => { + const message = + `Could not find a single version of the Solidity compiler that ` + + `satisfies the following semver expressions obtained from your source ` + + `files' pragma statements: ${semverExpressions.join(" - ")}. ` + + `${OS.EOL}Please check the pragma statements for ${path} and its imports.`; + throw new Error(message); }; const compileWithPragmaAnalysis = async ({ paths, options }) => { @@ -43,10 +47,17 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const compilations = []; for (const path of paths) { const source = await fse.readFile(path, "utf8"); + const parserVersion = findNewestSatisfyingVersion({ solcReleases: releases, semverExpressions: [getSemverExpression(source)] }); + if (!parserVersion) { + throwCompilerVersionNotFound({ + path, + semverExpressions: [getSemverExpression(source)] + }); + } // allSources is of the format { [filename]: string } const { allSources } = await Profiler.requiredSourcesForSingleFile( @@ -70,6 +81,12 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { solcReleases: releases, semverExpressions }); + if (!newestSatisfyingVersion) { + throwCompilerVersionNotFound({ + path, + semverExpressions + }); + } const compilationOptions = options.merge({ compilers: { From 8f931bf9ddaabb9e1ba6dcc4922b1aabd4e31d68 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 6 Oct 2020 17:12:41 -0400 Subject: [PATCH 08/39] Make compilation slightly more efficient by collecting all sources based on the version of the Solidity compiler that they require --- .../compileWithPragmaAnalysis.js | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 6a93cbf963b..816379c8215 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -42,9 +42,8 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const compilerSupplier = new CompilerSupplier(supplierOptions); const { releases } = await compilerSupplier.getReleases(); - // for each source, collect all its dependencies and determine the newest - // version of the Solidity compiler to use for compilation of the group - const compilations = []; + // collect sources by the version of the Solidity compiler that they require + const versionsAndSources = {}; for (const path of paths) { const source = await fse.readFile(path, "utf8"); @@ -88,16 +87,29 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { }); } + if (versionsAndSources[newestSatisfyingVersion]) { + versionsAndSources[newestSatisfyingVersion] = Object.assign( + {}, + versionsAndSources[newestSatisfyingVersion], + allSources + ); + } else { + versionsAndSources[newestSatisfyingVersion] = allSources; + } + } + + const compilations = []; + for (const compilerVersion of Object.keys(versionsAndSources)) { const compilationOptions = options.merge({ compilers: { solc: { - version: newestSatisfyingVersion + version: compilerVersion } } }); const compilation = await run( - allSources, + versionsAndSources[compilerVersion], normalizeOptions(compilationOptions) ); if (compilation.contracts.length > 0) { From 2a22fdf392dff36449a6e4d6f01f4026b6aefb4c Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 14 Oct 2020 12:59:38 -0400 Subject: [PATCH 09/39] Add a couple of tests for the pragma analysis feature --- .../test/compileWithPragmaAnalysis.js | 88 +++++++++++++++++++ .../noImports/OtherSourceWith0.7.0.sol | 3 + .../noImports/SourceWith0.5.0.sol | 3 + .../noImports/SourceWith0.6.0.sol | 3 + .../noImports/SourceWith0.7.0.sol | 3 + .../multipleSolcVersions/withImports/A.sol | 3 + .../multipleSolcVersions/withImports/B.sol | 3 + .../multipleSolcVersions/withImports/C.sol | 6 ++ .../withImports/NoCommonVersion.sol | 5 ++ 9 files changed, 117 insertions(+) create mode 100644 packages/compile-solidity/test/compileWithPragmaAnalysis.js create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js new file mode 100644 index 00000000000..9e481f2024e --- /dev/null +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -0,0 +1,88 @@ +const assert = require("assert"); +const Config = require("@truffle/config"); +const Resolver = require("@truffle/resolver"); +const { compileWithPragmaAnalysis } = require("../compileWithPragmaAnalysis"); +const path = require("path"); +let paths = []; + +const sourceDirectory = path.resolve( + __dirname, + "sources", + "multipleSolcVersions" +); + +const config = new Config().with({ + compilers: { + solc: { + settings: {}, + version: "analyzePragmas" + } + } +}); + +// she needs a resolver! +config.resolver = new Resolver(config); + +describe("compileWithPragmaAnalysis", () => { + describe("solidity files with no imports", () => { + before(() => { + paths = [ + path.join(sourceDirectory, "noImports", "SourceWith0.5.0.sol"), + path.join(sourceDirectory, "noImports", "SourceWith0.6.0.sol"), + path.join(sourceDirectory, "noImports", "SourceWith0.7.0.sol") + ]; + }); + + // note that it will find the newest version of Solidity that satisifes + // each pragma expression and then do one compilation per version + it("will make one compilation per compiler version", async () => { + const { compilations } = await compileWithPragmaAnalysis({ + options: config, + paths + }); + assert.equal(compilations.length, 3); + }); + + it("will compile files with the same version together", async () => { + const { compilations } = await compileWithPragmaAnalysis({ + options: config, + paths: paths.concat( + path.join(sourceDirectory, "noImports", "OtherSourceWith0.7.0.sol") + ) + }); + assert.equal(compilations.length, 3); + }); + }); + + describe("solidity files with imports", () => { + before(() => { + paths = [path.join(sourceDirectory, "withImports", "C.sol")]; + }); + + it("finds a version that satisfies all pragmas if it exists", async () => { + const { compilations } = await compileWithPragmaAnalysis({ + options: config, + paths: [path.join(sourceDirectory, "withImports", "C.sol")] + }); + assert.equal(compilations.length, 1); + assert(compilations[0].compiler.version.startsWith("0.6.12")); + }); + + it("throws an error if it cannot find one that satisifes", async () => { + try { + await compileWithPragmaAnalysis({ + options: config, + paths: [ + path.join(sourceDirectory, "withImports", "NoCommonVersion.sol") + ] + }); + assert.fail("compiling that source should have failed"); + } catch (error) { + const expectedSnippet = "Could not find a single version of the"; + if (!error.message.includes(expectedSnippet)) { + throw error; + } + } + }); + }); +}); diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol new file mode 100644 index 00000000000..fcbc2822a19 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.7.0; + +contract D {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol new file mode 100644 index 00000000000..66779197627 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol @@ -0,0 +1,3 @@ +pragma solidity 0.5.0; + +contract A {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol new file mode 100644 index 00000000000..45e2bec2c0f --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.6.0; + +contract B {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol new file mode 100644 index 00000000000..b76ed89fb53 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.7.0; + +contract C {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol new file mode 100644 index 00000000000..80a843f2351 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol @@ -0,0 +1,3 @@ +pragma solidity >0.5.0 <0.7.0; + +contract A {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol new file mode 100644 index 00000000000..45e2bec2c0f --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol @@ -0,0 +1,3 @@ +pragma solidity ^0.6.0; + +contract B {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol new file mode 100644 index 00000000000..d47c0874408 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol @@ -0,0 +1,6 @@ +pragma solidity 0.6.12; + +import "./A.sol"; +import "./B.sol"; + +contract C {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol new file mode 100644 index 00000000000..f38039a3421 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol @@ -0,0 +1,5 @@ +pragma solidity 0.5.0; + +import "./B.sol"; + +contract NoCommonVersion {} From 3f51c2c0592ffd6627e4b07daf35ef157e802215 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 14 Oct 2020 13:35:43 -0400 Subject: [PATCH 10/39] Increase test timeout --- packages/compile-solidity/test/compileWithPragmaAnalysis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 9e481f2024e..3dc2d1fae97 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -85,4 +85,4 @@ describe("compileWithPragmaAnalysis", () => { } }); }); -}); +}).timeout(20000); From 9096540e17ab8e7f2e30f17f879a0d734aba9cef Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 14 Oct 2020 16:02:55 -0400 Subject: [PATCH 11/39] Correct typo --- packages/compile-solidity/test/compileWithPragmaAnalysis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 3dc2d1fae97..31ee7a15c11 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -68,7 +68,7 @@ describe("compileWithPragmaAnalysis", () => { assert(compilations[0].compiler.version.startsWith("0.6.12")); }); - it("throws an error if it cannot find one that satisifes", async () => { + it("throws an error if it cannot find one that satisfies", async () => { try { await compileWithPragmaAnalysis({ options: config, From bafeae4a4671538c8cc5f2125ca7e4209962ba68 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 14 Oct 2020 16:30:53 -0400 Subject: [PATCH 12/39] Increase test timeout globally for compile-solidity --- packages/compile-solidity/scripts/test.sh | 4 ++-- packages/compile-solidity/test/compileWithPragmaAnalysis.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/compile-solidity/scripts/test.sh b/packages/compile-solidity/scripts/test.sh index a9b2d46b992..31608d90ee3 100755 --- a/packages/compile-solidity/scripts/test.sh +++ b/packages/compile-solidity/scripts/test.sh @@ -3,8 +3,8 @@ set -o errexit if [ "$CI" = true ]; then - mocha ./test/** ./test/**/* --timeout 10000 $@ + mocha ./test/** ./test/**/* --timeout 20000 $@ else rm -rf ./node_modules/.cache/truffle - mocha ./test/** ./test/**/* --invert --grep native --timeout 10000 $@ + mocha ./test/** ./test/**/* --invert --grep native --timeout 20000 $@ fi diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 31ee7a15c11..0d0a0f7f7f9 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -85,4 +85,4 @@ describe("compileWithPragmaAnalysis", () => { } }); }); -}).timeout(20000); +}); From 0c05bcffff76b27348478ed8230dbd684579ac60 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 15 Oct 2020 11:41:58 -0400 Subject: [PATCH 13/39] Once again increase test timeouts --- packages/compile-solidity/scripts/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compile-solidity/scripts/test.sh b/packages/compile-solidity/scripts/test.sh index 31608d90ee3..75db068966c 100755 --- a/packages/compile-solidity/scripts/test.sh +++ b/packages/compile-solidity/scripts/test.sh @@ -3,8 +3,8 @@ set -o errexit if [ "$CI" = true ]; then - mocha ./test/** ./test/**/* --timeout 20000 $@ + mocha ./test/** ./test/**/* --timeout 30000 $@ else rm -rf ./node_modules/.cache/truffle - mocha ./test/** ./test/**/* --invert --grep native --timeout 20000 $@ + mocha ./test/** ./test/**/* --invert --grep native --timeout 30000 $@ fi From 51368f6f6176d7dc124b2f7a2bef4ddb728ef21c Mon Sep 17 00:00:00 2001 From: Amal Sudama Date: Wed, 14 Oct 2020 18:52:53 -0400 Subject: [PATCH 14/39] Add SPDX header to test contracts --- .../compile-solidity/test/sources/badSources/ShouldError.sol | 1 + .../multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol | 1 + .../sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol | 1 + .../sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol | 1 + .../sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol | 1 + .../test/sources/multipleSolcVersions/withImports/A.sol | 1 + .../test/sources/multipleSolcVersions/withImports/B.sol | 1 + .../test/sources/multipleSolcVersions/withImports/C.sol | 1 + .../sources/multipleSolcVersions/withImports/NoCommonVersion.sol | 1 + packages/compile-solidity/test/sources/v0.4.15/MyContract.sol | 1 + packages/compile-solidity/test/sources/v0.4.15/OldPragmaPin.sol | 1 + packages/compile-solidity/test/sources/v0.4.x/ComplexOrdered.sol | 1 + packages/compile-solidity/test/sources/v0.4.x/InheritB.sol | 1 + packages/compile-solidity/test/sources/v0.4.x/NewPragma.sol | 1 + packages/compile-solidity/test/sources/v0.4.x/OldPragmaFloat.sol | 1 + packages/compile-solidity/test/sources/v0.4.x/SimpleOrdered.sol | 1 + packages/compile-solidity/test/sources/v0.5.x/ComplexOrdered.sol | 1 + packages/compile-solidity/test/sources/v0.5.x/InheritB.sol | 1 + packages/compile-solidity/test/sources/v0.5.x/Version5Pragma.sol | 1 + packages/compile-solidity/test/sources/v0.6.x/ComplexOrdered.sol | 1 + packages/compile-solidity/test/sources/v0.6.x/InheritB.sol | 1 + packages/compile-solidity/test/sources/v0.6.x/Version6Pragma.sol | 1 + packages/compile-solidity/test/sources/v0.7.x/ComplexOrdered.sol | 1 + packages/compile-solidity/test/sources/v0.7.x/InheritB.sol | 1 + packages/compile-solidity/test/sources/v0.7.x/Version7Pragma.sol | 1 + 25 files changed, 25 insertions(+) diff --git a/packages/compile-solidity/test/sources/badSources/ShouldError.sol b/packages/compile-solidity/test/sources/badSources/ShouldError.sol index 405d9e0b155..8a210505cd9 100644 --- a/packages/compile-solidity/test/sources/badSources/ShouldError.sol +++ b/packages/compile-solidity/test/sources/badSources/ShouldError.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT paragma solidity >0.4.0; contract Error { diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol index fcbc2822a19..8a15e86e753 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/OtherSourceWith0.7.0.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.7.0; contract D {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol index 66779197627..fdf77f9d73e 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.5.0.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity 0.5.0; contract A {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol index 45e2bec2c0f..cbc880513cd 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.6.0.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract B {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol index b76ed89fb53..b74cdfd77bc 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/noImports/SourceWith0.7.0.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.7.0; contract C {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol index 80a843f2351..dc9f502a32e 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/A.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.7.0; contract A {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol index 45e2bec2c0f..cbc880513cd 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/B.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract B {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol index d47c0874408..cdd25d0f9fe 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/C.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "./A.sol"; diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol index f38039a3421..8770dfedb60 100644 --- a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/NoCommonVersion.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity 0.5.0; import "./B.sol"; diff --git a/packages/compile-solidity/test/sources/v0.4.15/MyContract.sol b/packages/compile-solidity/test/sources/v0.4.15/MyContract.sol index 6b48e839102..c307322b632 100644 --- a/packages/compile-solidity/test/sources/v0.4.15/MyContract.sol +++ b/packages/compile-solidity/test/sources/v0.4.15/MyContract.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity >0.4.15; import "./Dependency.sol"; diff --git a/packages/compile-solidity/test/sources/v0.4.15/OldPragmaPin.sol b/packages/compile-solidity/test/sources/v0.4.15/OldPragmaPin.sol index 04d28fbc9dd..a38516c1d01 100644 --- a/packages/compile-solidity/test/sources/v0.4.15/OldPragmaPin.sol +++ b/packages/compile-solidity/test/sources/v0.4.15/OldPragmaPin.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity 0.4.15; contract OldPragmaPin { diff --git a/packages/compile-solidity/test/sources/v0.4.x/ComplexOrdered.sol b/packages/compile-solidity/test/sources/v0.4.x/ComplexOrdered.sol index c67ad0e1a77..a5c2be92485 100644 --- a/packages/compile-solidity/test/sources/v0.4.x/ComplexOrdered.sol +++ b/packages/compile-solidity/test/sources/v0.4.x/ComplexOrdered.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.4.22; import "./InheritB.sol"; diff --git a/packages/compile-solidity/test/sources/v0.4.x/InheritB.sol b/packages/compile-solidity/test/sources/v0.4.x/InheritB.sol index 89ae692cf77..68c7b4cc0a3 100644 --- a/packages/compile-solidity/test/sources/v0.4.x/InheritB.sol +++ b/packages/compile-solidity/test/sources/v0.4.x/InheritB.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.4.22; // These are out of alphabetic order diff --git a/packages/compile-solidity/test/sources/v0.4.x/NewPragma.sol b/packages/compile-solidity/test/sources/v0.4.x/NewPragma.sol index 0e75f7097b5..96a1b2e9668 100644 --- a/packages/compile-solidity/test/sources/v0.4.x/NewPragma.sol +++ b/packages/compile-solidity/test/sources/v0.4.x/NewPragma.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.4.21; contract NewPragma { diff --git a/packages/compile-solidity/test/sources/v0.4.x/OldPragmaFloat.sol b/packages/compile-solidity/test/sources/v0.4.x/OldPragmaFloat.sol index 7aadf72eb6b..3273191c115 100644 --- a/packages/compile-solidity/test/sources/v0.4.x/OldPragmaFloat.sol +++ b/packages/compile-solidity/test/sources/v0.4.x/OldPragmaFloat.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.4.15; contract OldPragmaFloat { diff --git a/packages/compile-solidity/test/sources/v0.4.x/SimpleOrdered.sol b/packages/compile-solidity/test/sources/v0.4.x/SimpleOrdered.sol index 9db6f09f012..708c8ac42a3 100644 --- a/packages/compile-solidity/test/sources/v0.4.x/SimpleOrdered.sol +++ b/packages/compile-solidity/test/sources/v0.4.x/SimpleOrdered.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.4.18; // These are out of alphabetic order diff --git a/packages/compile-solidity/test/sources/v0.5.x/ComplexOrdered.sol b/packages/compile-solidity/test/sources/v0.5.x/ComplexOrdered.sol index eb0c49853e7..3a9b81d1951 100644 --- a/packages/compile-solidity/test/sources/v0.5.x/ComplexOrdered.sol +++ b/packages/compile-solidity/test/sources/v0.5.x/ComplexOrdered.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.5.0; import "./InheritB.sol"; diff --git a/packages/compile-solidity/test/sources/v0.5.x/InheritB.sol b/packages/compile-solidity/test/sources/v0.5.x/InheritB.sol index 41e9fbd77f5..b91277cfede 100644 --- a/packages/compile-solidity/test/sources/v0.5.x/InheritB.sol +++ b/packages/compile-solidity/test/sources/v0.5.x/InheritB.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.5.0; // These are out of alphabetic order diff --git a/packages/compile-solidity/test/sources/v0.5.x/Version5Pragma.sol b/packages/compile-solidity/test/sources/v0.5.x/Version5Pragma.sol index 99ffa6eaffd..a36b9ad6866 100644 --- a/packages/compile-solidity/test/sources/v0.5.x/Version5Pragma.sol +++ b/packages/compile-solidity/test/sources/v0.5.x/Version5Pragma.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.5.0; contract Version5Pragma { diff --git a/packages/compile-solidity/test/sources/v0.6.x/ComplexOrdered.sol b/packages/compile-solidity/test/sources/v0.6.x/ComplexOrdered.sol index 35c87056e8e..3380d5cbe51 100644 --- a/packages/compile-solidity/test/sources/v0.6.x/ComplexOrdered.sol +++ b/packages/compile-solidity/test/sources/v0.6.x/ComplexOrdered.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "./InheritB.sol"; diff --git a/packages/compile-solidity/test/sources/v0.6.x/InheritB.sol b/packages/compile-solidity/test/sources/v0.6.x/InheritB.sol index 523fb141c88..ec2ba19439e 100644 --- a/packages/compile-solidity/test/sources/v0.6.x/InheritB.sol +++ b/packages/compile-solidity/test/sources/v0.6.x/InheritB.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.6.0; // These are out of alphabetic order diff --git a/packages/compile-solidity/test/sources/v0.6.x/Version6Pragma.sol b/packages/compile-solidity/test/sources/v0.6.x/Version6Pragma.sol index ebac31554d4..70ef97ac60e 100644 --- a/packages/compile-solidity/test/sources/v0.6.x/Version6Pragma.sol +++ b/packages/compile-solidity/test/sources/v0.6.x/Version6Pragma.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract Version6Pragma { diff --git a/packages/compile-solidity/test/sources/v0.7.x/ComplexOrdered.sol b/packages/compile-solidity/test/sources/v0.7.x/ComplexOrdered.sol index d775fa37179..3071b0db56e 100644 --- a/packages/compile-solidity/test/sources/v0.7.x/ComplexOrdered.sol +++ b/packages/compile-solidity/test/sources/v0.7.x/ComplexOrdered.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "./InheritB.sol"; diff --git a/packages/compile-solidity/test/sources/v0.7.x/InheritB.sol b/packages/compile-solidity/test/sources/v0.7.x/InheritB.sol index 6974e11ef06..1566b18956a 100644 --- a/packages/compile-solidity/test/sources/v0.7.x/InheritB.sol +++ b/packages/compile-solidity/test/sources/v0.7.x/InheritB.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.7.0; // These are out of alphabetic order diff --git a/packages/compile-solidity/test/sources/v0.7.x/Version7Pragma.sol b/packages/compile-solidity/test/sources/v0.7.x/Version7Pragma.sol index 10dcff29ce7..ad2f77a6bde 100644 --- a/packages/compile-solidity/test/sources/v0.7.x/Version7Pragma.sol +++ b/packages/compile-solidity/test/sources/v0.7.x/Version7Pragma.sol @@ -1,3 +1,4 @@ +//SPDX-License-Identifier: MIT pragma solidity ^0.7.0; contract Version7Pragma { From 32cf3dfd8633dde3736cb089d5b024009a7d2dff Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 16 Oct 2020 10:23:24 -0400 Subject: [PATCH 15/39] Mock request to get solc versions --- .../test/compileWithPragmaAnalysis.js | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 0d0a0f7f7f9..e6165f666d8 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -1,6 +1,8 @@ const assert = require("assert"); const Config = require("@truffle/config"); +const { CompilerSupplier } = require("../index"); const Resolver = require("@truffle/resolver"); +const sinon = require("sinon"); const { compileWithPragmaAnalysis } = require("../compileWithPragmaAnalysis"); const path = require("path"); let paths = []; @@ -20,6 +22,53 @@ const config = new Config().with({ } }); +const releases = { + prereleases: [], + releases: [ + "0.7.3", + "0.7.2", + "0.7.1", + "0.7.0", + "0.6.12", + "0.6.11", + "0.6.10", + "0.6.9", + "0.6.8", + "0.6.7", + "0.6.6", + "0.6.5", + "0.6.4", + "0.6.3", + "0.6.2", + "0.6.1", + "0.6.0", + "0.5.17", + "0.5.16", + "0.5.15", + "0.5.14", + "0.5.13", + "0.5.12", + "0.5.11", + "0.5.10", + "0.5.9", + "0.5.8", + "0.5.7", + "0.5.6", + "0.5.5", + "0.5.4", + "0.5.4", + "0.5.3", + "0.5.2", + "0.5.1", + "0.5.0", + "0.4.25", + "0.4.24", + "0.4.23", + "0.4.22" + ], + latestRelease: "0.7.3" +}; + // she needs a resolver! config.resolver = new Resolver(config); @@ -31,6 +80,11 @@ describe("compileWithPragmaAnalysis", () => { path.join(sourceDirectory, "noImports", "SourceWith0.6.0.sol"), path.join(sourceDirectory, "noImports", "SourceWith0.7.0.sol") ]; + sinon.stub(CompilerSupplier.prototype, "getReleases").returns(releases); + }); + + after(() => { + CompilerSupplier.prototype.getReleases.restore(); }); // note that it will find the newest version of Solidity that satisifes From 5dec52f1e71af0f62922eb921249884c2fb72088 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 16 Oct 2020 10:48:55 -0400 Subject: [PATCH 16/39] Use spread operator instead of Object.assign --- packages/compile-solidity/compileWithPragmaAnalysis.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 816379c8215..92229efba50 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -88,11 +88,10 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { } if (versionsAndSources[newestSatisfyingVersion]) { - versionsAndSources[newestSatisfyingVersion] = Object.assign( - {}, - versionsAndSources[newestSatisfyingVersion], - allSources - ); + versionsAndSources[newestSatisfyingVersion] = { + ...versionsAndSources[newestSatisfyingVersion], + ...allSources + }; } else { versionsAndSources[newestSatisfyingVersion] = allSources; } From bddada24a021e359e9c2f9ca3f76f0bf5fc49588 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 16 Oct 2020 11:00:29 -0400 Subject: [PATCH 17/39] Increase the timeout for tests once more --- packages/compile-solidity/scripts/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compile-solidity/scripts/test.sh b/packages/compile-solidity/scripts/test.sh index 75db068966c..0040827870c 100755 --- a/packages/compile-solidity/scripts/test.sh +++ b/packages/compile-solidity/scripts/test.sh @@ -3,8 +3,8 @@ set -o errexit if [ "$CI" = true ]; then - mocha ./test/** ./test/**/* --timeout 30000 $@ + mocha ./test/** ./test/**/* --timeout 40000 $@ else rm -rf ./node_modules/.cache/truffle - mocha ./test/** ./test/**/* --invert --grep native --timeout 30000 $@ + mocha ./test/** ./test/**/* --invert --grep native --timeout 40000 $@ fi From 7336ae10e93a97b3ecb16e9c77039064664c9c87 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 16 Oct 2020 11:14:32 -0400 Subject: [PATCH 18/39] Increase test timeout --- packages/compile-solidity/scripts/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compile-solidity/scripts/test.sh b/packages/compile-solidity/scripts/test.sh index 0040827870c..ec9c19110d2 100755 --- a/packages/compile-solidity/scripts/test.sh +++ b/packages/compile-solidity/scripts/test.sh @@ -3,8 +3,8 @@ set -o errexit if [ "$CI" = true ]; then - mocha ./test/** ./test/**/* --timeout 40000 $@ + mocha ./test/** ./test/**/* --timeout 50000 $@ else rm -rf ./node_modules/.cache/truffle - mocha ./test/** ./test/**/* --invert --grep native --timeout 40000 $@ + mocha ./test/** ./test/**/* --invert --grep native --timeout 50000 $@ fi From 03104420b01ee1f45a7ea846ed9a4dc7d7730d68 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 27 Oct 2020 11:29:31 -0400 Subject: [PATCH 19/39] Remove some unnecessary awaits and a couple of comments --- packages/compile-solidity/index.js | 4 ++-- packages/compile-solidity/profiler/index.js | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/compile-solidity/index.js b/packages/compile-solidity/index.js index 69a17b73844..d6b6c0d3063 100644 --- a/packages/compile-solidity/index.js +++ b/packages/compile-solidity/index.js @@ -47,7 +47,7 @@ const Compile = { // this takes an array of paths and options async sourcesWithDependencies({ paths, options }) { if (options.compilers.solc.version === "analyzePragmas") { - return await this.sourcesWithPragmaAnalysis({ paths, options }); + return this.sourcesWithPragmaAnalysis({ paths, options }); } options.logger = options.logger || console; @@ -100,7 +100,7 @@ const Compile = { }, async sourcesWithPragmaAnalysis({ paths, options }) { - return await compileWithPragmaAnalysis({ paths, options }); + return compileWithPragmaAnalysis({ paths, options }); }, display(paths, options) { diff --git a/packages/compile-solidity/profiler/index.js b/packages/compile-solidity/profiler/index.js index 23e85df8882..6c39c31a634 100644 --- a/packages/compile-solidity/profiler/index.js +++ b/packages/compile-solidity/profiler/index.js @@ -29,16 +29,13 @@ module.exports = { }, requiredSourcesForSingleFile: async options => { - // get parser const parseImports = await loadParser(options); - // generate profiler const profiler = new Common.Profiler({ parseImports, shouldIncludePath }); - // invoke profiler - return await profiler.requiredSourcesForSingleFile(options); + return profiler.requiredSourcesForSingleFile(options); } }; From 296f89046a74698b851c9f5448b1b647eee42f78 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 27 Oct 2020 11:43:45 -0400 Subject: [PATCH 20/39] Type profiler method input --- packages/compile-common/package.json | 3 ++- packages/compile-common/src/profiler/profiler.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/compile-common/package.json b/packages/compile-common/package.json index 1a03034ac5f..6aa896e90fd 100644 --- a/packages/compile-common/package.json +++ b/packages/compile-common/package.json @@ -15,7 +15,8 @@ "devDependencies": { "@types/fs-extra": "^8.1.0", "@types/mocha": "^5.2.7", - "typescript": "3.9.6" + "typescript": "3.9.6", + "@truffle/config": "^1.2.32" }, "dependencies": { "@truffle/contract-schema": "^3.3.1", diff --git a/packages/compile-common/src/profiler/profiler.ts b/packages/compile-common/src/profiler/profiler.ts index 657b8c81567..7dc9acf42ec 100644 --- a/packages/compile-common/src/profiler/profiler.ts +++ b/packages/compile-common/src/profiler/profiler.ts @@ -1,6 +1,7 @@ const findContracts = require("@truffle/contract-sources"); const expect = require("@truffle/expect"); +import type TruffleConfig from "@truffle/config"; import { updated } from "./updated"; import { UnresolvedSource } from "./resolveAllSources"; import { requiredSources, RequiredSourcesOptions } from "./requiredSources"; @@ -69,7 +70,7 @@ export class Profiler { }); } - async requiredSourcesForSingleFile(options: any) { + async requiredSourcesForSingleFile(options: TruffleConfig) { expect.options(options, ["path", "base_path", "resolver"]); const { resolver, path, base_path: basePath } = options; From a57ca33c29441699e98f8bf1458cd947071237ba Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 27 Oct 2020 12:02:56 -0400 Subject: [PATCH 21/39] Get rid of call to normalizeOptions --- packages/compile-solidity/compileWithPragmaAnalysis.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 92229efba50..194b55ac472 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -1,7 +1,6 @@ const CompilerSupplier = require("./compilerSupplier"); const semver = require("semver"); const Profiler = require("./profiler"); -const { normalizeOptions } = require("./normalizeOptions"); const fse = require("fs-extra"); const { run } = require("./run"); const OS = require("os"); @@ -109,7 +108,7 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const compilation = await run( versionsAndSources[compilerVersion], - normalizeOptions(compilationOptions) + compilationOptions ); if (compilation.contracts.length > 0) { compilations.push(compilation); From b63fcc6f8e09d5340187ab0c87353f9efa96b47c Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 27 Oct 2020 12:05:27 -0400 Subject: [PATCH 22/39] Remove unnecessary setting of variable in test --- packages/compile-solidity/test/compileWithPragmaAnalysis.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index e6165f666d8..e8a432ebb15 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -109,10 +109,6 @@ describe("compileWithPragmaAnalysis", () => { }); describe("solidity files with imports", () => { - before(() => { - paths = [path.join(sourceDirectory, "withImports", "C.sol")]; - }); - it("finds a version that satisfies all pragmas if it exists", async () => { const { compilations } = await compileWithPragmaAnalysis({ options: config, From 13e2d0b6ad91fa4113cefc34c4a6b8c004807b39 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 27 Oct 2020 15:42:46 -0400 Subject: [PATCH 23/39] Ensure solc version list is in descending order in compiler supplier --- packages/compile-solidity/compilerSupplier/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/compile-solidity/compilerSupplier/index.js b/packages/compile-solidity/compilerSupplier/index.js index a139c320cd5..fd9d9f018b5 100644 --- a/packages/compile-solidity/compilerSupplier/index.js +++ b/packages/compile-solidity/compilerSupplier/index.js @@ -112,7 +112,9 @@ class CompilerSupplier { .filter(build => build["prerelease"]) .map(build => build["longVersion"]); - const releases = Object.keys(list.releases); + const { rsort } = semver; + // ensure releases are listed in descending order + const releases = rsort(Object.keys(list.releases)); return { prereleases: prereleases, From 5edad34a60ef7f4e30142a85638ff440235dd2be Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 28 Oct 2020 10:59:29 -0400 Subject: [PATCH 24/39] Add semver validation layer and a couple of tests --- .../compileWithPragmaAnalysis.js | 16 +++++++++ .../test/compileWithPragmaAnalysis.js | 34 +++++++++++++++++++ .../multipleSolcVersions/WithSemverError.sol | 3 ++ .../withImports/ImportsBadSemver.sol | 5 +++ 4 files changed, 58 insertions(+) create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/WithSemverError.sol create mode 100644 packages/compile-solidity/test/sources/multipleSolcVersions/withImports/ImportsBadSemver.sol diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 194b55ac472..2170ab07d18 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -13,6 +13,17 @@ const getSemverExpressions = sources => { return sources.map(source => getSemverExpression(source)); }; +const validateSemverExpressions = semverExpressions => { + const { validRange } = semver; + for (const expression of semverExpressions) { + if (semver.validRange(expression) === null) { + const message = `Invalid semver expression (${expression}) found in` + + `one of your contract's imports.`; + throw new Error(message); + } + } +}; + // takes an array of versions and an array of semver expressions // returns a version of the compiler or undefined if none can be found const findNewestSatisfyingVersion = ({ solcReleases, semverExpressions }) => { @@ -75,6 +86,11 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const semverExpressions = await getSemverExpressions( Object.values(allSources) ); + + // this really just validates the expressions from the contracts' imports + // as it has already determined the parser version for each contract + await validateSemverExpressions(semverExpressions); + const newestSatisfyingVersion = findNewestSatisfyingVersion({ solcReleases: releases, semverExpressions diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index e8a432ebb15..9ef6886f17b 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -135,4 +135,38 @@ describe("compileWithPragmaAnalysis", () => { } }); }); + + describe("when there is a semver expression error", () => { + it("throws an error when it can't determine parser version", async () => { + try { + await compileWithPragmaAnalysis({ + options: config, + paths: [path.join(sourceDirectory, "WithSemverError.sol")] + }); + assert.fail("The function should have thrown."); + } catch (error) { + const expectedMessage = "$0.5.3"; + if (error.message.includes(expectedMessage)) { + return "all good"; + } + throw error; + } + }); + + it("throws an error when import has bad semver", async () => { + try { + await compileWithPragmaAnalysis({ + options: config, + paths: [path.join(sourceDirectory, "withImports", "ImportsBadSemver.sol")] + }); + assert.fail("The function should have thrown."); + } catch (error) { + const expectedMessage = "Invalid semver expression ($0.5.3)"; + if (error.message.includes(expectedMessage)) { + return "all good"; + } + throw error; + } + }); + }); }); diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/WithSemverError.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/WithSemverError.sol new file mode 100644 index 00000000000..729e3a7229a --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/WithSemverError.sol @@ -0,0 +1,3 @@ +pragma solidity $0.5.3; + +contract BadSemver {} diff --git a/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/ImportsBadSemver.sol b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/ImportsBadSemver.sol new file mode 100644 index 00000000000..15aafd83048 --- /dev/null +++ b/packages/compile-solidity/test/sources/multipleSolcVersions/withImports/ImportsBadSemver.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.5.0; + +import "../WithSemverError.sol"; + +contract ImportsBadSemver {} From 599d24bcc50309244092c0feda634299018f26c8 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 29 Oct 2020 14:28:43 -0400 Subject: [PATCH 25/39] Change setting name to 'pragma' --- packages/compile-solidity/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compile-solidity/index.js b/packages/compile-solidity/index.js index d6b6c0d3063..1e521e1ddfc 100644 --- a/packages/compile-solidity/index.js +++ b/packages/compile-solidity/index.js @@ -46,7 +46,7 @@ const Compile = { // this takes an array of paths and options async sourcesWithDependencies({ paths, options }) { - if (options.compilers.solc.version === "analyzePragmas") { + if (options.compilers.solc.version === "pragma") { return this.sourcesWithPragmaAnalysis({ paths, options }); } From fc4a7be1c50f5cd3581008af587c95c8c0471049 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 30 Oct 2020 15:20:49 -0400 Subject: [PATCH 26/39] Remove unnecessary await --- packages/compile-solidity/compileWithPragmaAnalysis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 2170ab07d18..029c2aa5950 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -89,7 +89,7 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { // this really just validates the expressions from the contracts' imports // as it has already determined the parser version for each contract - await validateSemverExpressions(semverExpressions); + validateSemverExpressions(semverExpressions); const newestSatisfyingVersion = findNewestSatisfyingVersion({ solcReleases: releases, From 07f65e096a4a694b60fc08953716220d2170ccb4 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 30 Oct 2020 15:44:42 -0400 Subject: [PATCH 27/39] Add one more test --- .../compile-solidity/test/compileWithPragmaAnalysis.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 9ef6886f17b..0a53ce97997 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -109,6 +109,14 @@ describe("compileWithPragmaAnalysis", () => { }); describe("solidity files with imports", () => { + it("compiles both files with imports and without", async () => { + const { compilations } = await compileWithPragmaAnalysis({ + options: config, + paths: paths.concat([path.join(sourceDirectory, "withImports", "C.sol")]) + }); + assert.equal(compilations.length, 3); + }); + it("finds a version that satisfies all pragmas if it exists", async () => { const { compilations } = await compileWithPragmaAnalysis({ options: config, From 828178ac6513bbff94e22d435b70213fa5420957 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 10 Nov 2020 11:50:43 -0500 Subject: [PATCH 28/39] Stub the request for getting the releases at a higher level in test --- .../test/compileWithPragmaAnalysis.js | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 0a53ce97997..2fac89fc143 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -1,9 +1,9 @@ const assert = require("assert"); const Config = require("@truffle/config"); -const { CompilerSupplier } = require("../index"); +const {CompilerSupplier} = require("../index"); const Resolver = require("@truffle/resolver"); const sinon = require("sinon"); -const { compileWithPragmaAnalysis } = require("../compileWithPragmaAnalysis"); +const {compileWithPragmaAnalysis} = require("../compileWithPragmaAnalysis"); const path = require("path"); let paths = []; @@ -73,6 +73,13 @@ const releases = { config.resolver = new Resolver(config); describe("compileWithPragmaAnalysis", () => { + before(() => { + sinon.stub(CompilerSupplier.prototype, "getReleases").returns(releases); + }); + after(() => { + CompilerSupplier.prototype.getReleases.restore(); + }); + describe("solidity files with no imports", () => { before(() => { paths = [ @@ -80,17 +87,12 @@ describe("compileWithPragmaAnalysis", () => { path.join(sourceDirectory, "noImports", "SourceWith0.6.0.sol"), path.join(sourceDirectory, "noImports", "SourceWith0.7.0.sol") ]; - sinon.stub(CompilerSupplier.prototype, "getReleases").returns(releases); - }); - - after(() => { - CompilerSupplier.prototype.getReleases.restore(); }); // note that it will find the newest version of Solidity that satisifes // each pragma expression and then do one compilation per version it("will make one compilation per compiler version", async () => { - const { compilations } = await compileWithPragmaAnalysis({ + const {compilations} = await compileWithPragmaAnalysis({ options: config, paths }); @@ -98,7 +100,7 @@ describe("compileWithPragmaAnalysis", () => { }); it("will compile files with the same version together", async () => { - const { compilations } = await compileWithPragmaAnalysis({ + const {compilations} = await compileWithPragmaAnalysis({ options: config, paths: paths.concat( path.join(sourceDirectory, "noImports", "OtherSourceWith0.7.0.sol") @@ -110,15 +112,17 @@ describe("compileWithPragmaAnalysis", () => { describe("solidity files with imports", () => { it("compiles both files with imports and without", async () => { - const { compilations } = await compileWithPragmaAnalysis({ + const {compilations} = await compileWithPragmaAnalysis({ options: config, - paths: paths.concat([path.join(sourceDirectory, "withImports", "C.sol")]) + paths: paths.concat([ + path.join(sourceDirectory, "withImports", "C.sol") + ]) }); assert.equal(compilations.length, 3); }); it("finds a version that satisfies all pragmas if it exists", async () => { - const { compilations } = await compileWithPragmaAnalysis({ + const {compilations} = await compileWithPragmaAnalysis({ options: config, paths: [path.join(sourceDirectory, "withImports", "C.sol")] }); @@ -165,7 +169,9 @@ describe("compileWithPragmaAnalysis", () => { try { await compileWithPragmaAnalysis({ options: config, - paths: [path.join(sourceDirectory, "withImports", "ImportsBadSemver.sol")] + paths: [ + path.join(sourceDirectory, "withImports", "ImportsBadSemver.sol") + ] }); assert.fail("The function should have thrown."); } catch (error) { From cc9144b97044ecea6f7182333d1b13420c4d0953 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Tue, 12 Jan 2021 10:12:37 -0500 Subject: [PATCH 29/39] Strip off .json and .abi.json from source file extensions when creating DeployedAddresses --- packages/resolver/lib/sources/truffle/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/resolver/lib/sources/truffle/index.ts b/packages/resolver/lib/sources/truffle/index.ts index 99b4854faf4..533585ff02c 100644 --- a/packages/resolver/lib/sources/truffle/index.ts +++ b/packages/resolver/lib/sources/truffle/index.ts @@ -29,7 +29,8 @@ export class Truffle implements ResolverSource { // Ensure we have a mapping for source files and abstraction files // to prevent any compile errors in tests. sourceFiles.forEach((file: string) => { - const name = path.basename(file, ".sol"); + // we need to account for .json and .abi.json files + const name = path.basename(path.basename(path.basename(file, ".sol"), ".json"), ".abi"); if (blacklist.has(name)) return; mapping[name] = false; }); From 2f065281d1711cf0d1de58b5d827b059caec4889 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 14 Jan 2021 19:01:43 -0500 Subject: [PATCH 30/39] Add lodash.clonedeep to compile-solidity and use it to clone the compiler options --- .../compileWithPragmaAnalysis.js | 19 ++++++++++--------- packages/compile-solidity/package.json | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 029c2aa5950..94e2f9a6916 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -1,9 +1,11 @@ const CompilerSupplier = require("./compilerSupplier"); +const Config = require("@truffle/config"); const semver = require("semver"); const Profiler = require("./profiler"); const fse = require("fs-extra"); const { run } = require("./run"); const OS = require("os"); +const cloneDeep = require("lodash/clonedeep"); const getSemverExpression = source => { return source.match(/pragma solidity(.*);/)[1].trim(); @@ -55,7 +57,7 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { // collect sources by the version of the Solidity compiler that they require const versionsAndSources = {}; for (const path of paths) { - const source = await fse.readFile(path, "utf8"); + const source = (await options.resolver.resolve(path)).body; const parserVersion = findNewestSatisfyingVersion({ solcReleases: releases, @@ -114,17 +116,16 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const compilations = []; for (const compilerVersion of Object.keys(versionsAndSources)) { - const compilationOptions = options.merge({ - compilers: { - solc: { - version: compilerVersion - } - } - }); + const compilationOptions = Object.assign( + {}, + { compilers: cloneDeep(options.compilers) } + ); + compilationOptions.compilers.solc.version = compilerVersion; + const config = Config.default().with(compilationOptions); const compilation = await run( versionsAndSources[compilerVersion], - compilationOptions + config ); if (compilation.contracts.length > 0) { compilations.push(compilation); diff --git a/packages/compile-solidity/package.json b/packages/compile-solidity/package.json index 33a97d5aa84..8cc7369b8b0 100644 --- a/packages/compile-solidity/package.json +++ b/packages/compile-solidity/package.json @@ -21,6 +21,7 @@ "@truffle/expect": "^0.0.15", "debug": "^4.1.0", "fs-extra": "^8.1.0", + "lodash.clonedeep": "^4.5.0", "ora": "^3.4.0", "original-require": "^1.0.1", "request": "^2.85.0", From 7101f5d4bfb1e0f76846680f51ee8059fd42d8a0 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 14 Jan 2021 19:02:15 -0500 Subject: [PATCH 31/39] Omit rewriting the pragma expression of DeployedAddresses --- packages/resolver/lib/sources/truffle/Deployed.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/resolver/lib/sources/truffle/Deployed.ts b/packages/resolver/lib/sources/truffle/Deployed.ts index 7325a96742d..d895c48a0fa 100644 --- a/packages/resolver/lib/sources/truffle/Deployed.ts +++ b/packages/resolver/lib/sources/truffle/Deployed.ts @@ -46,14 +46,6 @@ export class Deployed { //remove "payable"s in conversions if we're before 0.6.0 source = source.replace(/payable\((.*)\)/g, "$1"); } - //regardless of version, replace all pragmas with the new version - const coercedVersion = RangeUtils.coerce(version); - - // we need to update the pragma expression differently depending on whether - // a single version or range is suppplied - source = semver.valid(coercedVersion) ? - source.replace(/0\.5\.0/g, coercedVersion) : - source.replace(/>= 0.5.0 < 0.9.0/g, coercedVersion); return source; } From fa165a2f8f49cc3cbf0f05ac99efa916dc129773 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 14 Jan 2021 20:23:19 -0500 Subject: [PATCH 32/39] Correct require statement for lodash.clonedeep --- packages/compile-solidity/compileWithPragmaAnalysis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 94e2f9a6916..703a4fc6b69 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -5,7 +5,7 @@ const Profiler = require("./profiler"); const fse = require("fs-extra"); const { run } = require("./run"); const OS = require("os"); -const cloneDeep = require("lodash/clonedeep"); +const cloneDeep = require("lodash.clonedeep"); const getSemverExpression = source => { return source.match(/pragma solidity(.*);/)[1].trim(); From 36558e50968b52fa0bc4e81f1df0abbda212af5e Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 29 Jan 2021 11:06:52 -0500 Subject: [PATCH 33/39] Upate Deployed pragma expression --- packages/resolver/lib/sources/truffle/Deployed.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/resolver/lib/sources/truffle/Deployed.ts b/packages/resolver/lib/sources/truffle/Deployed.ts index d895c48a0fa..9fb86c387cc 100644 --- a/packages/resolver/lib/sources/truffle/Deployed.ts +++ b/packages/resolver/lib/sources/truffle/Deployed.ts @@ -14,7 +14,7 @@ export class Deployed { let source = ""; source += "//SPDX-License-Identifier: MIT\n" + - "pragma solidity >= 0.5.0 < 0.9.0; \n\n library DeployedAddresses {" + + "pragma solidity >= 0.4.15 < 0.9.0; \n\n library DeployedAddresses {" + "\n"; for (let [name, address] of Object.entries(mapping)) { From 0099e47c4d8f6a7457d26cf6f102125206c28174 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Fri, 29 Jan 2021 14:10:56 -0500 Subject: [PATCH 34/39] Filter out sol and json files in compileWithPragmaAnalysis --- packages/compile-solidity/compileWithPragmaAnalysis.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 703a4fc6b69..c509ae5c063 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -47,6 +47,9 @@ const throwCompilerVersionNotFound = ({ path, semverExpressions }) => { }; const compileWithPragmaAnalysis = async ({ paths, options }) => { + const filteredPaths = paths.filter( + path => path.endsWith(".sol") || path.endsWith(".json") + ); const supplierOptions = { events: options.events, solcConfig: options.compilers.solc From 0f6cd57eb8f35feb1f7685f9f23ba0f21daee370 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 3 Feb 2021 12:03:46 -0500 Subject: [PATCH 35/39] Remove unnecessary conditional and make slight edit to loop --- .../compile-solidity/compileWithPragmaAnalysis.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index c509ae5c063..da5eb23351d 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -107,18 +107,14 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { }); } - if (versionsAndSources[newestSatisfyingVersion]) { - versionsAndSources[newestSatisfyingVersion] = { - ...versionsAndSources[newestSatisfyingVersion], - ...allSources - }; - } else { - versionsAndSources[newestSatisfyingVersion] = allSources; - } + versionsAndSources[newestSatisfyingVersion] = { + ...versionsAndSources[newestSatisfyingVersion], + ...allSources + }; } const compilations = []; - for (const compilerVersion of Object.keys(versionsAndSources)) { + for (const compilerVersion in versionsAndSources) { const compilationOptions = Object.assign( {}, { compilers: cloneDeep(options.compilers) } From 4856c59f4366afb354a2d5314d358be8d1f243ca Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 3 Feb 2021 12:27:37 -0500 Subject: [PATCH 36/39] Fix variable error and stop compilation early if there is nothing to compile --- packages/compile-solidity/compileWithPragmaAnalysis.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index da5eb23351d..46420dba23d 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -50,6 +50,9 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const filteredPaths = paths.filter( path => path.endsWith(".sol") || path.endsWith(".json") ); + if (filteredPaths.length === 0) { + return { compilations: [] }; + } const supplierOptions = { events: options.events, solcConfig: options.compilers.solc @@ -59,7 +62,7 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { // collect sources by the version of the Solidity compiler that they require const versionsAndSources = {}; - for (const path of paths) { + for (const path of filteredPaths) { const source = (await options.resolver.resolve(path)).body; const parserVersion = findNewestSatisfyingVersion({ From 1f3ec9c79e3a39c720d01d0f7a89f6bd28c5aa81 Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 3 Feb 2021 13:29:45 -0500 Subject: [PATCH 37/39] Remove unnecessary Object.assign --- packages/compile-solidity/compileWithPragmaAnalysis.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 46420dba23d..4c9c89bb632 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -118,10 +118,9 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { const compilations = []; for (const compilerVersion in versionsAndSources) { - const compilationOptions = Object.assign( - {}, - { compilers: cloneDeep(options.compilers) } - ); + const compilationOptions = { + compilers: cloneDeep(options.compilers) + }; compilationOptions.compilers.solc.version = compilerVersion; const config = Config.default().with(compilationOptions); From 96ab0fcd9713d5b88418efd38aaa6279a406a88c Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Wed, 3 Feb 2021 15:22:41 -0500 Subject: [PATCH 38/39] Allow for imports to not contain pragma expressions: throw when a users' contracts do not contain them --- .../compile-solidity/compileWithPragmaAnalysis.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/compile-solidity/compileWithPragmaAnalysis.js b/packages/compile-solidity/compileWithPragmaAnalysis.js index 4c9c89bb632..e3e5d499e86 100644 --- a/packages/compile-solidity/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/compileWithPragmaAnalysis.js @@ -8,11 +8,13 @@ const OS = require("os"); const cloneDeep = require("lodash.clonedeep"); const getSemverExpression = source => { - return source.match(/pragma solidity(.*);/)[1].trim(); + return source.match(/pragma solidity(.*);/)[1] ? + source.match(/pragma solidity(.*);/)[1].trim() : + undefined; }; const getSemverExpressions = sources => { - return sources.map(source => getSemverExpression(source)); + return sources.map(source => getSemverExpression(source)).filter(expression => expression); }; const validateSemverExpressions = semverExpressions => { @@ -70,10 +72,10 @@ const compileWithPragmaAnalysis = async ({ paths, options }) => { semverExpressions: [getSemverExpression(source)] }); if (!parserVersion) { - throwCompilerVersionNotFound({ - path, - semverExpressions: [getSemverExpression(source)] - }); + const m = `Could not find a pragma expression in ${path}. To use the ` + + `"pragma" compiler setting your contracts must contain a pragma ` + + `expression.`; + throw new Error(m); } // allSources is of the format { [filename]: string } From d4dfdff0307685e2d3aa0fbcb3f1fe2025d5452e Mon Sep 17 00:00:00 2001 From: eggplantzzz Date: Thu, 4 Feb 2021 09:29:49 -0500 Subject: [PATCH 39/39] Update expected message in test --- packages/compile-solidity/test/compileWithPragmaAnalysis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compile-solidity/test/compileWithPragmaAnalysis.js b/packages/compile-solidity/test/compileWithPragmaAnalysis.js index 2fac89fc143..9ce5fe66c23 100644 --- a/packages/compile-solidity/test/compileWithPragmaAnalysis.js +++ b/packages/compile-solidity/test/compileWithPragmaAnalysis.js @@ -157,7 +157,7 @@ describe("compileWithPragmaAnalysis", () => { }); assert.fail("The function should have thrown."); } catch (error) { - const expectedMessage = "$0.5.3"; + const expectedMessage = "Could not find a pragma expression"; if (error.message.includes(expectedMessage)) { return "all good"; }